summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux_builds.yml2
-rw-r--r--.github/workflows/windows_builds.yml4
-rw-r--r--.gitignore6
-rw-r--r--SConstruct62
-rw-r--r--core/config/engine.cpp8
-rw-r--r--core/config/engine.h6
-rw-r--r--core/config/project_settings.cpp47
-rw-r--r--core/core_bind.cpp24
-rw-r--r--core/core_bind.h14
-rw-r--r--core/doc_data.h340
-rw-r--r--core/error/error_macros.h67
-rw-r--r--core/extension/SCsub7
-rw-r--r--core/extension/extension_api_dump.cpp39
-rw-r--r--core/extension/gdnative_interface.h13
-rw-r--r--core/extension/make_interface_dumper.py47
-rw-r--r--core/extension/native_extension.cpp2
-rw-r--r--core/input/input.cpp3
-rw-r--r--core/input/input_event.cpp57
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/input/input_map.cpp36
-rw-r--r--core/io/dir_access.cpp2
-rw-r--r--core/io/file_access_encrypted.cpp8
-rw-r--r--core/io/file_access_network.cpp8
-rw-r--r--core/io/http_client_tcp.cpp20
-rw-r--r--core/io/image.cpp68
-rw-r--r--core/io/image.h18
-rw-r--r--core/io/image_loader.cpp8
-rw-r--r--core/io/logger.cpp2
-rw-r--r--core/io/marshalls.cpp6
-rw-r--r--core/io/resource_format_binary.cpp91
-rw-r--r--core/io/resource_importer.cpp4
-rw-r--r--core/io/resource_loader.cpp49
-rw-r--r--core/io/resource_loader.h1
-rw-r--r--core/io/resource_saver.cpp51
-rw-r--r--core/io/resource_saver.h2
-rw-r--r--core/io/stream_peer_tcp.cpp4
-rw-r--r--core/io/stream_peer_tcp.h2
-rw-r--r--core/io/zip_io.cpp12
-rw-r--r--core/math/aabb.cpp7
-rw-r--r--core/math/aabb.h4
-rw-r--r--core/math/basis.cpp10
-rw-r--r--core/math/basis.h1
-rw-r--r--core/math/bvh_tree.h1
-rw-r--r--core/math/color.cpp80
-rw-r--r--core/math/color.h19
-rw-r--r--core/math/convex_hull.cpp54
-rw-r--r--core/math/convex_hull.h6
-rw-r--r--core/math/delaunay_3d.h39
-rw-r--r--core/math/expression.cpp54
-rw-r--r--core/math/geometry_3d.cpp52
-rw-r--r--core/math/geometry_3d.h12
-rw-r--r--core/math/math_fieldwise.cpp32
-rw-r--r--core/math/math_funcs.h3
-rw-r--r--core/math/plane.cpp6
-rw-r--r--core/math/plane.h1
-rw-r--r--core/math/projection.cpp222
-rw-r--r--core/math/projection.h23
-rw-r--r--core/math/quaternion.cpp17
-rw-r--r--core/math/quaternion.h11
-rw-r--r--core/math/quick_hull.cpp19
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/rect2.cpp4
-rw-r--r--core/math/rect2.h13
-rw-r--r--core/math/rect2i.h2
-rw-r--r--core/math/transform_2d.cpp6
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/transform_3d.cpp6
-rw-r--r--core/math/transform_3d.h2
-rw-r--r--core/math/triangle_mesh.cpp18
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h1
-rw-r--r--core/math/vector3.cpp4
-rw-r--r--core/math/vector3.h1
-rw-r--r--core/math/vector4.cpp7
-rw-r--r--core/math/vector4.h7
-rw-r--r--core/object/class_db.cpp11
-rw-r--r--core/object/method_bind.cpp4
-rw-r--r--core/object/method_bind.h48
-rw-r--r--core/object/object.cpp44
-rw-r--r--core/object/object.h30
-rw-r--r--core/object/script_language.cpp19
-rw-r--r--core/object/script_language_extension.h7
-rw-r--r--core/os/main_loop.cpp18
-rw-r--r--core/os/midi_driver.cpp5
-rw-r--r--core/os/os.cpp9
-rw-r--r--core/os/os.h2
-rw-r--r--core/os/thread.cpp40
-rw-r--r--core/os/thread.h19
-rw-r--r--core/string/optimized_translation.cpp18
-rw-r--r--core/string/translation.cpp127
-rw-r--r--core/string/translation.h1
-rw-r--r--core/string/ustring.cpp79
-rw-r--r--core/templates/rid_owner.h11
-rw-r--r--core/variant/array.cpp8
-rw-r--r--core/variant/array.h1
-rw-r--r--core/variant/callable.cpp24
-rw-r--r--core/variant/container_type_validate.h15
-rw-r--r--core/variant/variant.cpp402
-rw-r--r--core/variant/variant_call.cpp20
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_destruct.cpp5
-rw-r--r--core/variant/variant_destruct.h5
-rw-r--r--core/variant/variant_internal.h27
-rw-r--r--core/variant/variant_op.cpp12
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_setget.cpp2
-rw-r--r--core/variant/variant_setget.h8
-rw-r--r--core/variant/variant_utility.cpp5
-rw-r--r--doc/classes/@GlobalScope.xml496
-rw-r--r--doc/classes/AABB.xml7
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AStar3D.xml2
-rw-r--r--doc/classes/Animation.xml16
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml3
-rw-r--r--doc/classes/AnimationPlayer.xml9
-rw-r--r--doc/classes/Area3D.xml6
-rw-r--r--doc/classes/Array.xml25
-rw-r--r--doc/classes/AtlasTexture.xml15
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml2
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml8
-rw-r--r--doc/classes/BaseButton.xml4
-rw-r--r--doc/classes/BaseMaterial3D.xml16
-rw-r--r--doc/classes/Basis.xml13
-rw-r--r--doc/classes/BoneMap.xml1
-rw-r--r--doc/classes/Button.xml4
-rw-r--r--doc/classes/CPUParticles2D.xml36
-rw-r--r--doc/classes/CPUParticles3D.xml8
-rw-r--r--doc/classes/Camera2D.xml21
-rw-r--r--doc/classes/CanvasItem.xml31
-rw-r--r--doc/classes/CanvasLayer.xml1
-rw-r--r--doc/classes/CanvasTexture.xml11
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml2
-rw-r--r--doc/classes/ClassDB.xml2
-rw-r--r--doc/classes/CodeEdit.xml4
-rw-r--r--doc/classes/CollisionShape2D.xml4
-rw-r--r--doc/classes/Color.xml30
-rw-r--r--doc/classes/ColorPicker.xml39
-rw-r--r--doc/classes/ConfirmationDialog.xml4
-rw-r--r--doc/classes/Container.xml4
-rw-r--r--doc/classes/Control.xml39
-rw-r--r--doc/classes/Curve2D.xml16
-rw-r--r--doc/classes/CylinderShape3D.xml1
-rw-r--r--doc/classes/Dictionary.xml3
-rw-r--r--doc/classes/DirAccess.xml4
-rw-r--r--doc/classes/DisplayServer.xml300
-rw-r--r--doc/classes/EditorFeatureProfile.xml8
-rw-r--r--doc/classes/EditorFileDialog.xml3
-rw-r--r--doc/classes/EditorInspector.xml2
-rw-r--r--doc/classes/EditorInspectorPlugin.xml2
-rw-r--r--doc/classes/EditorInterface.xml14
-rw-r--r--doc/classes/EditorNode3DGizmo.xml14
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml4
-rw-r--r--doc/classes/EditorPlugin.xml32
-rw-r--r--doc/classes/EditorProperty.xml1
-rw-r--r--doc/classes/EditorScript.xml1
-rw-r--r--doc/classes/EditorSettings.xml28
-rw-r--r--doc/classes/EditorSpinSlider.xml3
-rw-r--r--doc/classes/EditorUndoRedoManager.xml12
-rw-r--r--doc/classes/Engine.xml19
-rw-r--r--doc/classes/Environment.xml1
-rw-r--r--doc/classes/Expression.xml4
-rw-r--r--doc/classes/FileSystemDock.xml2
-rw-r--r--doc/classes/FlowContainer.xml14
-rw-r--r--doc/classes/FogMaterial.xml1
-rw-r--r--doc/classes/FontFile.xml4
-rw-r--r--doc/classes/GPUParticles2D.xml5
-rw-r--r--doc/classes/GPUParticles3D.xml2
-rw-r--r--doc/classes/HSlider.xml3
-rw-r--r--doc/classes/Image.xml28
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/InputEventMIDI.xml2
-rw-r--r--doc/classes/InputEventScreenTouch.xml3
-rw-r--r--doc/classes/Light3D.xml2
-rw-r--r--doc/classes/LineEdit.xml3
-rw-r--r--doc/classes/Marker3D.xml5
-rw-r--r--doc/classes/MenuBar.xml3
-rw-r--r--doc/classes/Mesh.xml2
-rw-r--r--doc/classes/MovieWriter.xml4
-rw-r--r--doc/classes/MultiMesh.xml2
-rw-r--r--doc/classes/MultiplayerPeer.xml36
-rw-r--r--doc/classes/MultiplayerPeerExtension.xml14
-rw-r--r--doc/classes/NavigationAgent2D.xml28
-rw-r--r--doc/classes/NavigationAgent3D.xml26
-rw-r--r--doc/classes/NavigationObstacle2D.xml2
-rw-r--r--doc/classes/NavigationObstacle3D.xml2
-rw-r--r--doc/classes/Node.xml15
-rw-r--r--doc/classes/Node2D.xml2
-rw-r--r--doc/classes/Node3D.xml1
-rw-r--r--doc/classes/NodePath.xml2
-rw-r--r--doc/classes/OS.xml20
-rw-r--r--doc/classes/Object.xml16
-rw-r--r--doc/classes/OccluderInstance3D.xml2
-rw-r--r--doc/classes/OmniLight3D.xml1
-rw-r--r--doc/classes/ParticleProcessMaterial.xml6
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml3
-rw-r--r--doc/classes/PhysicsDirectBodyState3DExtension.xml5
-rw-r--r--doc/classes/Plane.xml6
-rw-r--r--doc/classes/Polygon2D.xml1
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--doc/classes/PortableCompressedTexture2D.xml2
-rw-r--r--doc/classes/ProjectSettings.xml271
-rw-r--r--doc/classes/Projection.xml62
-rw-r--r--doc/classes/PropertyTweener.xml2
-rw-r--r--doc/classes/Quaternion.xml19
-rw-r--r--doc/classes/RDPipelineRasterizationState.xml2
-rw-r--r--doc/classes/RandomNumberGenerator.xml3
-rw-r--r--doc/classes/Rect2.xml6
-rw-r--r--doc/classes/RenderingDevice.xml4
-rw-r--r--doc/classes/RenderingServer.xml23
-rw-r--r--doc/classes/Resource.xml58
-rw-r--r--doc/classes/ResourceFormatLoader.xml9
-rw-r--r--doc/classes/ResourceFormatSaver.xml9
-rw-r--r--doc/classes/RichTextLabel.xml17
-rw-r--r--doc/classes/Script.xml2
-rw-r--r--doc/classes/Shape2D.xml6
-rw-r--r--doc/classes/SkeletonProfile.xml1
-rw-r--r--doc/classes/SkeletonProfileHumanoid.xml1
-rw-r--r--doc/classes/SpinBox.xml3
-rw-r--r--doc/classes/SpotLight3D.xml2
-rw-r--r--doc/classes/StandardMaterial3D.xml2
-rw-r--r--doc/classes/StaticBody2D.xml2
-rw-r--r--doc/classes/StaticBody3D.xml2
-rw-r--r--doc/classes/String.xml8
-rw-r--r--doc/classes/SurfaceTool.xml1
-rw-r--r--doc/classes/TextEdit.xml160
-rw-r--r--doc/classes/TextLine.xml1
-rw-r--r--doc/classes/TextServer.xml4
-rw-r--r--doc/classes/Texture2D.xml2
-rw-r--r--doc/classes/TileMap.xml3
-rw-r--r--doc/classes/Transform2D.xml6
-rw-r--r--doc/classes/Transform3D.xml6
-rw-r--r--doc/classes/TreeItem.xml9
-rw-r--r--doc/classes/VSlider.xml4
-rw-r--r--doc/classes/Vector2.xml6
-rw-r--r--doc/classes/Vector3.xml14
-rw-r--r--doc/classes/Vector4.xml6
-rw-r--r--doc/classes/Vector4i.xml8
-rw-r--r--doc/classes/Viewport.xml48
-rw-r--r--doc/classes/ViewportTexture.xml1
-rw-r--r--doc/classes/VisibleOnScreenEnabler2D.xml7
-rw-r--r--doc/classes/VisualInstance3D.xml9
-rw-r--r--doc/classes/VisualShaderNodeFloatParameter.xml2
-rw-r--r--doc/classes/VisualShaderNodeParameter.xml2
-rw-r--r--doc/classes/VoxelGIData.xml2
-rw-r--r--doc/classes/Window.xml43
-rw-r--r--doc/classes/World2D.xml2
-rw-r--r--doc/classes/World3D.xml2
-rw-r--r--doc/classes/XRInterfaceExtension.xml33
-rw-r--r--doc/classes/XROrigin3D.xml3
-rw-r--r--doc/classes/XRPose.xml4
-rw-r--r--doc/classes/XRServer.xml6
-rw-r--r--doc/classes/float.xml21
-rw-r--r--doc/classes/int.xml29
-rw-r--r--drivers/SCsub2
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp184
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h38
-rw-r--r--drivers/gles3/effects/copy_effects.cpp21
-rw-r--r--drivers/gles3/effects/copy_effects.h4
-rw-r--r--drivers/gles3/environment/fog.cpp2
-rw-r--r--drivers/gles3/environment/fog.h2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp1930
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h191
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp37
-rw-r--r--drivers/gles3/rasterizer_gles3.h7
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp202
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h90
-rw-r--r--drivers/gles3/shader_gles3.cpp33
-rw-r--r--drivers/gles3/shader_gles3.h8
-rw-r--r--drivers/gles3/shaders/SCsub2
-rw-r--r--drivers/gles3/shaders/canvas.glsl342
-rw-r--r--drivers/gles3/shaders/canvas_occlusion.glsl68
-rw-r--r--drivers/gles3/shaders/canvas_sdf.glsl205
-rw-r--r--drivers/gles3/shaders/canvas_shadow.glsl60
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl22
-rw-r--r--drivers/gles3/shaders/copy.glsl5
-rw-r--r--drivers/gles3/shaders/scene.glsl51
-rw-r--r--drivers/gles3/shaders/tonemap.glsl20
-rw-r--r--drivers/gles3/storage/config.cpp34
-rw-r--r--drivers/gles3/storage/config.h14
-rw-r--r--drivers/gles3/storage/light_storage.cpp131
-rw-r--r--drivers/gles3/storage/light_storage.h90
-rw-r--r--drivers/gles3/storage/material_storage.cpp43
-rw-r--r--drivers/gles3/storage/material_storage.h4
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp40
-rw-r--r--drivers/gles3/storage/mesh_storage.h11
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp48
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp877
-rw-r--r--drivers/gles3/storage/texture_storage.h159
-rw-r--r--drivers/gles3/storage/utilities.cpp178
-rw-r--r--drivers/gles3/storage/utilities.h87
-rw-r--r--drivers/png/png_driver_common.cpp2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h4
-rw-r--r--drivers/unix/dir_access_unix.cpp24
-rw-r--r--drivers/unix/dir_access_unix.h4
-rw-r--r--drivers/unix/file_access_unix.cpp31
-rw-r--r--drivers/unix/file_access_unix.h4
-rw-r--r--drivers/unix/net_socket_posix.cpp32
-rw-r--r--drivers/unix/os_unix.cpp17
-rw-r--r--drivers/unix/os_unix.h6
-rw-r--r--drivers/unix/thread_posix.cpp6
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp34
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h2
-rw-r--r--drivers/vulkan/vulkan_context.cpp231
-rw-r--r--drivers/vulkan/vulkan_context.h5
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp23
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h2
-rw-r--r--drivers/windows/dir_access_windows.cpp34
-rw-r--r--drivers/windows/file_access_windows.cpp6
-rw-r--r--editor/action_map_editor.cpp780
-rw-r--r--editor/action_map_editor.h114
-rw-r--r--editor/animation_bezier_editor.cpp18
-rw-r--r--editor/animation_track_editor.cpp113
-rw-r--r--editor/animation_track_editor_plugins.cpp36
-rw-r--r--editor/code_editor.cpp866
-rw-r--r--editor/code_editor.h5
-rw-r--r--editor/connections_dialog.cpp159
-rw-r--r--editor/connections_dialog.h4
-rw-r--r--editor/create_dialog.cpp45
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_protocol.cpp14
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_server.cpp12
-rw-r--r--editor/debugger/editor_debugger_inspector.cpp10
-rw-r--r--editor/debugger/editor_debugger_node.cpp38
-rw-r--r--editor/debugger/editor_debugger_node.h1
-rw-r--r--editor/debugger/editor_debugger_server.cpp4
-rw-r--r--editor/debugger/editor_debugger_tree.cpp32
-rw-r--r--editor/debugger/editor_debugger_tree.h5
-rw-r--r--editor/debugger/editor_performance_profiler.cpp8
-rw-r--r--editor/debugger/editor_profiler.cpp6
-rw-r--r--editor/debugger/editor_visual_profiler.cpp6
-rw-r--r--editor/debugger/script_editor_debugger.cpp42
-rw-r--r--editor/dependency_editor.cpp24
-rw-r--r--editor/dependency_editor.h2
-rw-r--r--editor/editor_asset_installer.cpp16
-rw-r--r--editor/editor_audio_buses.cpp16
-rw-r--r--editor/editor_autoload_settings.cpp59
-rw-r--r--editor/editor_build_profile.cpp7
-rw-r--r--editor/editor_command_palette.h6
-rw-r--r--editor/editor_data.cpp4
-rw-r--r--editor/editor_dir_dialog.cpp2
-rw-r--r--editor/editor_file_dialog.cpp32
-rw-r--r--editor/editor_file_system.cpp50
-rw-r--r--editor/editor_fonts.cpp70
-rw-r--r--editor/editor_help.cpp45
-rw-r--r--editor/editor_help_search.cpp88
-rw-r--r--editor/editor_help_search.h3
-rw-r--r--editor/editor_inspector.cpp52
-rw-r--r--editor/editor_locale_dialog.cpp26
-rw-r--r--editor/editor_log.cpp25
-rw-r--r--editor/editor_node.cpp270
-rw-r--r--editor/editor_node.h11
-rw-r--r--editor/editor_path.cpp14
-rw-r--r--editor/editor_paths.cpp2
-rw-r--r--editor/editor_plugin.cpp90
-rw-r--r--editor/editor_plugin.h13
-rw-r--r--editor/editor_plugin_settings.cpp6
-rw-r--r--editor/editor_properties.cpp219
-rw-r--r--editor/editor_properties.h33
-rw-r--r--editor/editor_properties_array_dict.cpp56
-rw-r--r--editor/editor_resource_picker.cpp28
-rw-r--r--editor/editor_resource_preview.cpp24
-rw-r--r--editor/editor_run.cpp18
-rw-r--r--editor/editor_sectioned_inspector.cpp10
-rw-r--r--editor/editor_settings.cpp25
-rw-r--r--editor/editor_settings_dialog.cpp73
-rw-r--r--editor/editor_settings_dialog.h6
-rw-r--r--editor/editor_spin_slider.cpp2
-rw-r--r--editor/editor_themes.cpp13
-rw-r--r--editor/editor_toaster.cpp24
-rw-r--r--editor/editor_undo_redo_manager.cpp62
-rw-r--r--editor/editor_undo_redo_manager.h4
-rw-r--r--editor/editor_zoom_widget.cpp10
-rw-r--r--editor/editor_zoom_widget.h2
-rw-r--r--editor/event_listener_line_edit.cpp138
-rw-r--r--editor/event_listener_line_edit.h (renamed from modules/websocket/websocket_macros.h)72
-rw-r--r--editor/export/editor_export.cpp2
-rw-r--r--editor/export/editor_export_platform.cpp24
-rw-r--r--editor/export/editor_export_platform.h1
-rw-r--r--editor/export/editor_export_platform_pc.cpp6
-rw-r--r--editor/export/editor_export_plugin.cpp12
-rw-r--r--editor/export/export_template_manager.cpp30
-rw-r--r--editor/export/project_export.cpp32
-rw-r--r--editor/filesystem_dock.cpp205
-rw-r--r--editor/filesystem_dock.h6
-rw-r--r--editor/find_in_files.cpp8
-rw-r--r--editor/find_in_files.h2
-rw-r--r--editor/groups_editor.cpp144
-rw-r--r--editor/groups_editor.h11
-rw-r--r--editor/history_dock.cpp251
-rw-r--r--editor/history_dock.h66
-rw-r--r--editor/icons/BoneMapHumanBody.svg27
-rw-r--r--editor/icons/Line.svg1
-rw-r--r--editor/icons/PickerShapeCircle.svg1
-rw-r--r--editor/icons/PickerShapeRectangle.svg1
-rw-r--r--editor/icons/PickerShapeRectangleWheel.svg58
-rw-r--r--editor/import/audio_stream_import_settings.cpp14
-rw-r--r--editor/import/collada.cpp10
-rw-r--r--editor/import/dynamic_font_import_settings.cpp12
-rw-r--r--editor/import/editor_import_collada.cpp6
-rw-r--r--editor/import/editor_import_plugin.cpp4
-rw-r--r--editor/import/resource_importer_layered_texture.cpp34
-rw-r--r--editor/import/resource_importer_scene.cpp239
-rw-r--r--editor/import/resource_importer_scene.h4
-rw-r--r--editor/import/resource_importer_texture.cpp49
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp4
-rw-r--r--editor/import_defaults_editor.cpp2
-rw-r--r--editor/import_dock.cpp2
-rw-r--r--editor/input_event_configuration_dialog.cpp704
-rw-r--r--editor/input_event_configuration_dialog.h124
-rw-r--r--editor/inspector_dock.cpp20
-rw-r--r--editor/localization_editor.cpp44
-rw-r--r--editor/plugin_config_dialog.cpp8
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp2
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp28
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp52
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h4
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp56
-rw-r--r--editor/plugins/animation_player_editor_plugin.h3
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp2
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp28
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp16
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp8
-rw-r--r--editor/plugins/bone_map_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp510
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h3
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/curve_editor_plugin.cpp8
-rw-r--r--editor/plugins/editor_preview_plugins.cpp24
-rw-r--r--editor/plugins/editor_resource_conversion_plugin.cpp23
-rw-r--r--editor/plugins/font_config_plugin.cpp10
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp22
-rw-r--r--editor/plugins/gradient_editor.cpp4
-rw-r--r--editor/plugins/input_event_editor_plugin.cpp11
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp6
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp19
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h1
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp289
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h7
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp234
-rw-r--r--editor/plugins/node_3d_editor_plugin.h10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp22
-rw-r--r--editor/plugins/path_3d_editor_plugin.h2
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.h4
-rw-r--r--editor/plugins/script_editor_plugin.cpp371
-rw-r--r--editor/plugins/script_editor_plugin.h5
-rw-r--r--editor/plugins/script_text_editor.cpp202
-rw-r--r--editor/plugins/script_text_editor.h4
-rw-r--r--editor/plugins/shader_editor_plugin.cpp6
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp46
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h2
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp119
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h10
-rw-r--r--editor/plugins/text_editor.cpp24
-rw-r--r--editor/plugins/text_editor.h3
-rw-r--r--editor/plugins/text_shader_editor.cpp113
-rw-r--r--editor/plugins/text_shader_editor.h1
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp85
-rw-r--r--editor/plugins/texture_region_editor_plugin.h2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp12
-rw-r--r--editor/plugins/theme_editor_preview.cpp2
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp4
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp6
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp67
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp91
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp37
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp90
-rw-r--r--editor/plugins/tiles/tile_set_editor.h1
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp2
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp18
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.h2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp464
-rw-r--r--editor/pot_generator.cpp6
-rw-r--r--editor/project_converter_3_to_4.cpp42
-rw-r--r--editor/project_manager.cpp46
-rw-r--r--editor/project_settings_editor.cpp22
-rw-r--r--editor/project_settings_editor.h2
-rw-r--r--editor/rename_dialog.cpp6
-rw-r--r--editor/scene_create_dialog.cpp6
-rw-r--r--editor/scene_tree_dock.cpp128
-rw-r--r--editor/scene_tree_dock.h10
-rw-r--r--editor/scene_tree_editor.cpp100
-rw-r--r--editor/scene_tree_editor.h2
-rw-r--r--editor/script_create_dialog.cpp10
-rw-r--r--editor/script_create_dialog.h4
-rw-r--r--editor/shader_create_dialog.cpp30
-rw-r--r--editor/shader_globals_editor.cpp4
-rw-r--r--gles3_builders.py10
-rw-r--r--main/main.cpp74
-rw-r--r--methods.py31
-rw-r--r--misc/dist/html/editor.html1449
-rw-r--r--misc/dist/html/full-size.html472
-rw-r--r--misc/dist/html/offline-export.html71
-rw-r--r--misc/dist/html/offline.html74
-rw-r--r--misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist1
-rw-r--r--misc/dist/linux/godot.66
-rw-r--r--misc/dist/shell/_godot.zsh-completion1
-rw-r--r--misc/dist/shell/godot.bash-completion1
-rw-r--r--misc/dist/shell/godot.fish1
-rwxr-xr-xmisc/scripts/dotnet_format.sh7
-rw-r--r--modules/basis_universal/register_types.cpp2
-rw-r--r--modules/bmp/image_loader_bmp.cpp4
-rw-r--r--modules/camera/camera_macos.mm4
-rw-r--r--modules/csg/csg_shape.cpp110
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml5
-rw-r--r--modules/csg/editor/csg_gizmos.cpp10
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp4
-rw-r--r--modules/denoise/lightmap_denoiser.cpp2
-rw-r--r--modules/enet/doc_classes/ENetMultiplayerPeer.xml14
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml26
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp466
-rw-r--r--modules/enet/enet_multiplayer_peer.h31
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml98
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp37
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h3
-rw-r--r--modules/gdscript/gdscript.cpp143
-rw-r--r--modules/gdscript/gdscript.h3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp101
-rw-r--r--modules/gdscript/gdscript_analyzer.h2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp104
-rw-r--r--modules/gdscript/gdscript_compiler.h8
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp4
-rw-r--r--modules/gdscript/gdscript_editor.cpp40
-rw-r--r--modules/gdscript/gdscript_function.cpp10
-rw-r--r--modules/gdscript/gdscript_parser.cpp38
-rw-r--r--modules/gdscript/gdscript_parser.h22
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp18
-rw-r--r--modules/gdscript/gdscript_vm.cpp2
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp50
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp12
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp38
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h1
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp36
-rw-r--r--modules/gdscript/language_server/godot_lsp.h2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp12
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_dictionary.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd11
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out7
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.gd60
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.out1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/range_returns_ints.gd77
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/range_returns_ints.out1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out2
-rw-r--r--modules/glslang/register_types.cpp4
-rw-r--r--modules/gltf/config.py1
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml19
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml30
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml3
-rw-r--r--modules/gltf/doc_classes/GLTFTextureSampler.xml25
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp23
-rw-r--r--modules/gltf/extensions/gltf_light.cpp5
-rw-r--r--modules/gltf/gltf_defines.h2
-rw-r--r--modules/gltf/gltf_document.cpp246
-rw-r--r--modules/gltf/gltf_document.h9
-rw-r--r--modules/gltf/gltf_document_extension.cpp42
-rw-r--r--modules/gltf/gltf_state.cpp21
-rw-r--r--modules/gltf/gltf_state.h10
-rw-r--r--modules/gltf/register_types.cpp2
-rw-r--r--modules/gltf/structures/gltf_node.cpp10
-rw-r--r--modules/gltf/structures/gltf_node.h4
-rw-r--r--modules/gltf/structures/gltf_texture.cpp11
-rw-r--r--modules/gltf/structures/gltf_texture.h3
-rw-r--r--modules/gltf/structures/gltf_texture_sampler.cpp47
-rw-r--r--modules/gltf/structures/gltf_texture_sampler.h163
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp6
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h2
-rw-r--r--modules/gridmap/grid_map.cpp8
-rw-r--r--modules/hdr/image_loader_hdr.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp40
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp64
-rw-r--r--modules/mono/.gitignore3
-rw-r--r--modules/mono/Directory.Build.targets6
-rw-r--r--modules/mono/SdkPackageVersions.props8
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py50
-rw-r--r--modules/mono/class_db_api_json.cpp3
-rw-r--r--modules/mono/csharp_script.cpp4
-rw-r--r--modules/mono/csharp_script.h10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs9
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs118
-rw-r--r--modules/mono/editor/bindings_generator.cpp112
-rw-r--r--modules/mono/editor/code_completion.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs32
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs74
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs480
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs67
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs45
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs84
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj3
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj2
-rw-r--r--modules/mono/glue/runtime_interop.cpp12
-rw-r--r--modules/mono/godotsharp_dirs.cpp154
-rw-r--r--modules/mono/godotsharp_dirs.h16
-rw-r--r--modules/mono/managed_callable.cpp5
-rw-r--r--modules/mono/managed_callable.h4
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h2
-rw-r--r--modules/multiplayer/doc_classes/SceneMultiplayer.xml4
-rw-r--r--modules/multiplayer/multiplayer_synchronizer.cpp4
-rw-r--r--modules/multiplayer/scene_cache_interface.cpp6
-rw-r--r--modules/multiplayer/scene_multiplayer.cpp163
-rw-r--r--modules/multiplayer/scene_multiplayer.h18
-rw-r--r--modules/multiplayer/scene_replication_config.cpp16
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp13
-rw-r--r--modules/multiplayer/scene_rpc_interface.cpp9
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp12
-rw-r--r--modules/noise/noise_texture_2d.cpp22
-rw-r--r--modules/openxr/SCsub2
-rw-r--r--modules/openxr/action_map/openxr_action.cpp6
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp20
-rw-r--r--modules/openxr/doc_classes/OpenXRInterface.xml13
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp8
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp2
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp58
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_depth_extension.h53
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_provider.h1
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h3
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp123
-rw-r--r--modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h (renamed from modules/websocket/wsl_client.h)77
-rw-r--r--modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp28
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp76
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h6
-rw-r--r--modules/openxr/openxr_api.cpp332
-rw-r--r--modules/openxr/openxr_api.h39
-rw-r--r--modules/openxr/openxr_interface.cpp122
-rw-r--r--modules/openxr/openxr_interface.h8
-rw-r--r--modules/openxr/util.h84
-rw-r--r--modules/regex/doc_classes/RegEx.xml11
-rw-r--r--modules/squish/image_decompress_squish.cpp2
-rw-r--r--modules/svg/SCsub43
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/text_server_adv/SCsub9
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct16
-rw-r--r--modules/text_server_adv/gdextension_build/text_server_adv.gdextension24
-rw-r--r--modules/text_server_adv/text_server_adv.cpp298
-rw-r--r--modules/text_server_adv/text_server_adv.h87
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct6
-rw-r--r--modules/text_server_fb/gdextension_build/text_server_fb.gdextension24
-rw-r--r--modules/text_server_fb/text_server_fb.cpp196
-rw-r--r--modules/text_server_fb/text_server_fb.h86
-rw-r--r--modules/tga/image_loader_tga.cpp10
-rw-r--r--modules/theora/video_stream_theora.cpp41
-rw-r--r--modules/theora/video_stream_theora.h2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp2
-rw-r--r--modules/upnp/doc_classes/UPNP.xml2
-rw-r--r--modules/webp/resource_saver_webp.cpp6
-rw-r--r--modules/webp/webp_common.cpp6
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml39
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp98
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h43
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml94
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml68
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml143
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml127
-rw-r--r--modules/websocket/editor/editor_debugger_server_websocket.cpp62
-rw-r--r--modules/websocket/editor/editor_debugger_server_websocket.h9
-rw-r--r--modules/websocket/emws_client.cpp159
-rw-r--r--modules/websocket/emws_peer.cpp166
-rw-r--r--modules/websocket/emws_peer.h48
-rw-r--r--modules/websocket/packet_buffer.h58
-rw-r--r--modules/websocket/register_types.cpp33
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.cpp44
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h7
-rw-r--r--modules/websocket/websocket_client.cpp141
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp522
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h86
-rw-r--r--modules/websocket/websocket_peer.cpp107
-rw-r--r--modules/websocket/websocket_peer.h67
-rw-r--r--modules/websocket/websocket_server.cpp167
-rw-r--r--modules/websocket/websocket_server.h90
-rw-r--r--modules/websocket/wsl_client.cpp407
-rw-r--r--modules/websocket/wsl_peer.cpp849
-rw-r--r--modules/websocket/wsl_peer.h130
-rw-r--r--modules/websocket/wsl_server.cpp329
-rw-r--r--modules/websocket/wsl_server.h98
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml10
-rw-r--r--modules/webxr/godot_webxr.h2
-rw-r--r--modules/webxr/native/library_godot_webxr.js41
-rw-r--r--modules/webxr/webxr_interface_js.cpp9
-rw-r--r--modules/zip/SCsub9
-rw-r--r--modules/zip/config.py17
-rw-r--r--modules/zip/doc_classes/ZIPPacker.xml72
-rw-r--r--modules/zip/doc_classes/ZIPReader.xml52
-rw-r--r--modules/zip/register_types.cpp50
-rw-r--r--modules/zip/register_types.h39
-rw-r--r--modules/zip/zip_packer.cpp107
-rw-r--r--modules/zip/zip_packer.h (renamed from modules/websocket/websocket_client.h)61
-rw-r--r--modules/zip/zip_reader.cpp123
-rw-r--r--modules/zip/zip_reader.h59
-rw-r--r--platform/android/SCsub6
-rw-r--r--platform/android/android_input_handler.cpp9
-rw-r--r--platform/android/android_input_handler.h4
-rw-r--r--platform/android/api/jni_singleton.h5
-rw-r--r--platform/android/detect.py16
-rw-r--r--platform/android/display_server_android.cpp16
-rw-r--r--platform/android/display_server_android.h4
-rw-r--r--platform/android/export/export_plugin.cpp75
-rw-r--r--platform/android/export/gradle_export_util.cpp2
-rw-r--r--platform/android/java/build.gradle51
-rw-r--r--platform/android/java/lib/build.gradle31
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java10
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt25
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java26
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java2
-rw-r--r--platform/android/java_godot_lib_jni.cpp6
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/java_godot_view_wrapper.cpp15
-rw-r--r--platform/android/java_godot_view_wrapper.h3
-rw-r--r--platform/android/java_godot_wrapper.cpp30
-rw-r--r--platform/android/java_godot_wrapper.h3
-rw-r--r--platform/android/jni_utils.cpp21
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp2
-rw-r--r--platform/android/thread_jandroid.cpp2
-rw-r--r--platform/android/vulkan/vulkan_context_android.cpp8
-rw-r--r--platform/android/vulkan/vulkan_context_android.h6
-rw-r--r--platform/ios/display_server_ios.h8
-rw-r--r--platform/ios/display_server_ios.mm8
-rw-r--r--platform/ios/export/export_plugin.cpp36
-rw-r--r--platform/ios/godot_view.mm13
-rw-r--r--platform/ios/os_ios.mm9
-rw-r--r--platform/ios/view_controller.mm12
-rw-r--r--platform/ios/vulkan_context_ios.h4
-rw-r--r--platform/ios/vulkan_context_ios.mm4
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp2
-rw-r--r--platform/linuxbsd/detect.py5
-rw-r--r--platform/linuxbsd/display_server_x11.cpp73
-rw-r--r--platform/linuxbsd/display_server_x11.h5
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp4
-rw-r--r--platform/linuxbsd/freedesktop_screensaver.cpp2
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp1
-rw-r--r--platform/linuxbsd/key_mapping_x11.cpp26
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp218
-rw-r--r--platform/linuxbsd/os_linuxbsd.h5
-rw-r--r--platform/linuxbsd/vulkan_context_x11.cpp4
-rw-r--r--platform/linuxbsd/vulkan_context_x11.h4
-rw-r--r--platform/macos/detect.py4
-rw-r--r--platform/macos/dir_access_macos.h10
-rw-r--r--platform/macos/dir_access_macos.mm4
-rw-r--r--platform/macos/display_server_macos.h6
-rw-r--r--platform/macos/display_server_macos.mm58
-rw-r--r--platform/macos/export/export_plugin.cpp153
-rw-r--r--platform/macos/export/export_plugin.h2
-rw-r--r--platform/macos/export/lipo.cpp6
-rw-r--r--platform/macos/export/lipo.h5
-rw-r--r--platform/macos/export/macho.cpp16
-rw-r--r--platform/macos/export/macho.h5
-rw-r--r--platform/macos/export/plist.cpp6
-rw-r--r--platform/macos/export/plist.h5
-rw-r--r--platform/macos/godot_button_view.h5
-rw-r--r--platform/macos/godot_button_view.mm22
-rw-r--r--platform/macos/joypad_macos.h6
-rw-r--r--platform/macos/os_macos.mm13
-rw-r--r--platform/macos/vulkan_context_macos.h4
-rw-r--r--platform/macos/vulkan_context_macos.mm3
-rw-r--r--platform/uwp/export/export_plugin.cpp8
-rw-r--r--platform/uwp/export/export_plugin.h2
-rw-r--r--platform/uwp/os_uwp.cpp9
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/web/.eslintrc.html.js19
-rw-r--r--platform/web/SCsub15
-rw-r--r--platform/web/display_server_web.cpp9
-rw-r--r--platform/web/display_server_web.h4
-rw-r--r--platform/web/export/export_plugin.cpp1
-rw-r--r--platform/web/godot_webgl2.h17
-rw-r--r--platform/web/js/libs/library_godot_display.js6
-rw-r--r--platform/web/js/libs/library_godot_javascript_singleton.js4
-rw-r--r--platform/web/js/libs/library_godot_webgl2.js52
-rw-r--r--platform/web/os_web.cpp8
-rw-r--r--platform/web/package-lock.json1560
-rw-r--r--platform/web/package.json17
-rw-r--r--platform/web/serve.json21
-rwxr-xr-xplatform/web/serve.py55
-rw-r--r--platform/web/web_main.cpp6
-rw-r--r--platform/windows/detect.py14
-rw-r--r--platform/windows/display_server_windows.cpp111
-rw-r--r--platform/windows/display_server_windows.h14
-rw-r--r--platform/windows/export/export_plugin.cpp14
-rw-r--r--platform/windows/joypad_windows.h2
-rw-r--r--platform/windows/os_windows.cpp147
-rw-r--r--platform/windows/os_windows.h17
-rw-r--r--platform/windows/vulkan_context_win.cpp4
-rw-r--r--platform/windows/vulkan_context_win.h6
-rw-r--r--scene/2d/audio_listener_2d.cpp1
-rw-r--r--scene/2d/audio_stream_player_2d.cpp2
-rw-r--r--scene/2d/camera_2d.cpp108
-rw-r--r--scene/2d/camera_2d.h25
-rw-r--r--scene/2d/collision_object_2d.cpp20
-rw-r--r--scene/2d/collision_shape_2d.cpp49
-rw-r--r--scene/2d/collision_shape_2d.h10
-rw-r--r--scene/2d/cpu_particles_2d.cpp71
-rw-r--r--scene/2d/cpu_particles_2d.h4
-rw-r--r--scene/2d/gpu_particles_2d.cpp10
-rw-r--r--scene/2d/light_2d.cpp7
-rw-r--r--scene/2d/navigation_agent_2d.cpp6
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp10
-rw-r--r--scene/2d/node_2d.cpp2
-rw-r--r--scene/2d/parallax_background.cpp28
-rw-r--r--scene/2d/parallax_layer.cpp12
-rw-r--r--scene/2d/path_2d.cpp45
-rw-r--r--scene/2d/physics_body_2d.cpp29
-rw-r--r--scene/2d/skeleton_2d.cpp26
-rw-r--r--scene/2d/sprite_2d.cpp6
-rw-r--r--scene/2d/tile_map.cpp343
-rw-r--r--scene/2d/tile_map.h8
-rw-r--r--scene/3d/area_3d.cpp12
-rw-r--r--scene/3d/area_3d.h7
-rw-r--r--scene/3d/audio_listener_3d.cpp2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp20
-rw-r--r--scene/3d/audio_stream_player_3d.h6
-rw-r--r--scene/3d/bone_attachment_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp24
-rw-r--r--scene/3d/collision_shape_3d.cpp6
-rw-r--r--scene/3d/cpu_particles_3d.cpp36
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp48
-rw-r--r--scene/3d/gpu_particles_collision_3d.h2
-rw-r--r--scene/3d/label_3d.cpp18
-rw-r--r--scene/3d/light_3d.cpp14
-rw-r--r--scene/3d/light_3d.h1
-rw-r--r--scene/3d/lightmap_gi.cpp43
-rw-r--r--scene/3d/marker_3d.cpp19
-rw-r--r--scene/3d/marker_3d.h8
-rw-r--r--scene/3d/mesh_instance_3d.cpp50
-rw-r--r--scene/3d/mesh_instance_3d.h1
-rw-r--r--scene/3d/navigation_agent_3d.cpp4
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp10
-rw-r--r--scene/3d/node_3d.cpp6
-rw-r--r--scene/3d/node_3d.h5
-rw-r--r--scene/3d/path_3d.cpp4
-rw-r--r--scene/3d/physics_body_3d.cpp29
-rw-r--r--scene/3d/ray_cast_3d.cpp2
-rw-r--r--scene/3d/shape_cast_3d.cpp2
-rw-r--r--scene/3d/skeleton_3d.cpp16
-rw-r--r--scene/3d/soft_body_3d.cpp8
-rw-r--r--scene/3d/sprite_3d.cpp61
-rw-r--r--scene/3d/visible_on_screen_notifier_3d.cpp7
-rw-r--r--scene/3d/visual_instance_3d.cpp12
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/3d/voxel_gi.cpp26
-rw-r--r--scene/3d/xr_nodes.cpp171
-rw-r--r--scene/3d/xr_nodes.h13
-rw-r--r--scene/animation/animation_blend_space_2d.cpp36
-rw-r--r--scene/animation/animation_blend_tree.cpp216
-rw-r--r--scene/animation/animation_node_state_machine.cpp77
-rw-r--r--scene/animation/animation_node_state_machine.h4
-rw-r--r--scene/animation/animation_player.cpp47
-rw-r--r--scene/animation/animation_tree.cpp53
-rw-r--r--scene/animation/tween.cpp12
-rw-r--r--scene/debugger/scene_debugger.cpp48
-rw-r--r--scene/debugger/scene_debugger.h13
-rw-r--r--scene/gui/base_button.cpp51
-rw-r--r--scene/gui/base_button.h7
-rw-r--r--scene/gui/code_edit.cpp832
-rw-r--r--scene/gui/code_edit.h5
-rw-r--r--scene/gui/color_mode.cpp127
-rw-r--r--scene/gui/color_picker.cpp694
-rw-r--r--scene/gui/color_picker.h51
-rw-r--r--scene/gui/control.cpp87
-rw-r--r--scene/gui/control.h14
-rw-r--r--scene/gui/dialogs.cpp10
-rw-r--r--scene/gui/file_dialog.cpp8
-rw-r--r--scene/gui/flow_container.cpp41
-rw-r--r--scene/gui/flow_container.h13
-rw-r--r--scene/gui/graph_edit.cpp20
-rw-r--r--scene/gui/graph_node.cpp4
-rw-r--r--scene/gui/item_list.cpp36
-rw-r--r--scene/gui/label.cpp40
-rw-r--r--scene/gui/label.h1
-rw-r--r--scene/gui/line_edit.cpp55
-rw-r--r--scene/gui/line_edit.h10
-rw-r--r--scene/gui/menu_bar.cpp60
-rw-r--r--scene/gui/menu_bar.h5
-rw-r--r--scene/gui/menu_button.cpp24
-rw-r--r--scene/gui/popup.cpp78
-rw-r--r--scene/gui/popup.h1
-rw-r--r--scene/gui/popup_menu.cpp26
-rw-r--r--scene/gui/rich_text_effect.cpp6
-rw-r--r--scene/gui/rich_text_label.cpp273
-rw-r--r--scene/gui/rich_text_label.h16
-rw-r--r--scene/gui/scroll_bar.cpp14
-rw-r--r--scene/gui/scroll_container.cpp107
-rw-r--r--scene/gui/slider.cpp8
-rw-r--r--scene/gui/spin_box.cpp17
-rw-r--r--scene/gui/spin_box.h3
-rw-r--r--scene/gui/text_edit.cpp3167
-rw-r--r--scene/gui/text_edit.h205
-rw-r--r--scene/gui/texture_progress_bar.cpp26
-rw-r--r--scene/gui/tree.cpp63
-rw-r--r--scene/gui/view_panner.cpp4
-rw-r--r--scene/main/canvas_item.cpp90
-rw-r--r--scene/main/canvas_item.h30
-rw-r--r--scene/main/canvas_layer.cpp1
-rw-r--r--scene/main/instance_placeholder.cpp2
-rw-r--r--scene/main/multiplayer_api.cpp60
-rw-r--r--scene/main/multiplayer_peer.cpp20
-rw-r--r--scene/main/multiplayer_peer.h13
-rw-r--r--scene/main/node.cpp127
-rw-r--r--scene/main/node.h13
-rw-r--r--scene/main/scene_tree.cpp124
-rw-r--r--scene/main/viewport.cpp101
-rw-r--r--scene/main/viewport.h9
-rw-r--r--scene/main/window.cpp116
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/property_utils.cpp16
-rw-r--r--scene/resources/animation.cpp38
-rw-r--r--scene/resources/audio_stream_wav.cpp4
-rw-r--r--scene/resources/bit_map.cpp4
-rw-r--r--scene/resources/capsule_shape_3d.cpp10
-rw-r--r--scene/resources/convex_polygon_shape_3d.cpp12
-rw-r--r--scene/resources/curve.cpp49
-rw-r--r--scene/resources/curve.h1
-rw-r--r--scene/resources/cylinder_shape_3d.cpp10
-rw-r--r--scene/resources/default_theme/default_theme.cpp18
-rw-r--r--scene/resources/default_theme/picker_shape_circle.svg1
-rw-r--r--scene/resources/default_theme/picker_shape_rectangle.svg1
-rw-r--r--scene/resources/default_theme/picker_shape_rectangle_wheel.svg58
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/font.cpp239
-rw-r--r--scene/resources/importer_mesh.cpp6
-rw-r--r--scene/resources/material.cpp23
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/mesh.cpp47
-rw-r--r--scene/resources/mesh_library.cpp30
-rw-r--r--scene/resources/navigation_mesh.cpp26
-rw-r--r--scene/resources/packed_scene.cpp16
-rw-r--r--scene/resources/packed_scene.h2
-rw-r--r--scene/resources/particle_process_material.cpp46
-rw-r--r--scene/resources/particle_process_material.h11
-rw-r--r--scene/resources/polygon_path_finder.cpp8
-rw-r--r--scene/resources/primitive_meshes.cpp13
-rw-r--r--scene/resources/resource_format_text.cpp35
-rw-r--r--scene/resources/shape_2d.cpp1
-rw-r--r--scene/resources/skeleton_modification_2d.cpp4
-rw-r--r--scene/resources/skeleton_modification_2d_twoboneik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp2
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp2
-rw-r--r--scene/resources/skin.cpp20
-rw-r--r--scene/resources/sprite_frames.cpp6
-rw-r--r--scene/resources/style_box.cpp16
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/text_line.cpp43
-rw-r--r--scene/resources/text_paragraph.cpp86
-rw-r--r--scene/resources/texture.cpp51
-rw-r--r--scene/resources/texture.h10
-rw-r--r--scene/resources/theme.cpp34
-rw-r--r--scene/resources/tile_set.cpp16
-rw-r--r--scene/resources/tile_set.h3
-rw-r--r--scene/resources/visual_shader.cpp403
-rw-r--r--scene/resources/visual_shader.h2
-rw-r--r--scene/resources/visual_shader_nodes.cpp59
-rw-r--r--scene/resources/visual_shader_particle_nodes.cpp32
-rw-r--r--servers/audio/audio_effect.cpp8
-rw-r--r--servers/audio/audio_stream.cpp58
-rw-r--r--servers/audio/effects/audio_effect_eq.cpp6
-rw-r--r--servers/audio_server.cpp2
-rw-r--r--servers/display_server.cpp11
-rw-r--r--servers/display_server.h6
-rw-r--r--servers/display_server_headless.h2
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp1
-rw-r--r--servers/movie_writer/movie_writer.cpp15
-rw-r--r--servers/navigation_server_3d.cpp20
-rw-r--r--servers/physics_2d/godot_area_2d.cpp6
-rw-r--r--servers/physics_2d/godot_body_2d.cpp16
-rw-r--r--servers/physics_2d/godot_body_pair_2d.cpp2
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.cpp2
-rw-r--r--servers/physics_2d/godot_collision_solver_2d_sat.cpp2
-rw-r--r--servers/physics_2d/godot_joints_2d.cpp6
-rw-r--r--servers/physics_2d/godot_shape_2d.cpp66
-rw-r--r--servers/physics_3d/godot_area_3d.cpp6
-rw-r--r--servers/physics_3d/godot_body_3d.cpp32
-rw-r--r--servers/physics_3d/godot_body_pair_3d.cpp2
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp4
-rw-r--r--servers/physics_3d/godot_collision_solver_3d_sat.cpp63
-rw-r--r--servers/physics_3d/godot_shape_3d.cpp210
-rw-r--r--servers/physics_3d/godot_shape_3d.h2
-rw-r--r--servers/physics_3d/godot_soft_body_3d.cpp9
-rw-r--r--servers/physics_server_2d.h2
-rw-r--r--servers/physics_server_3d.cpp2
-rw-r--r--servers/physics_server_3d.h2
-rw-r--r--servers/rendering/dummy/environment/fog.h2
-rw-r--r--servers/rendering/dummy/rasterizer_canvas_dummy.h1
-rw-r--r--servers/rendering/dummy/rasterizer_dummy.h3
-rw-r--r--servers/rendering/dummy/rasterizer_scene_dummy.h35
-rw-r--r--servers/rendering/dummy/storage/light_storage.h47
-rw-r--r--servers/rendering/dummy/storage/material_storage.h2
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h30
-rw-r--r--servers/rendering/dummy/storage/utilities.h2
-rw-r--r--servers/rendering/environment/renderer_fog.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp68
-rw-r--r--servers/rendering/renderer_canvas_cull.h12
-rw-r--r--servers/rendering/renderer_canvas_render.h1
-rw-r--r--servers/rendering/renderer_compositor.h1
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/fsr.cpp3
-rw-r--r--servers/rendering/renderer_rd/effects/fsr.h7
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp261
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.h54
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp11
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h39
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp156
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h12
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp21
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp862
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h93
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp6
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp484
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h115
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp6
-rw-r--r--servers/rendering/renderer_rd/pipeline_cache_rd.cpp5
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp67
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h4
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp12
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2597
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h767
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl35
-rw-r--r--servers/rendering/renderer_rd/shaders/cluster_render.glsl3
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl34
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl52
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl3
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp43
-rw-r--r--servers/rendering/renderer_rd/storage_rd/forward_id_storage.h (renamed from modules/websocket/emws_client.h)61
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp1626
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h708
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp58
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp18
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h12
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp23
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h2
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp91
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h46
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp443
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h157
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.cpp63
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.h2
-rw-r--r--servers/rendering/renderer_scene_cull.cpp122
-rw-r--r--servers/rendering/renderer_scene_cull.h7
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp2
-rw-r--r--servers/rendering/renderer_scene_render.h38
-rw-r--r--servers/rendering/renderer_viewport.cpp104
-rw-r--r--servers/rendering/renderer_viewport.h4
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h6
-rw-r--r--servers/rendering/rendering_device_binds.h8
-rw-r--r--servers/rendering/rendering_method.h6
-rw-r--r--servers/rendering/rendering_server_default.cpp8
-rw-r--r--servers/rendering/rendering_server_default.h14
-rw-r--r--servers/rendering/shader_compiler.cpp14
-rw-r--r--servers/rendering/shader_language.cpp5
-rw-r--r--servers/rendering/storage/light_storage.h51
-rw-r--r--servers/rendering/storage/material_storage.h2
-rw-r--r--servers/rendering/storage/texture_storage.h32
-rw-r--r--servers/rendering/storage/utilities.h2
-rw-r--r--servers/rendering_server.cpp19
-rw-r--r--servers/rendering_server.h13
-rw-r--r--servers/text/text_server_extension.cpp742
-rw-r--r--servers/text_server.cpp57
-rw-r--r--servers/xr/xr_interface.cpp20
-rw-r--r--servers/xr/xr_interface.h5
-rw-r--r--servers/xr/xr_interface_extension.cpp160
-rw-r--r--servers/xr/xr_interface_extension.h6
-rw-r--r--tests/core/io/test_image.h4
-rw-r--r--tests/core/math/test_aabb.h21
-rw-r--r--tests/core/math/test_basis.h166
-rw-r--r--tests/core/math/test_plane.h23
-rw-r--r--tests/core/math/test_quaternion.h95
-rw-r--r--tests/core/math/test_rect2.h21
-rw-r--r--tests/core/math/test_transform_2d.h34
-rw-r--r--tests/core/math/test_transform_3d.h23
-rw-r--r--tests/core/math/test_vector2.h26
-rw-r--r--tests/core/math/test_vector3.h45
-rw-r--r--tests/core/math/test_vector4.h78
-rw-r--r--tests/core/string/test_string.h22
-rw-r--r--tests/scene/test_animation.h8
-rw-r--r--tests/scene/test_arraymesh.h321
-rw-r--r--tests/scene/test_bit_map.h8
-rw-r--r--tests/scene/test_text_edit.h1178
-rw-r--r--tests/test_main.cpp3
-rw-r--r--tests/test_validate_testing.h2
-rw-r--r--thirdparty/README.md10
-rw-r--r--thirdparty/glad/KHR/khrplatform.h27
-rw-r--r--thirdparty/glad/glad.c20
-rw-r--r--thirdparty/glad/glad/glad.h25
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh18
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh24
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/Glyph.hh66
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh26
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh1
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/glyf.hh75
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh29
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh9
-rw-r--r--thirdparty/harfbuzz/src/graph/markbasepos-graph.hh23
-rw-r--r--thirdparty/harfbuzz/src/graph/pairpos-graph.hh71
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh20
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-aat-layout.cc1
-rw-r--r--thirdparty/harfbuzz/src/hb-config.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-cplusplus.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc76
-rw-r--r--thirdparty/harfbuzz/src/hb-face.h4
-rw-r--r--thirdparty/harfbuzz/src/hb-meta.hh12
-rw-r--r--thirdparty/harfbuzz/src/hb-open-type.hh29
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-color.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-font.cc5
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh469
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh22
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.cc73
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout.h11
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-post-table.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh120
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc34
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-stat-table.hh14
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh98
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh2
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-accelerator.hh76
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.cc55
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-input.hh1
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.cc201
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-plan.hh27
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.cc30
-rw-r--r--thirdparty/harfbuzz/src/hb-subset.h17
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h6
-rw-r--r--thirdparty/icu4c/common/appendable.cpp8
-rw-r--r--thirdparty/icu4c/common/bmpset.cpp4
-rw-r--r--thirdparty/icu4c/common/brkeng.cpp4
-rw-r--r--thirdparty/icu4c/common/brkiter.cpp6
-rw-r--r--thirdparty/icu4c/common/bytesinkutil.cpp16
-rw-r--r--thirdparty/icu4c/common/bytesinkutil.h5
-rw-r--r--thirdparty/icu4c/common/bytestream.cpp8
-rw-r--r--thirdparty/icu4c/common/bytestrie.cpp14
-rw-r--r--thirdparty/icu4c/common/bytestriebuilder.cpp10
-rw-r--r--thirdparty/icu4c/common/bytestrieiterator.cpp12
-rw-r--r--thirdparty/icu4c/common/caniter.cpp10
-rw-r--r--thirdparty/icu4c/common/characterproperties.cpp10
-rw-r--r--thirdparty/icu4c/common/charstr.cpp6
-rw-r--r--thirdparty/icu4c/common/charstr.h4
-rw-r--r--thirdparty/icu4c/common/cmemory.cpp2
-rw-r--r--thirdparty/icu4c/common/cstr.h4
-rw-r--r--thirdparty/icu4c/common/dictbe.cpp8
-rw-r--r--thirdparty/icu4c/common/edits.cpp64
-rw-r--r--thirdparty/icu4c/common/emojiprops.cpp2
-rw-r--r--thirdparty/icu4c/common/filteredbrk.cpp38
-rw-r--r--thirdparty/icu4c/common/filterednormalizer2.cpp16
-rw-r--r--thirdparty/icu4c/common/hash.h4
-rw-r--r--thirdparty/icu4c/common/icuplug.cpp28
-rw-r--r--thirdparty/icu4c/common/loadednormalizer2impl.cpp12
-rw-r--r--thirdparty/icu4c/common/localebuilder.cpp4
-rw-r--r--thirdparty/icu4c/common/localefallback_data.h632
-rw-r--r--thirdparty/icu4c/common/localematcher.cpp22
-rw-r--r--thirdparty/icu4c/common/localeprioritylist.cpp2
-rw-r--r--thirdparty/icu4c/common/locavailable.cpp8
-rw-r--r--thirdparty/icu4c/common/locdispnames.cpp16
-rw-r--r--thirdparty/icu4c/common/locdistance.cpp4
-rw-r--r--thirdparty/icu4c/common/locdspnm.cpp40
-rw-r--r--thirdparty/icu4c/common/locid.cpp53
-rw-r--r--thirdparty/icu4c/common/loclikely.cpp50
-rw-r--r--thirdparty/icu4c/common/loclikelysubtags.cpp6
-rw-r--r--thirdparty/icu4c/common/locmap.cpp8
-rw-r--r--thirdparty/icu4c/common/locutil.cpp4
-rw-r--r--thirdparty/icu4c/common/messageimpl.h2
-rw-r--r--thirdparty/icu4c/common/messagepattern.cpp74
-rw-r--r--thirdparty/icu4c/common/norm2_nfc_data.h130
-rw-r--r--thirdparty/icu4c/common/normalizer2.cpp20
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.cpp134
-rw-r--r--thirdparty/icu4c/common/normalizer2impl.h6
-rw-r--r--thirdparty/icu4c/common/normlzr.cpp6
-rw-r--r--thirdparty/icu4c/common/patternprops.cpp22
-rw-r--r--thirdparty/icu4c/common/patternprops.h2
-rw-r--r--thirdparty/icu4c/common/propname.cpp4
-rw-r--r--thirdparty/icu4c/common/propname_data.h1392
-rw-r--r--thirdparty/icu4c/common/propsvec.cpp6
-rw-r--r--thirdparty/icu4c/common/punycode.cpp2
-rw-r--r--thirdparty/icu4c/common/putil.cpp34
-rw-r--r--thirdparty/icu4c/common/rbbi.cpp32
-rw-r--r--thirdparty/icu4c/common/rbbi_cache.cpp150
-rw-r--r--thirdparty/icu4c/common/rbbidata.cpp6
-rw-r--r--thirdparty/icu4c/common/rbbinode.cpp14
-rw-r--r--thirdparty/icu4c/common/rbbirb.cpp6
-rw-r--r--thirdparty/icu4c/common/rbbirb.h8
-rw-r--r--thirdparty/icu4c/common/rbbirpt.h208
-rw-r--r--thirdparty/icu4c/common/rbbiscan.cpp78
-rw-r--r--thirdparty/icu4c/common/rbbiscan.h4
-rw-r--r--thirdparty/icu4c/common/rbbisetb.cpp4
-rw-r--r--thirdparty/icu4c/common/rbbisetb.h4
-rw-r--r--thirdparty/icu4c/common/rbbistbl.cpp4
-rw-r--r--thirdparty/icu4c/common/rbbitblb.cpp24
-rw-r--r--thirdparty/icu4c/common/rbbitblb.h4
-rw-r--r--thirdparty/icu4c/common/resbund.cpp10
-rw-r--r--thirdparty/icu4c/common/resource.h4
-rw-r--r--thirdparty/icu4c/common/ruleiter.cpp4
-rw-r--r--thirdparty/icu4c/common/ruleiter.h8
-rw-r--r--thirdparty/icu4c/common/serv.cpp18
-rw-r--r--thirdparty/icu4c/common/servlk.cpp8
-rw-r--r--thirdparty/icu4c/common/servlkf.cpp2
-rw-r--r--thirdparty/icu4c/common/servls.cpp4
-rw-r--r--thirdparty/icu4c/common/sharedobject.h4
-rw-r--r--thirdparty/icu4c/common/simpleformatter.cpp18
-rw-r--r--thirdparty/icu4c/common/static_unicode_sets.cpp12
-rw-r--r--thirdparty/icu4c/common/stringtriebuilder.cpp20
-rw-r--r--thirdparty/icu4c/common/uarrsort.cpp8
-rw-r--r--thirdparty/icu4c/common/ubidi.cpp64
-rw-r--r--thirdparty/icu4c/common/ubidi_props.cpp2
-rw-r--r--thirdparty/icu4c/common/ubidi_props_data.h253
-rw-r--r--thirdparty/icu4c/common/ubidiln.cpp16
-rw-r--r--thirdparty/icu4c/common/ubiditransform.cpp28
-rw-r--r--thirdparty/icu4c/common/ucase.cpp60
-rw-r--r--thirdparty/icu4c/common/ucase.h4
-rw-r--r--thirdparty/icu4c/common/ucase_props_data.h1373
-rw-r--r--thirdparty/icu4c/common/ucasemap.cpp18
-rw-r--r--thirdparty/icu4c/common/uchar.cpp12
-rw-r--r--thirdparty/icu4c/common/uchar_props_data.h7155
-rw-r--r--thirdparty/icu4c/common/ucharstrie.cpp14
-rw-r--r--thirdparty/icu4c/common/ucharstriebuilder.cpp10
-rw-r--r--thirdparty/icu4c/common/ucharstrieiterator.cpp20
-rw-r--r--thirdparty/icu4c/common/uchriter.cpp4
-rw-r--r--thirdparty/icu4c/common/ucln_cmn.cpp2
-rw-r--r--thirdparty/icu4c/common/ucnv.cpp110
-rw-r--r--thirdparty/icu4c/common/ucnv2022.cpp76
-rw-r--r--thirdparty/icu4c/common/ucnv_bld.cpp50
-rw-r--r--thirdparty/icu4c/common/ucnv_cb.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnv_ct.cpp14
-rw-r--r--thirdparty/icu4c/common/ucnv_ext.cpp38
-rw-r--r--thirdparty/icu4c/common/ucnv_io.cpp42
-rw-r--r--thirdparty/icu4c/common/ucnv_lmb.cpp18
-rw-r--r--thirdparty/icu4c/common/ucnv_u16.cpp8
-rw-r--r--thirdparty/icu4c/common/ucnv_u32.cpp8
-rw-r--r--thirdparty/icu4c/common/ucnv_u7.cpp42
-rw-r--r--thirdparty/icu4c/common/ucnv_u8.cpp6
-rw-r--r--thirdparty/icu4c/common/ucnvbocu.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnvhz.cpp34
-rw-r--r--thirdparty/icu4c/common/ucnvisci.cpp40
-rw-r--r--thirdparty/icu4c/common/ucnvlat1.cpp4
-rw-r--r--thirdparty/icu4c/common/ucnvmbcs.cpp48
-rw-r--r--thirdparty/icu4c/common/ucnvscsu.cpp52
-rw-r--r--thirdparty/icu4c/common/ucnvsel.cpp4
-rw-r--r--thirdparty/icu4c/common/ucol_swp.cpp12
-rw-r--r--thirdparty/icu4c/common/ucptrie_impl.h108
-rw-r--r--thirdparty/icu4c/common/ucurr.cpp91
-rw-r--r--thirdparty/icu4c/common/udata.cpp52
-rw-r--r--thirdparty/icu4c/common/udatamem.cpp2
-rw-r--r--thirdparty/icu4c/common/udatamem.h2
-rw-r--r--thirdparty/icu4c/common/uhash.cpp30
-rw-r--r--thirdparty/icu4c/common/uidna.cpp78
-rw-r--r--thirdparty/icu4c/common/uinit.cpp4
-rw-r--r--thirdparty/icu4c/common/uinvchar.cpp12
-rw-r--r--thirdparty/icu4c/common/uiter.cpp12
-rw-r--r--thirdparty/icu4c/common/ulist.cpp8
-rw-r--r--thirdparty/icu4c/common/uloc.cpp54
-rw-r--r--thirdparty/icu4c/common/uloc_keytype.cpp38
-rw-r--r--thirdparty/icu4c/common/uloc_tag.cpp234
-rw-r--r--thirdparty/icu4c/common/umapfile.cpp56
-rw-r--r--thirdparty/icu4c/common/umapfile.h2
-rw-r--r--thirdparty/icu4c/common/umutex.h10
-rw-r--r--thirdparty/icu4c/common/unames.cpp56
-rw-r--r--thirdparty/icu4c/common/unicode/bytestrie.h2
-rw-r--r--thirdparty/icu4c/common/unicode/bytestriebuilder.h4
-rw-r--r--thirdparty/icu4c/common/unicode/caniter.h6
-rw-r--r--thirdparty/icu4c/common/unicode/dtintrv.h2
-rw-r--r--thirdparty/icu4c/common/unicode/idna.h4
-rw-r--r--thirdparty/icu4c/common/unicode/normlzr.h4
-rw-r--r--thirdparty/icu4c/common/unicode/platform.h17
-rw-r--r--thirdparty/icu4c/common/unicode/rbbi.h7
-rw-r--r--thirdparty/icu4c/common/unicode/resbund.h2
-rw-r--r--thirdparty/icu4c/common/unicode/schriter.h8
-rw-r--r--thirdparty/icu4c/common/unicode/ubiditransform.h2
-rw-r--r--thirdparty/icu4c/common/unicode/uchar.h43
-rw-r--r--thirdparty/icu4c/common/unicode/ucharstrie.h2
-rw-r--r--thirdparty/icu4c/common/unicode/ucharstriebuilder.h4
-rw-r--r--thirdparty/icu4c/common/unicode/ucnv_cb.h4
-rw-r--r--thirdparty/icu4c/common/unicode/ucnv_err.h2
-rw-r--r--thirdparty/icu4c/common/unicode/ucnvsel.h1
-rw-r--r--thirdparty/icu4c/common/unicode/ucpmap.h3
-rw-r--r--thirdparty/icu4c/common/unicode/ucptrie.h3
-rw-r--r--thirdparty/icu4c/common/unicode/uloc.h4
-rw-r--r--thirdparty/icu4c/common/unicode/umachine.h8
-rw-r--r--thirdparty/icu4c/common/unicode/umisc.h4
-rw-r--r--thirdparty/icu4c/common/unicode/umutablecptrie.h3
-rw-r--r--thirdparty/icu4c/common/unicode/uniset.h11
-rw-r--r--thirdparty/icu4c/common/unicode/urename.h7
-rw-r--r--thirdparty/icu4c/common/unicode/uscript.h7
-rw-r--r--thirdparty/icu4c/common/unicode/uset.h8
-rw-r--r--thirdparty/icu4c/common/unicode/usetiter.h4
-rw-r--r--thirdparty/icu4c/common/unicode/utf_old.h6
-rw-r--r--thirdparty/icu4c/common/unicode/uvernum.h25
-rw-r--r--thirdparty/icu4c/common/unifiedcache.cpp24
-rw-r--r--thirdparty/icu4c/common/unifiedcache.h4
-rw-r--r--thirdparty/icu4c/common/uniset.cpp32
-rw-r--r--thirdparty/icu4c/common/uniset_closure.cpp4
-rw-r--r--thirdparty/icu4c/common/uniset_props.cpp70
-rw-r--r--thirdparty/icu4c/common/unisetspan.cpp28
-rw-r--r--thirdparty/icu4c/common/unistr.cpp72
-rw-r--r--thirdparty/icu4c/common/unistr_case.cpp12
-rw-r--r--thirdparty/icu4c/common/unistr_cnv.cpp16
-rw-r--r--thirdparty/icu4c/common/unorm.cpp6
-rw-r--r--thirdparty/icu4c/common/unormcmp.cpp8
-rw-r--r--thirdparty/icu4c/common/uprops.cpp34
-rw-r--r--thirdparty/icu4c/common/uresbund.cpp380
-rw-r--r--thirdparty/icu4c/common/uresdata.cpp28
-rw-r--r--thirdparty/icu4c/common/usc_impl.cpp4
-rw-r--r--thirdparty/icu4c/common/uscript.cpp4
-rw-r--r--thirdparty/icu4c/common/uscript_props.cpp2
-rw-r--r--thirdparty/icu4c/common/uset.cpp36
-rw-r--r--thirdparty/icu4c/common/usetiter.cpp16
-rw-r--r--thirdparty/icu4c/common/ushape.cpp12
-rw-r--r--thirdparty/icu4c/common/usprep.cpp50
-rw-r--r--thirdparty/icu4c/common/ustr_cnv.cpp4
-rw-r--r--thirdparty/icu4c/common/ustr_titlecase_brkiter.cpp2
-rw-r--r--thirdparty/icu4c/common/ustrcase.cpp14
-rw-r--r--thirdparty/icu4c/common/ustring.cpp44
-rw-r--r--thirdparty/icu4c/common/ustrtrns.cpp2
-rw-r--r--thirdparty/icu4c/common/utext.cpp126
-rw-r--r--thirdparty/icu4c/common/utf_impl.cpp8
-rw-r--r--thirdparty/icu4c/common/util.cpp10
-rw-r--r--thirdparty/icu4c/common/util.h2
-rw-r--r--thirdparty/icu4c/common/utrace.cpp2
-rw-r--r--thirdparty/icu4c/common/utrie.cpp48
-rw-r--r--thirdparty/icu4c/common/utrie2.cpp8
-rw-r--r--thirdparty/icu4c/common/utrie2.h2
-rw-r--r--thirdparty/icu4c/common/utrie2_builder.cpp44
-rw-r--r--thirdparty/icu4c/common/utrie_swap.cpp6
-rw-r--r--thirdparty/icu4c/common/uts46.cpp100
-rw-r--r--thirdparty/icu4c/common/uvector.cpp34
-rw-r--r--thirdparty/icu4c/common/uvectr32.cpp38
-rw-r--r--thirdparty/icu4c/common/uvectr32.h4
-rw-r--r--thirdparty/icu4c/common/uvectr64.cpp16
-rw-r--r--thirdparty/icu4c/common/uvectr64.h4
-rw-r--r--thirdparty/icu4c/common/wintz.cpp2
-rw-r--r--thirdparty/icu4c/i18n/scriptset.cpp14
-rw-r--r--thirdparty/icu4c/i18n/scriptset.h5
-rw-r--r--thirdparty/icu4c/i18n/ucln_in.cpp2
-rw-r--r--thirdparty/icu4c/i18n/unicode/uspoof.h2
-rw-r--r--thirdparty/icu4c/i18n/uspoof.cpp45
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.cpp20
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.h1
-rw-r--r--thirdparty/icu4c/icudt72l.dat (renamed from thirdparty/icu4c/icudt71l.dat)bin4271680 -> 4298880 bytes
-rw-r--r--thirdparty/misc/patches/polypartition-hole.patch15
-rw-r--r--thirdparty/misc/polypartition.h4
-rw-r--r--thirdparty/thorvg/inc/config.h2
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h2
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp2
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp2
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp6
-rw-r--r--thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp2
-rw-r--r--thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp164
-rw-r--r--thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.h52
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp2647
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgLodePng.h174
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp194
-rw-r--r--thirdparty/thorvg/src/loaders/png/tvgPngLoader.h54
-rw-r--r--thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp6
-rw-r--r--thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp4
-rw-r--r--thirdparty/thorvg/src/savers/tvg/tvgTvgSaver.cpp4
-rwxr-xr-xthirdparty/thorvg/update-thorvg.sh8
1400 files changed, 46964 insertions, 35468 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index b0ed71a7b5..3a92b8ffb4 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -215,7 +215,7 @@ jobs:
if: ${{ matrix.godot-cpp-test }}
run: |
cd godot-cpp/test
- scons target=debug
+ scons target=template_debug dev_build=yes
cd ../..
- name: Prepare artifact
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index b35c811763..31661e3f90 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -6,7 +6,7 @@ on: [push, pull_request]
env:
# Only used for the cache key. Increment version to force clean build.
GODOT_BASE_BRANCH: master
- SCONSFLAGS: verbose=yes warnings=all werror=yes module_text_server_fb_enabled=yes
+ SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
SCONS_CACHE_MSVC_CONFIG: true
concurrency:
@@ -27,7 +27,7 @@ jobs:
target: editor
tests: true
# Skip debug symbols, they're way too big with MSVC.
- sconsflags: debug_symbols=no
+ sconsflags: debug_symbols=no vsproj=yes
bin: "./bin/godot.windows.editor.x86_64.exe"
- name: Template (target=template_release, tools=no)
diff --git a/.gitignore b/.gitignore
index 539003ca6b..ca7d850f9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ platform/windows/godot_res.res
# Generated by Godot binary
.import/
+/gdnative_interface.h
extension_api.json
logs/
@@ -82,9 +83,9 @@ platform/android/java/*/libs/
# iOS
*.dSYM
-# Javascript
+# Web platform
*.bc
-platform/javascript/node_modules/
+platform/web/node_modules/
# Misc
*.debug
@@ -154,6 +155,7 @@ gmon.out
# Jetbrains IDEs
.idea/
+.fleet/
# Kate
*.kate-swp
diff --git a/SConstruct b/SConstruct
index 646f41839d..7009cb8fbe 100644
--- a/SConstruct
+++ b/SConstruct
@@ -182,8 +182,8 @@ opts.Add(BoolVariable("deprecated", "Enable compatibility code for deprecated an
opts.Add(EnumVariable("float", "Floating-point precision", "32", ("32", "64")))
opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True))
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
-opts.Add(BoolVariable("vulkan", "Enable the vulkan video driver", True))
-opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 video driver", True))
+opts.Add(BoolVariable("vulkan", "Enable the vulkan rendering driver", True))
+opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 rendering driver", True))
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
@@ -651,16 +651,32 @@ if selected_platform in platform_list:
# Configure compiler warnings
if env.msvc: # MSVC
- # Truncations, narrowing conversions, signed/unsigned comparisons...
- disable_nonessential_warnings = ["/wd4267", "/wd4244", "/wd4305", "/wd4018", "/wd4800"]
- if env["warnings"] == "extra":
- env.Append(CCFLAGS=["/Wall"]) # Implies /W4
- elif env["warnings"] == "all":
- env.Append(CCFLAGS=["/W3"] + disable_nonessential_warnings)
- elif env["warnings"] == "moderate":
- env.Append(CCFLAGS=["/W2"] + disable_nonessential_warnings)
- else: # 'no'
+ if env["warnings"] == "no":
env.Append(CCFLAGS=["/w"])
+ else:
+ if env["warnings"] == "extra":
+ env.Append(CCFLAGS=["/W4"])
+ elif env["warnings"] == "all":
+ env.Append(CCFLAGS=["/W3"])
+ elif env["warnings"] == "moderate":
+ env.Append(CCFLAGS=["/W2"])
+ # Disable warnings which we don't plan to fix.
+
+ env.Append(
+ CCFLAGS=[
+ "/wd4100", # C4100 (unreferenced formal parameter): Doesn't play nice with polymorphism.
+ "/wd4127", # C4127 (conditional expression is constant)
+ "/wd4201", # C4201 (non-standard nameless struct/union): Only relevant for C89.
+ "/wd4244", # C4244 C4245 C4267 (narrowing conversions): Unavoidable at this scale.
+ "/wd4245",
+ "/wd4267",
+ "/wd4305", # C4305 (truncation): double to float or real_t, too hard to avoid.
+ "/wd4514", # C4514 (unreferenced inline function has been removed)
+ "/wd4714", # C4714 (function marked as __forceinline not inlined)
+ "/wd4820", # C4820 (padding added after construct)
+ ]
+ )
+
# Set exception handling model to avoid warnings caused by Windows system headers.
env.Append(CCFLAGS=["/EHsc"])
@@ -671,6 +687,14 @@ if selected_platform in platform_list:
if methods.using_gcc(env):
common_warnings += ["-Wshadow-local", "-Wno-misleading-indentation"]
+ if cc_version_major == 7: # Bogus warning fixed in 8+.
+ common_warnings += ["-Wno-strict-overflow"]
+ if cc_version_major < 11:
+ # Regression in GCC 9/10, spams so much in our variadic templates
+ # that we need to outright disable it.
+ common_warnings += ["-Wno-type-limits"]
+ if cc_version_major >= 12: # False positives in our error macros, see GH-58747.
+ common_warnings += ["-Wno-return-type"]
elif methods.using_clang(env) or methods.using_emcc(env):
# We often implement `operator<` for structs of pointers as a requirement
# for putting them in `Set` or `Map`. We don't mind about unreliable ordering.
@@ -686,13 +710,16 @@ if selected_platform in platform_list:
"-Wduplicated-branches",
"-Wduplicated-cond",
"-Wstringop-overflow=4",
- "-Wlogical-op",
]
)
- # -Wnoexcept was removed temporarily due to GH-36325.
env.Append(CXXFLAGS=["-Wplacement-new=1"])
+ # Need to fix a warning with AudioServer lambdas before enabling.
+ # if cc_version_major != 9: # GCC 9 had a regression (GH-36325).
+ # env.Append(CXXFLAGS=["-Wnoexcept"])
if cc_version_major >= 9:
env.Append(CCFLAGS=["-Wattribute-alias=2"])
+ if cc_version_major >= 11: # Broke on MethodBind templates before GCC 11.
+ env.Append(CCFLAGS=["-Wlogical-op"])
elif methods.using_clang(env) or methods.using_emcc(env):
env.Append(CCFLAGS=["-Wimplicit-fallthrough"])
elif env["warnings"] == "all":
@@ -704,15 +731,6 @@ if selected_platform in platform_list:
if env["werror"]:
env.Append(CCFLAGS=["-Werror"])
- # FIXME: Temporary workaround after the Vulkan merge, remove once warnings are fixed.
- if methods.using_gcc(env):
- env.Append(CXXFLAGS=["-Wno-error=cpp"])
- if cc_version_major == 7: # Bogus warning fixed in 8+.
- env.Append(CCFLAGS=["-Wno-error=strict-overflow"])
- if cc_version_major >= 12: # False positives in our error macros, see GH-58747.
- env.Append(CCFLAGS=["-Wno-error=return-type"])
- elif methods.using_clang(env) or methods.using_emcc(env):
- env.Append(CXXFLAGS=["-Wno-error=#warnings"])
if hasattr(detect, "get_program_suffix"):
suffix = "." + detect.get_program_suffix()
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index cf9697be07..21e910be5b 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -59,12 +59,12 @@ double Engine::get_physics_jitter_fix() const {
return physics_jitter_fix;
}
-void Engine::set_target_fps(int p_fps) {
- _target_fps = p_fps > 0 ? p_fps : 0;
+void Engine::set_max_fps(int p_fps) {
+ _max_fps = p_fps > 0 ? p_fps : 0;
}
-int Engine::get_target_fps() const {
- return _target_fps;
+int Engine::get_max_fps() const {
+ return _max_fps;
}
uint64_t Engine::get_frames_drawn() {
diff --git a/core/config/engine.h b/core/config/engine.h
index 121fd4d541..21517e46b7 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -60,7 +60,7 @@ private:
int ips = 60;
double physics_jitter_fix = 0.5;
double _fps = 1;
- int _target_fps = 0;
+ int _max_fps = 0;
double _time_scale = 1.0;
uint64_t _physics_frames = 0;
double _physics_interpolation_fraction = 0.0f;
@@ -96,8 +96,8 @@ public:
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
- virtual void set_target_fps(int p_fps);
- virtual int get_target_fps() const;
+ virtual void set_max_fps(int p_fps);
+ virtual int get_max_fps() const;
virtual double get_frames_per_second() const { return _fps; }
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 4d19a93991..7a10390d72 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -153,8 +153,23 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
- if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
- (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ if (resource_path.is_empty() || (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ return p_path.simplify_path();
+ }
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = p_path.find("://");
+ bool found = false;
+ if (p > 0) {
+ found = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(p_path[i])) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
return p_path.simplify_path();
}
@@ -785,7 +800,7 @@ Error ProjectSettings::save() {
return error;
}
-Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + ".");
@@ -795,7 +810,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
int count = 0;
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
count += E.value.size();
}
@@ -821,7 +836,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
file->store_32(count); //store how many properties are saved
}
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
for (const String &key : E.value) {
String k = key;
if (!E.key.is_empty()) {
@@ -853,7 +868,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
return OK;
}
-Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
@@ -874,8 +889,8 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
}
file->store_string("\n");
- for (const KeyValue<String, List<String>> &E : props) {
- if (E.key != props.begin()->key) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
+ if (E.key != p_props.begin()->key) {
file->store_string("\n");
}
@@ -980,7 +995,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
vclist.insert(vc);
}
- RBMap<String, List<String>> props;
+ RBMap<String, List<String>> save_props;
for (const _VCSort &E : vclist) {
String category = E.name;
@@ -994,24 +1009,24 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
category = category.substr(0, div);
name = name.substr(div + 1, name.size());
}
- props[category].push_back(name);
+ save_props[category].push_back(name);
}
- String custom_features;
+ String save_features;
for (int i = 0; i < p_custom_features.size(); i++) {
if (i > 0) {
- custom_features += ",";
+ save_features += ",";
}
String f = p_custom_features[i].strip_edges().replace("\"", "");
- custom_features += f;
+ save_features += f;
}
if (p_path.ends_with(".godot") || p_path.ends_with("override.cfg")) {
- return _save_settings_text(p_path, props, p_custom, custom_features);
+ return _save_settings_text(p_path, save_props, p_custom, save_features);
} else if (p_path.ends_with(".binary")) {
- return _save_settings_binary(p_path, props, p_custom, custom_features);
+ return _save_settings_binary(p_path, save_props, p_custom, save_features);
} else {
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path + ".");
}
@@ -1022,7 +1037,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
}
- ret = ProjectSettings::get_singleton()->get(p_var);
+ ret = GLOBAL_GET(p_var);
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 723217875d..87b36f7a21 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -334,6 +334,10 @@ String OS::get_version() const {
return ::OS::get_singleton()->get_version();
}
+Vector<String> OS::get_video_adapter_driver_info() const {
+ return ::OS::get_singleton()->get_video_adapter_driver_info();
+}
+
Vector<String> OS::get_cmdline_args() {
List<String> cmdline = ::OS::get_singleton()->get_cmdline_args();
Vector<String> cmdlinev;
@@ -549,6 +553,8 @@ void OS::_bind_methods() {
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);
+ ClassDB::bind_method(D_METHOD("get_video_adapter_driver_info"), &OS::get_video_adapter_driver_info);
+
ClassDB::bind_method(D_METHOD("set_restart_on_exit", "restart", "arguments"), &OS::set_restart_on_exit, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("is_restart_on_exit_set"), &OS::is_restart_on_exit_set);
ClassDB::bind_method(D_METHOD("get_restart_on_exit_arguments"), &OS::get_restart_on_exit_arguments);
@@ -599,8 +605,8 @@ void OS::_bind_methods() {
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL_3);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
BIND_ENUM_CONSTANT(DAY_SUNDAY);
BIND_ENUM_CONSTANT(DAY_MONDAY);
@@ -1483,12 +1489,12 @@ double Engine::get_physics_interpolation_fraction() const {
return ::Engine::get_singleton()->get_physics_interpolation_fraction();
}
-void Engine::set_target_fps(int p_fps) {
- ::Engine::get_singleton()->set_target_fps(p_fps);
+void Engine::set_max_fps(int p_fps) {
+ ::Engine::get_singleton()->set_max_fps(p_fps);
}
-int Engine::get_target_fps() const {
- return ::Engine::get_singleton()->get_target_fps();
+int Engine::get_max_fps() const {
+ return ::Engine::get_singleton()->get_max_fps();
}
double Engine::get_frames_per_second() const {
@@ -1625,8 +1631,8 @@ void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &Engine::set_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &Engine::get_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_interpolation_fraction"), &Engine::get_physics_interpolation_fraction);
- ClassDB::bind_method(D_METHOD("set_target_fps", "target_fps"), &Engine::set_target_fps);
- ClassDB::bind_method(D_METHOD("get_target_fps"), &Engine::get_target_fps);
+ ClassDB::bind_method(D_METHOD("set_max_fps", "max_fps"), &Engine::set_max_fps);
+ ClassDB::bind_method(D_METHOD("get_max_fps"), &Engine::get_max_fps);
ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &Engine::set_time_scale);
ClassDB::bind_method(D_METHOD("get_time_scale"), &Engine::get_time_scale);
@@ -1669,7 +1675,7 @@ void Engine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix");
}
diff --git a/core/core_bind.h b/core/core_bind.h
index a63ed91137..784f3e63b1 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -124,9 +124,9 @@ protected:
static OS *singleton;
public:
- enum VideoDriver {
- VIDEO_DRIVER_VULKAN,
- VIDEO_DRIVER_OPENGL_3,
+ enum RenderingDriver {
+ RENDERING_DRIVER_VULKAN,
+ RENDERING_DRIVER_OPENGL3,
};
enum Weekday {
@@ -196,6 +196,8 @@ public:
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
+ Vector<String> get_video_adapter_driver_info() const;
+
String get_locale() const;
String get_locale_language() const;
@@ -488,8 +490,8 @@ public:
double get_physics_jitter_fix() const;
double get_physics_interpolation_fraction() const;
- void set_target_fps(int p_fps);
- int get_target_fps() const;
+ void set_max_fps(int p_fps);
+ int get_max_fps() const;
double get_frames_per_second() const;
uint64_t get_physics_frames() const;
@@ -576,7 +578,7 @@ VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
-VARIANT_ENUM_CAST(core_bind::OS::VideoDriver);
+VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::Weekday);
VARIANT_ENUM_CAST(core_bind::OS::Month);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
diff --git a/core/doc_data.h b/core/doc_data.h
index bb356f027e..d5fbe37c96 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -57,6 +57,27 @@ public:
}
return name < p_arg.name;
}
+ static ArgumentDoc from_dict(const Dictionary &p_dict) {
+ ArgumentDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct MethodDoc {
@@ -97,6 +118,55 @@ public:
}
return name < p_method.name;
}
+ static MethodDoc from_dict(const Dictionary &p_dict) {
+ MethodDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("return_type")) {
+ doc.return_type = p_dict["return_type"];
+ }
+
+ if (p_dict.has("return_enum")) {
+ doc.return_enum = p_dict["return_enum"];
+ }
+
+ if (p_dict.has("qualifiers")) {
+ doc.qualifiers = p_dict["qualifiers"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ Array arguments;
+ if (p_dict.has("arguments")) {
+ arguments = p_dict["arguments"];
+ }
+ for (int i = 0; i < arguments.size(); i++) {
+ doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
+ }
+
+ Array errors_returned;
+ if (p_dict.has("errors_returned")) {
+ errors_returned = p_dict["errors_returned"];
+ }
+ for (int i = 0; i < errors_returned.size(); i++) {
+ doc.errors_returned.push_back(errors_returned[i]);
+ }
+
+ return doc;
+ }
};
struct ConstantDoc {
@@ -111,6 +181,43 @@ public:
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
+ static ConstantDoc from_dict(const Dictionary &p_dict) {
+ ConstantDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("value")) {
+ doc.value = p_dict["value"];
+ }
+
+ if (p_dict.has("is_value_valid")) {
+ doc.is_value_valid = p_dict["is_value_valid"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ return doc;
+ }
};
struct EnumDoc {
@@ -118,6 +225,31 @@ public:
bool is_bitfield = false;
String description;
Vector<DocData::ConstantDoc> values;
+ static EnumDoc from_dict(const Dictionary &p_dict) {
+ EnumDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array values;
+ if (p_dict.has("values")) {
+ values = p_dict["values"];
+ }
+ for (int i = 0; i < values.size(); i++) {
+ doc.values.push_back(ConstantDoc::from_dict(values[i]));
+ }
+
+ return doc;
+ }
};
struct PropertyDoc {
@@ -134,6 +266,55 @@ public:
bool operator<(const PropertyDoc &p_prop) const {
return name < p_prop.name;
}
+ static PropertyDoc from_dict(const Dictionary &p_dict) {
+ PropertyDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("setter")) {
+ doc.setter = p_dict["setter"];
+ }
+
+ if (p_dict.has("getter")) {
+ doc.getter = p_dict["getter"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ if (p_dict.has("overridden")) {
+ doc.overridden = p_dict["overridden"];
+ }
+
+ if (p_dict.has("overrides")) {
+ doc.overrides = p_dict["overrides"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ return doc;
+ }
};
struct ThemeItemDoc {
@@ -149,11 +330,49 @@ public:
}
return data_type < p_theme_item.data_type;
}
+ static ThemeItemDoc from_dict(const Dictionary &p_dict) {
+ ThemeItemDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("data_type")) {
+ doc.data_type = p_dict["data_type"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct TutorialDoc {
String link;
String title;
+ static TutorialDoc from_dict(const Dictionary &p_dict) {
+ TutorialDoc doc;
+
+ if (p_dict.has("link")) {
+ doc.link = p_dict["link"];
+ }
+
+ if (p_dict.has("title")) {
+ doc.title = p_dict["title"];
+ }
+
+ return doc;
+ }
};
struct ClassDoc {
@@ -179,6 +398,127 @@ public:
bool operator<(const ClassDoc &p_class) const {
return name < p_class.name;
}
+ static ClassDoc from_dict(const Dictionary &p_dict) {
+ ClassDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("inherits")) {
+ doc.inherits = p_dict["inherits"];
+ }
+
+ if (p_dict.has("category")) {
+ doc.category = p_dict["category"];
+ }
+
+ if (p_dict.has("brief_description")) {
+ doc.brief_description = p_dict["brief_description"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array tutorials;
+ if (p_dict.has("tutorials")) {
+ tutorials = p_dict["tutorials"];
+ }
+ for (int i = 0; i < tutorials.size(); i++) {
+ doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
+ }
+
+ Array constructors;
+ if (p_dict.has("constructors")) {
+ constructors = p_dict["constructors"];
+ }
+ for (int i = 0; i < constructors.size(); i++) {
+ doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
+ }
+
+ Array methods;
+ if (p_dict.has("methods")) {
+ methods = p_dict["methods"];
+ }
+ for (int i = 0; i < methods.size(); i++) {
+ doc.methods.push_back(MethodDoc::from_dict(methods[i]));
+ }
+
+ Array operators;
+ if (p_dict.has("operators")) {
+ operators = p_dict["operators"];
+ }
+ for (int i = 0; i < operators.size(); i++) {
+ doc.operators.push_back(MethodDoc::from_dict(operators[i]));
+ }
+
+ Array signals;
+ if (p_dict.has("signals")) {
+ signals = p_dict["signals"];
+ }
+ for (int i = 0; i < signals.size(); i++) {
+ doc.signals.push_back(MethodDoc::from_dict(signals[i]));
+ }
+
+ Array constants;
+ if (p_dict.has("constants")) {
+ constants = p_dict["constants"];
+ }
+ for (int i = 0; i < constants.size(); i++) {
+ doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
+ }
+
+ Dictionary enums;
+ if (p_dict.has("enums")) {
+ enums = p_dict["enums"];
+ }
+ for (int i = 0; i < enums.size(); i++) {
+ doc.enums[enums.get_key_at_index(i)] = enums.get_value_at_index(i);
+ }
+
+ Array properties;
+ if (p_dict.has("properties")) {
+ properties = p_dict["properties"];
+ }
+ for (int i = 0; i < properties.size(); i++) {
+ doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
+ }
+
+ Array annotations;
+ if (p_dict.has("annotations")) {
+ annotations = p_dict["annotations"];
+ }
+ for (int i = 0; i < annotations.size(); i++) {
+ doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
+ }
+
+ Array theme_properties;
+ if (p_dict.has("theme_properties")) {
+ theme_properties = p_dict["theme_properties"];
+ }
+ for (int i = 0; i < theme_properties.size(); i++) {
+ doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ if (p_dict.has("is_script_doc")) {
+ doc.is_script_doc = p_dict["is_script_doc"];
+ }
+
+ if (p_dict.has("script_path")) {
+ doc.script_path = p_dict["script_path"];
+ }
+
+ return doc;
+ }
};
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 2cfb5421c6..6901548cca 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -137,8 +137,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
@@ -173,8 +172,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
@@ -240,9 +238,9 @@ void _err_flush_stdout();
return; \
} else \
((void)0)
+
/**
- * Ensures an unsigned integer index `m_index` is less than `m_size`.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
@@ -277,8 +275,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an unsigned integer index `m_index` is less than `m_size`.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
@@ -346,8 +343,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures a pointer `m_param` is not null.
- * If it is null, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
@@ -382,8 +378,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures a pointer `m_param` is not null.
- * If it is null, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
@@ -423,11 +418,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns.
- *
- * If checking for null use ERR_FAIL_NULL_MSG instead.
- * If checking index bounds use ERR_FAIL_INDEX_MSG instead.
+ * Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -467,11 +458,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
- *
- * If checking for null use ERR_FAIL_NULL_V_MSG instead.
- * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
+ * Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
@@ -506,8 +493,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop continues.
+ * Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -542,8 +528,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop breaks.
+ * Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -613,10 +598,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_MSG`.
- * Only use this macro if more complex error detection or recovery is required.
- *
- * Prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
@@ -653,10 +635,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_V_MSG`.
- * Only use this macro if more complex error detection or recovery is required.
- *
- * Prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
@@ -666,7 +645,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG.
+ * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
* Only use this macro at the start of a function that has not been implemented yet, or
* if more complex error detection or recovery is required.
*
@@ -676,14 +655,10 @@ void _err_flush_stdout();
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
- * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG.
- * Only use this macro at the start of a function that has not been implemented yet, or
- * if more complex error detection or recovery is required.
- *
- * Prints `m_msg` and notifies the editor.
+ * Same as `ERR_PRINT` but also notifies the editor.
*/
#define ERR_PRINT_ED(m_msg) \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, )
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/**
* Prints `m_msg` once during the application lifetime.
@@ -699,7 +674,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Prints `m_msg` and notifies the editor once during the application lifetime.
+ * Same as `ERR_PRINT_ONCE` but also notifies the editor.
*/
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
@@ -722,9 +697,7 @@ void _err_flush_stdout();
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING)
/**
- * Prints `m_msg` and notifies the editor.
- *
- * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
+ * Same as `WARN_PRINT` but also notifies the editor.
*/
#define WARN_PRINT_ED(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING)
@@ -745,9 +718,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Prints `m_msg` and notifies the editor once during the application lifetime.
- *
- * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
+ * Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
diff --git a/core/extension/SCsub b/core/extension/SCsub
index 23727c1b76..a8f68a1533 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -3,10 +3,15 @@
Import("env")
import make_wrappers
+import make_interface_dumper
from platform_methods import run_in_subprocess
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", run_in_subprocess(make_wrappers.run))
-
+env.CommandNoCache(
+ "gdnative_interface_dump.gen.h",
+ ["gdnative_interface.h", "make_interface_dumper.py"],
+ run_in_subprocess(make_interface_dumper.run),
+)
env_extension = env.Clone()
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index e6e0fff266..96b396caa9 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -38,7 +38,15 @@
#ifdef TOOLS_ENABLED
-static String get_type_name(const PropertyInfo &p_info) {
+static String get_builtin_or_variant_type_name(const Variant::Type p_type) {
+ if (p_type == Variant::NIL) {
+ return "Variant";
+ } else {
+ return Variant::get_type_name(p_type);
+ }
+}
+
+static String get_property_info_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::INT && (p_info.hint == PROPERTY_HINT_INT_IS_POINTER)) {
if (p_info.hint_string.is_empty()) {
return "void*";
@@ -70,7 +78,7 @@ static String get_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::NIL) {
return "void";
}
- return Variant::get_type_name(p_info.type);
+ return get_builtin_or_variant_type_name(p_info.type);
}
Dictionary NativeExtensionAPIDump::generate_extension_api() {
@@ -430,8 +438,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary arg;
String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i);
arg["name"] = argname;
- Variant::Type argtype = Variant::get_utility_function_argument_type(name, i);
- arg["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ arg["type"] = get_builtin_or_variant_type_name(Variant::get_utility_function_argument_type(name, i));
//no default value support in utility functions
arguments.push_back(arg);
}
@@ -461,8 +468,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d;
d["name"] = Variant::get_type_name(type);
if (Variant::has_indexing(type)) {
- Variant::Type index_type = Variant::get_indexed_element_type(type);
- d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
+ d["indexing_return_type"] = get_builtin_or_variant_type_name(Variant::get_indexed_element_type(type));
}
d["is_keyed"] = Variant::is_keyed(type);
@@ -476,7 +482,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (const StringName &member_name : member_names) {
Dictionary d2;
d2["name"] = String(member_name);
- d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name));
+ d2["type"] = get_builtin_or_variant_type_name(Variant::get_member_type(type, member_name));
members.push_back(d2);
}
if (members.size()) {
@@ -493,7 +499,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = String(constant_name);
Variant constant = Variant::get_constant_value(type, constant_name);
- d2["type"] = Variant::get_type_name(constant.get_type());
+ d2["type"] = get_builtin_or_variant_type_name(constant.get_type());
d2["value"] = constant.get_construct_string();
constants.push_back(d2);
}
@@ -544,9 +550,9 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = Variant::get_operator_name(Variant::Operator(k));
if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) {
- d2["right_type"] = Variant::get_type_name(Variant::Type(j));
+ d2["right_type"] = get_builtin_or_variant_type_name(Variant::Type(j));
}
- d2["return_type"] = Variant::get_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
+ d2["return_type"] = get_builtin_or_variant_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
operators.push_back(d2);
}
}
@@ -580,8 +586,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int j = 0; j < argcount; j++) {
Dictionary d3;
d3["name"] = Variant::get_builtin_method_argument_name(type, method_name, j);
- Variant::Type argtype = Variant::get_builtin_method_argument_type(type, method_name, j);
- d3["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_builtin_method_argument_type(type, method_name, j));
if (j >= (argcount - default_args.size())) {
int dargidx = j - (argcount - default_args.size());
@@ -613,7 +618,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int k = 0; k < argcount; k++) {
Dictionary d3;
d3["name"] = Variant::get_constructor_argument_name(type, j, k);
- d3["type"] = Variant::get_type_name(Variant::get_constructor_argument_type(type, j, k));
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_constructor_argument_type(type, j, k));
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -741,7 +746,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (i == -1) {
d2["return_value"] = d3;
@@ -784,7 +789,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (i >= 0) {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (method->get_argument_meta(i) > 0) {
static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
@@ -831,7 +836,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int i = 0; i < F.arguments.size(); i++) {
Dictionary d3;
d3["name"] = F.arguments[i].name;
- d3["type"] = get_type_name(F.arguments[i]);
+ d3["type"] = get_property_info_type_name(F.arguments[i]);
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -863,7 +868,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
StringName property_name = F.name;
Dictionary d2;
- d2["type"] = get_type_name(F);
+ d2["type"] = get_property_info_type_name(F);
d2["name"] = String(property_name);
d2["setter"] = ClassDB::get_property_setter(class_name, F.name);
d2["getter"] = ClassDB::get_property_getter(class_name, F.name);
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 39378d8261..1ce50bc186 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -201,18 +201,18 @@ typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_
typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
typedef struct {
- uint32_t type;
+ GDNativeVariantType type;
const char *name;
const char *class_name;
- uint32_t hint;
+ uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`)
const char *hint_string;
- uint32_t usage;
+ uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`)
} GDNativePropertyInfo;
typedef struct {
const char *name;
GDNativePropertyInfo return_value;
- uint32_t flags; // From GDNativeExtensionClassMethodFlags
+ uint32_t flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
int32_t id;
GDNativePropertyInfo *arguments;
uint32_t argument_count;
@@ -231,10 +231,11 @@ typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
typedef GDNativeObjectPtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
-typedef void (*GDNativeExtensionClassObjectInstance)(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance);
typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
typedef struct {
+ GDNativeBool is_virtual;
+ GDNativeBool is_abstract;
GDNativeExtensionClassSet set_func;
GDNativeExtensionClassGet get_func;
GDNativeExtensionClassGetPropertyList get_property_list_func;
@@ -293,7 +294,7 @@ typedef struct {
void *method_userdata;
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
- uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
+ uint32_t method_flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
uint32_t argument_count;
GDNativeBool has_return_value;
GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
diff --git a/core/extension/make_interface_dumper.py b/core/extension/make_interface_dumper.py
new file mode 100644
index 0000000000..cc85c728d5
--- /dev/null
+++ b/core/extension/make_interface_dumper.py
@@ -0,0 +1,47 @@
+def run(target, source, env):
+ src = source[0]
+ dst = target[0]
+ f = open(src, "r", encoding="utf-8")
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
+#ifndef GDNATIVE_INTERFACE_DUMP_H
+#define GDNATIVE_INTERFACE_DUMP_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/file_access.h"
+#include "core/string/ustring.h"
+
+class GDNativeInterfaceDump {
+ private:
+ static constexpr char const *gdnative_interface_dump ="""
+ )
+ for line in f:
+ g.write('"' + line.rstrip().replace('"', '\\"') + '\\n"\n')
+ g.write(";\n")
+
+ g.write(
+ """
+ public:
+ static void generate_gdnative_interface_file(const String &p_path) {
+ Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
+ CharString cs(gdnative_interface_dump);
+ fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ };
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // GDNATIVE_INTERFACE_DUMP_H
+"""
+ )
+ g.close()
+ f.close()
+
+
+if __name__ == "__main__":
+ from platform_methods import subprocess_main
+
+ subprocess_main(globals())
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index 6418da2235..cc019584a5 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -152,6 +152,8 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.parent_class_name = parent_class_name;
extension->native_extension.class_name = class_name;
extension->native_extension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
+ extension->native_extension.is_virtual = p_extension_funcs->is_virtual;
+ extension->native_extension.is_abstract = p_extension_funcs->is_abstract;
extension->native_extension.set = p_extension_funcs->set_func;
extension->native_extension.get = p_extension_funcs->get_func;
extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 1390a0a7fa..1321e40795 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -365,7 +365,6 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po
// Inverse lerp length to map (p_deadzone, 1) to (0, 1).
return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
}
- return vector;
}
float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
@@ -520,6 +519,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
touch_event.instantiate();
touch_event->set_pressed(mb->is_pressed());
touch_event->set_position(mb->get_position());
+ touch_event->set_double_tap(mb->is_double_click());
event_dispatch_function(touch_event);
}
}
@@ -581,6 +581,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
button_event->set_button_index(MouseButton::LEFT);
+ button_event->set_double_click(st->is_double_tap());
if (st->is_pressed()) {
button_event->set_button_mask(MouseButton(mouse_button_mask | MouseButton::MASK_LEFT));
} else {
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 712fc68c93..9dc071de9c 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -449,11 +449,11 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool p_exact_ma
match &= action_mask == key_mask;
}
if (match) {
- bool pressed = key->is_pressed();
+ bool key_pressed = key->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = key_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = key_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -610,20 +610,20 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool p_
}
bool match = button_index == mb->button_index;
- Key action_mask = get_modifiers_mask();
- Key button_mask = mb->get_modifiers_mask();
+ Key action_modifiers_mask = get_modifiers_mask();
+ Key button_modifiers_mask = mb->get_modifiers_mask();
if (mb->is_pressed()) {
- match &= (action_mask & button_mask) == action_mask;
+ match &= (action_modifiers_mask & button_modifiers_mask) == action_modifiers_mask;
}
if (p_exact_match) {
- match &= action_mask == button_mask;
+ match &= action_modifiers_mask == button_modifiers_mask;
}
if (match) {
- bool pressed = mb->is_pressed();
+ bool mb_pressed = mb->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = mb_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = mb_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -808,9 +808,9 @@ String InputEventMouseMotion::as_text() const {
}
String InputEventMouseMotion::to_string() {
- MouseButton button_mask = get_button_mask();
- String button_mask_string = itos((int64_t)button_mask);
- switch (button_mask) {
+ MouseButton mouse_button_mask = get_button_mask();
+ String button_mask_string = itos((int64_t)mouse_button_mask);
+ switch (mouse_button_mask) {
case MouseButton::MASK_LEFT:
button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::LEFT - 1]));
break;
@@ -1045,11 +1045,11 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool p
bool match = button_index == jb->button_index;
if (match) {
- bool pressed = jb->is_pressed();
+ bool jb_pressed = jb->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = jb_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = jb_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -1162,6 +1162,13 @@ bool InputEventScreenTouch::is_pressed() const {
return pressed;
}
+void InputEventScreenTouch::set_double_tap(bool p_double_tap) {
+ double_tap = p_double_tap;
+}
+bool InputEventScreenTouch::is_double_tap() const {
+ return double_tap;
+}
+
Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Ref<InputEventScreenTouch> st;
st.instantiate();
@@ -1170,6 +1177,7 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
st->set_index(index);
st->set_position(p_xform.xform(pos + p_local_ofs));
st->set_pressed(pressed);
+ st->set_double_tap(double_tap);
return st;
}
@@ -1182,7 +1190,8 @@ String InputEventScreenTouch::as_text() const {
String InputEventScreenTouch::to_string() {
String p = pressed ? "true" : "false";
- return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position()));
+ String double_tap_string = double_tap ? "true" : "false";
+ return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s), double_tap=%s", index, p, String(get_position()), double_tap_string);
}
void InputEventScreenTouch::_bind_methods() {
@@ -1195,9 +1204,13 @@ void InputEventScreenTouch::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
//ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
+ ClassDB::bind_method(D_METHOD("set_double_tap", "double_tap"), &InputEventScreenTouch::set_double_tap);
+ ClassDB::bind_method(D_METHOD("is_double_tap"), &InputEventScreenTouch::is_double_tap);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_tap"), "set_double_tap", "is_double_tap");
}
///////////////////////////////////
@@ -1340,16 +1353,16 @@ bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool p_exact
bool match = action == act->action;
if (match) {
- bool pressed = act->pressed;
+ bool act_pressed = act->pressed;
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = act_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float act_strength = act_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
- *r_strength = strength;
+ *r_strength = act_strength;
}
if (r_raw_strength != nullptr) {
- *r_raw_strength = strength;
+ *r_raw_strength = act_strength;
}
}
return match;
diff --git a/core/input/input_event.h b/core/input/input_event.h
index bc3ec3e7ac..adbcb7cf68 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -353,6 +353,7 @@ class InputEventScreenTouch : public InputEventFromWindow {
int index = 0;
Vector2 pos;
bool pressed = false;
+ bool double_tap = false;
protected:
static void _bind_methods();
@@ -367,6 +368,9 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
+ void set_double_tap(bool p_double_tap);
+ bool is_double_tap() const;
+
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ce76d11b6e..aebb9caa2f 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -257,7 +257,7 @@ void InputMap::load_from_project_settings() {
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
+ Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
Array events = action["events"];
@@ -331,12 +331,18 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
+ { "ui_text_caret_add_below", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_above", TTRC("Caret Add Above") },
+ { "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
{ "ui_text_scroll_up", TTRC("Scroll Up") },
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
{ "ui_text_scroll_down", TTRC("Scroll Down") },
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
{ "ui_text_select_all", TTRC("Select All") },
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
+ { "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
+ { "ui_text_remove_secondary_carets", TTRC("Remove Secondary Carets") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
{ "ui_text_submit", TTRC("Text Submitted") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
@@ -616,6 +622,24 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
+ // Text Caret Addition Below/Above
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
+
// Text Scrolling
inputs = List<Ref<InputEvent>>();
@@ -641,10 +665,18 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
+ default_builtin_cache.insert("ui_text_remove_secondary_carets", inputs);
+
+ inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::INSERT));
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 79e7fa16e3..7eb50d2261 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -351,7 +351,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
const size_t copy_buffer_limit = 65536; // 64 KB
fsrc->seek_end(0);
- int size = fsrc->get_position();
+ uint64_t size = fsrc->get_position();
fsrc->seek(0);
err = OK;
size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit);
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index be502dacd9..e7b2a2dfee 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -102,13 +102,13 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode) {
String cs = p_key.md5_text();
ERR_FAIL_COND_V(cs.length() != 32, ERR_INVALID_PARAMETER);
- Vector<uint8_t> key;
- key.resize(32);
+ Vector<uint8_t> key_md5;
+ key_md5.resize(32);
for (int i = 0; i < 32; i++) {
- key.write[i] = cs[i];
+ key_md5.write[i] = cs[i];
}
- return open_and_parse(p_base, key, p_mode);
+ return open_and_parse(p_base, key_md5, p_mode);
}
Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) {
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 13730518bf..87f3f66597 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -137,12 +137,12 @@ void FileAccessNetworkClient::_thread_func() {
int64_t offset = get_64();
int32_t len = get_32();
- Vector<uint8_t> block;
- block.resize(len);
- client->get_data(block.ptrw(), len);
+ Vector<uint8_t> resp_block;
+ resp_block.resize(len);
+ client->get_data(resp_block.ptrw(), len);
if (fa) { //may have been queued
- fa->_set_block(offset, block);
+ fa->_set_block(offset, resp_block);
}
} break;
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index 5c1d00a330..aff79320ca 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -358,38 +358,38 @@ Error HTTPClientTCP::poll() {
} break;
}
} else if (tls) {
- Ref<StreamPeerTLS> tls;
+ Ref<StreamPeerTLS> tls_conn;
if (!handshaking) {
// Connect the StreamPeerTLS and start handshaking.
- tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
- tls->set_blocking_handshake_enabled(false);
- Error err = tls->connect_to_stream(tcp_connection, tls_verify_host, conn_host);
+ tls_conn = Ref<StreamPeerTLS>(StreamPeerTLS::create());
+ tls_conn->set_blocking_handshake_enabled(false);
+ Error err = tls_conn->connect_to_stream(tcp_connection, tls_verify_host, conn_host);
if (err != OK) {
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- connection = tls;
+ connection = tls_conn;
handshaking = true;
} else {
// We are already handshaking, which means we can use your already active TLS connection.
- tls = static_cast<Ref<StreamPeerTLS>>(connection);
- if (tls.is_null()) {
+ tls_conn = static_cast<Ref<StreamPeerTLS>>(connection);
+ if (tls_conn.is_null()) {
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- tls->poll(); // Try to finish the handshake.
+ tls_conn->poll(); // Try to finish the handshake.
}
- if (tls->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
+ if (tls_conn->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
// Handshake has been successful.
handshaking = false;
ip_candidates.clear();
status = STATUS_CONNECTED;
return OK;
- } else if (tls->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
+ } else if (tls_conn->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
// Handshake has failed.
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 56c05bf042..6a049014bc 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -982,7 +982,7 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
}
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
- ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first.");
+ ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use set_data() first.");
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
@@ -1017,7 +1017,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
if (interpolate_mipmaps) {
- dst2.create(p_width, p_height, false, format);
+ dst2.initialize_data(p_width, p_height, false, format);
}
bool had_mipmaps = mipmaps;
@@ -2016,9 +2016,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
uint8_t* wr = imgdata.ptrw();
memcpy(wr.ptr(), ptr, size);
wr = uint8_t*();
- Ref<Image> im;
- im.instantiate();
- im->create(w, h, false, format, imgdata);
+ Ref<Image> im = Image::create_from_data(w, h, false, format, imgdata);
im->save_png("res://mipmap_" + itos(i) + ".png");
}
#endif
@@ -2051,7 +2049,25 @@ Vector<uint8_t> Image::get_data() const {
return data;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+Ref<Image> Image::create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format);
+ return image;
+}
+
+Ref<Image> Image::create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+ return image;
+}
+
+void Image::set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+}
+
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2077,7 +2093,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
format = p_format;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2115,7 +2131,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
mipmaps = p_use_mipmaps;
}
-void Image::create(const char **p_xpm) {
+void Image::initialize_data(const char **p_xpm) {
int size_width = 0;
int size_height = 0;
int pixelchars = 0;
@@ -2230,7 +2246,7 @@ void Image::create(const char **p_xpm) {
}
if (line == colormap_size) {
status = READING_PIXELS;
- create(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
+ initialize_data(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
data_write = data.ptrw();
pixel_size = has_alpha ? 4 : 3;
}
@@ -2559,7 +2575,7 @@ Image::Image(const char **p_xpm) {
mipmaps = false;
format = FORMAT_L8;
- create(p_xpm);
+ initialize_data(p_xpm);
}
Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
@@ -2568,7 +2584,7 @@ Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
mipmaps = p_use_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_use_mipmaps, p_format);
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format);
}
Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
@@ -2577,7 +2593,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const V
mipmaps = p_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_mipmaps, p_format, p_data);
+ initialize_data(p_width, p_height, p_mipmaps, p_format, p_data);
}
Rect2i Image::get_used_rect() const {
@@ -2846,6 +2862,9 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s
}
void Image::fill(const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
uint8_t *dst_data_ptr = data.ptrw();
@@ -2859,6 +2878,9 @@ void Image::fill(const Color &p_color) {
}
void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
@@ -2931,7 +2953,7 @@ void Image::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(ddformat == FORMAT_MAX);
- create(dwidth, dheight, dmipmaps, ddformat, ddata);
+ initialize_data(dwidth, dheight, dmipmaps, ddformat, ddata);
}
Dictionary Image::_get_data() const {
@@ -3294,8 +3316,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
- ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
- ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
+ ClassDB::bind_static_method("Image", D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+ ClassDB::bind_static_method("Image", D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
+ ClassDB::bind_method(D_METHOD("set_data", "width", "height", "use_mipmaps", "format", "data"), &Image::set_data);
ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
@@ -3460,9 +3483,7 @@ Ref<Image> Image::rgbe_to_srgb() {
ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>());
- Ref<Image> new_image;
- new_image.instantiate();
- new_image->create(width, height, false, Image::FORMAT_RGB8);
+ Ref<Image> new_image = create_empty(width, height, false, Image::FORMAT_RGB8);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
@@ -3503,6 +3524,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
void Image::bump_map_to_normal_map(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format));
+ clear_mipmaps();
convert(Image::FORMAT_RF);
Vector<uint8_t> result_image; //rgba output
@@ -3869,15 +3891,15 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
double image_metric_max, image_metric_mean, image_metric_mean_squared, image_metric_root_mean_squared, image_metric_peak_snr = 0.0;
const bool average_component_error = true;
- const uint32_t width = MIN(compared_image->get_width(), source_image->get_width());
- const uint32_t height = MIN(compared_image->get_height(), source_image->get_height());
+ const uint32_t w = MIN(compared_image->get_width(), source_image->get_width());
+ const uint32_t h = MIN(compared_image->get_height(), source_image->get_height());
// Histogram approach originally due to Charles Bloom.
double hist[256];
memset(hist, 0, sizeof(hist));
- for (uint32_t y = 0; y < height; y++) {
- for (uint32_t x = 0; x < width; x++) {
+ for (uint32_t y = 0; y < h; y++) {
+ for (uint32_t x = 0; x < w; x++) {
const Color color_a = compared_image->get_pixel(x, y);
const Color color_b = source_image->get_pixel(x, y);
@@ -3922,7 +3944,7 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
}
// See http://richg42.blogspot.com/2016/09/how-to-compute-psnr-from-old-berkeley.html
- double total_values = width * height;
+ double total_values = w * h;
if (average_component_error) {
total_values *= 4;
diff --git a/core/io/image.h b/core/io/image.h
index fd264a7a38..194ee05bc7 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -279,12 +279,12 @@ public:
void normalize(); //for normal maps
/**
- * Create a new image of a given size and format. Current image will be lost
+ * Creates new internal image data of a given size and format. Current image will be lost.
*/
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(const char **p_xpm);
- void create(const char **p_xpm);
/**
* returns true when the image is empty (0,0) in size
*/
@@ -303,13 +303,9 @@ public:
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
- void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
- create(p_width, p_height, p_use_mipmaps, p_format);
- }
-
- void create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
- create(p_width, p_height, p_use_mipmaps, p_format, p_data);
- }
+ static Ref<Image> create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
/**
* create an empty image
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index d6854666c0..6c00ca4b67 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -51,11 +51,9 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
}
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;
+ Error err = ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err);
+ return err;
}
void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const {
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index b0f74f8db5..288e53d075 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -87,7 +87,7 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c
} else {
logf_error("USER %s: %s\n", err_type, err_details);
}
- logf_error(" at: %s (%s:%i) - %s\n", p_function, p_file, p_line, p_code);
+ logf_error(" at: %s (%s:%i)\n", p_function, p_file, p_line);
}
void Logger::logf(const char *p_format, ...) {
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index b24c49f58d..9ba653e1a9 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -503,7 +503,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- val.matrix[i][j] = decode_double(&buf[(i * 4 + j) * sizeof(double)]);
+ val.columns[i][j] = decode_double(&buf[(i * 4 + j) * sizeof(double)]);
}
}
if (r_len) {
@@ -513,7 +513,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(float) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- val.matrix[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
+ val.columns[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
}
}
@@ -1450,7 +1450,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Projection val = p_variant;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- memcpy(&buf[(i * 4 + j) * sizeof(real_t)], &val.matrix[i][j], sizeof(real_t));
+ memcpy(&buf[(i * 4 + j) * sizeof(real_t)], &val.columns[i][j], sizeof(real_t));
}
}
}
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 36fa77626e..4611528db7 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -169,10 +169,10 @@ StringName ResourceLoaderBinary::_get_string() {
}
Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
- uint32_t type = f->get_32();
- print_bl("find property of type: " + itos(type));
+ uint32_t prop_type = f->get_32();
+ print_bl("find property of type: " + itos(prop_type));
- switch (type) {
+ switch (prop_type) {
case VARIANT_NIL: {
r_v = Variant();
} break;
@@ -327,22 +327,22 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
} break;
case VARIANT_PROJECTION: {
Projection v;
- v.matrix[0].x = f->get_real();
- v.matrix[0].y = f->get_real();
- v.matrix[0].z = f->get_real();
- v.matrix[0].w = f->get_real();
- v.matrix[1].x = f->get_real();
- v.matrix[1].y = f->get_real();
- v.matrix[1].z = f->get_real();
- v.matrix[1].w = f->get_real();
- v.matrix[2].x = f->get_real();
- v.matrix[2].y = f->get_real();
- v.matrix[2].z = f->get_real();
- v.matrix[2].w = f->get_real();
- v.matrix[3].x = f->get_real();
- v.matrix[3].y = f->get_real();
- v.matrix[3].z = f->get_real();
- v.matrix[3].w = f->get_real();
+ v.columns[0].x = f->get_real();
+ v.columns[0].y = f->get_real();
+ v.columns[0].z = f->get_real();
+ v.columns[0].w = f->get_real();
+ v.columns[1].x = f->get_real();
+ v.columns[1].y = f->get_real();
+ v.columns[1].z = f->get_real();
+ v.columns[1].w = f->get_real();
+ v.columns[2].x = f->get_real();
+ v.columns[2].y = f->get_real();
+ v.columns[2].z = f->get_real();
+ v.columns[2].w = f->get_real();
+ v.columns[3].x = f->get_real();
+ v.columns[3].y = f->get_real();
+ v.columns[3].z = f->get_real();
+ v.columns[3].w = f->get_real();
r_v = v;
} break;
case VARIANT_COLOR: {
@@ -1042,7 +1042,14 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
er.path = ResourceUID::get_singleton()->get_id_path(er.uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(res_path) != er.uid) {
+ WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+#endif
}
}
}
@@ -1100,16 +1107,14 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
uint32_t ver_major = f->get_32();
f->get_32(); // ver_minor
- uint32_t ver_format = f->get_32();
+ uint32_t ver_fmt = f->get_32();
- if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
+ if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
f.unref();
return "";
}
- String type = get_unicode_string();
-
- return type;
+ return get_unicode_string();
}
Ref<Resource> ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
@@ -1630,22 +1635,22 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::PROJECTION: {
f->store_32(VARIANT_PROJECTION);
Projection val = p_property;
- f->store_real(val.matrix[0].x);
- f->store_real(val.matrix[0].y);
- f->store_real(val.matrix[0].z);
- f->store_real(val.matrix[0].w);
- f->store_real(val.matrix[1].x);
- f->store_real(val.matrix[1].y);
- f->store_real(val.matrix[1].z);
- f->store_real(val.matrix[1].w);
- f->store_real(val.matrix[2].x);
- f->store_real(val.matrix[2].y);
- f->store_real(val.matrix[2].z);
- f->store_real(val.matrix[2].w);
- f->store_real(val.matrix[3].x);
- f->store_real(val.matrix[3].y);
- f->store_real(val.matrix[3].z);
- f->store_real(val.matrix[3].w);
+ f->store_real(val.columns[0].x);
+ f->store_real(val.columns[0].y);
+ f->store_real(val.columns[0].z);
+ f->store_real(val.columns[0].w);
+ f->store_real(val.columns[1].x);
+ f->store_real(val.columns[1].y);
+ f->store_real(val.columns[1].z);
+ f->store_real(val.columns[1].w);
+ f->store_real(val.columns[2].x);
+ f->store_real(val.columns[2].y);
+ f->store_real(val.columns[2].z);
+ f->store_real(val.columns[2].w);
+ f->store_real(val.columns[3].x);
+ f->store_real(val.columns[3].y);
+ f->store_real(val.columns[3].z);
+ f->store_real(val.columns[3].w);
} break;
case Variant::COLOR: {
@@ -2118,9 +2123,9 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
for (int i = 0; i < save_order.size(); i++) {
save_unicode_string(f, save_order[i]->get_save_class());
- String path = save_order[i]->get_path();
- path = relative_paths ? local_path.path_to_file(path) : path;
- save_unicode_string(f, path);
+ String res_path = save_order[i]->get_path();
+ res_path = relative_paths ? local_path.path_to_file(res_path) : res_path;
+ save_unicode_string(f, res_path);
ResourceUID::ID ruid = ResourceSaver::get_resource_id_for_path(save_order[i]->get_path(), false);
f->store_64(ruid);
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index d923522317..564b37e662 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -110,8 +110,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
#ifdef TOOLS_ENABLED
if (r_path_and_type.metadata && !r_path_and_type.path.is_empty()) {
- Dictionary metadata = r_path_and_type.metadata;
- if (metadata.has("has_editor_variant")) {
+ Dictionary meta = r_path_and_type.metadata;
+ if (meta.has("has_editor_variant")) {
r_path_and_type.path = r_path_and_type.path.get_basename() + ".editor." + r_path_and_type.path.get_extension();
}
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index eccb397e2e..6219ea70e4 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -49,6 +49,11 @@ Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS];
int ResourceLoader::loader_count = 0;
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_path, p_for_type, ret)) {
+ return ret;
+ }
+
String extension = p_path.get_extension();
List<String> extensions;
@@ -68,12 +73,9 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_
}
bool ResourceFormatLoader::handles_type(const String &p_type) const {
- bool success;
- if (GDVIRTUAL_CALL(_handles_type, p_type, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_handles_type, p_type, success);
+ return success;
}
void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
@@ -93,21 +95,14 @@ void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<String
String ResourceFormatLoader::get_resource_type(const String &p_path) const {
String ret;
-
- if (GDVIRTUAL_CALL(_get_resource_type, p_path, ret)) {
- return ret;
- }
-
- return "";
+ GDVIRTUAL_CALL(_get_resource_type, p_path, ret);
+ return ret;
}
ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const {
- int64_t uid;
- if (GDVIRTUAL_CALL(_get_resource_uid, p_path, uid)) {
- return uid;
- }
-
- return ResourceUID::INVALID_ID;
+ int64_t uid = ResourceUID::INVALID_ID;
+ GDVIRTUAL_CALL(_get_resource_uid, p_path, uid);
+ return uid;
}
void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
@@ -123,11 +118,11 @@ void ResourceLoader::get_recognized_extensions_for_type(const String &p_type, Li
}
bool ResourceFormatLoader::exists(const String &p_path) const {
- bool success;
+ bool success = false;
if (GDVIRTUAL_CALL(_exists, p_path, success)) {
return success;
}
- return FileAccess::exists(p_path); //by default just check file
+ return FileAccess::exists(p_path); // By default just check file.
}
void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const {
@@ -175,12 +170,9 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Hash
deps_dict[E.key] = E.value;
}
- int64_t err;
- if (GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err)) {
- return (Error)err;
- }
-
- return OK;
+ int64_t err = OK;
+ GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err);
+ return (Error)err;
}
void ResourceFormatLoader::_bind_methods() {
@@ -189,6 +181,7 @@ void ResourceFormatLoader::_bind_methods() {
BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_recognize_path, "path", "type");
GDVIRTUAL_BIND(_handles_type, "type");
GDVIRTUAL_BIND(_get_resource_type, "path");
GDVIRTUAL_BIND(_get_resource_uid, "path");
@@ -908,7 +901,7 @@ void ResourceLoader::load_translation_remaps() {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (const Variant &E : keys) {
@@ -935,7 +928,7 @@ void ResourceLoader::load_path_remaps() {
return;
}
- Vector<String> remaps = ProjectSettings::get_singleton()->get("path_remap/remapped_paths");
+ Vector<String> remaps = GLOBAL_GET("path_remap/remapped_paths");
int rc = remaps.size();
ERR_FAIL_COND(rc & 1); //must be even
const String *r = remaps.ptr();
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 91ba930176..243670b2d0 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -51,6 +51,7 @@ protected:
static void _bind_methods();
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
+ GDVIRTUAL2RC(bool, _recognize_path, String, StringName)
GDVIRTUAL1RC(bool, _handles_type, StringName)
GDVIRTUAL1RC(String, _get_resource_type, String)
GDVIRTUAL1RC(ResourceUID::ID, _get_resource_uid, String)
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 386ccb78e9..710afc614f 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -42,21 +42,15 @@ ResourceSavedCallback ResourceSaver::save_callback = nullptr;
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;
Error ResourceFormatSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
- int64_t res;
- if (GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res)) {
- return (Error)res;
- }
-
- return ERR_METHOD_NOT_FOUND;
+ int64_t res = ERR_METHOD_NOT_FOUND;
+ GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res);
+ return (Error)res;
}
bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
- bool success;
- if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_recognize, p_resource, success);
+ return success;
}
void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
@@ -69,10 +63,31 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou
}
}
+bool ResourceFormatSaver::recognize_path(const Ref<Resource> &p_resource, const String &p_path) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_resource, p_path, ret)) {
+ return ret;
+ }
+
+ String extension = p_path.get_extension();
+
+ List<String> extensions;
+ get_recognized_extensions(p_resource, &extensions);
+
+ for (const String &E : extensions) {
+ if (E.nocasecmp_to(extension) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void ResourceFormatSaver::_bind_methods() {
GDVIRTUAL_BIND(_save, "resource", "path", "flags");
GDVIRTUAL_BIND(_recognize, "resource");
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
+ GDVIRTUAL_BIND(_recognize_path, "resource", "path");
}
Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
@@ -90,17 +105,7 @@ Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path,
continue;
}
- List<String> extensions;
- bool recognized = false;
- saver[i]->get_recognized_extensions(p_resource, &extensions);
-
- for (const String &E : extensions) {
- if (E.nocasecmp_to(extension) == 0) {
- recognized = true;
- }
- }
-
- if (!recognized) {
+ if (!saver[i]->recognize_path(p_resource, path)) {
continue;
}
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 4fee2bcfd1..5e48ce88c3 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -44,11 +44,13 @@ protected:
GDVIRTUAL3R(int64_t, _save, Ref<Resource>, String, uint32_t)
GDVIRTUAL1RC(bool, _recognize, Ref<Resource>)
GDVIRTUAL1RC(Vector<String>, _get_recognized_extensions, Ref<Resource>)
+ GDVIRTUAL2RC(bool, _recognize_path, Ref<Resource>, String)
public:
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
virtual bool recognize(const Ref<Resource> &p_resource) const;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize_path(const Ref<Resource> &p_resource, const String &p_path) const;
virtual ~ResourceFormatSaver() {}
};
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index ba79590c19..e035e1b613 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -256,9 +256,9 @@ void StreamPeerTCP::disconnect_from_host() {
peer_port = 0;
}
-Error StreamPeerTCP::wait(NetSocket::PollType p_type, int timeout) {
+Error StreamPeerTCP::wait(NetSocket::PollType p_type, int p_timeout) {
ERR_FAIL_COND_V(_sock.is_null() || !_sock->is_open(), ERR_UNAVAILABLE);
- return _sock->poll(p_type, timeout);
+ return _sock->poll(p_type, p_timeout);
}
Error StreamPeerTCP::put_data(const uint8_t *p_data, int p_bytes) {
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 39c2e84346..778fb83374 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -79,7 +79,7 @@ public:
Error poll();
// Wait or check for writable, readable.
- Error wait(NetSocket::PollType p_type, int timeout = 0);
+ Error wait(NetSocket::PollType p_type, int p_timeout = 0);
// Read/Write from StreamPeer
Error put_data(const uint8_t *p_data, int p_bytes) override;
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index e573e8de19..200e5f5e83 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -37,11 +37,17 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
String fname;
fname.parse_utf8(p_fname);
+ int file_access_mode = 0;
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
- (*fa) = FileAccess::open(fname, FileAccess::WRITE);
- } else {
- (*fa) = FileAccess::open(fname, FileAccess::READ);
+ file_access_mode |= FileAccess::WRITE;
}
+ if (mode & ZLIB_FILEFUNC_MODE_READ) {
+ file_access_mode |= FileAccess::READ;
+ }
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
+ file_access_mode |= FileAccess::WRITE_READ;
+ }
+ (*fa) = FileAccess::open(fname, file_access_mode);
if (fa->is_null()) {
return nullptr;
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 4c89be7f4d..fcf245d2ad 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -30,7 +30,7 @@
#include "aabb.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/variant/variant.h"
real_t AABB::get_volume() const {
@@ -76,6 +76,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
+bool AABB::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
@@ -403,6 +407,7 @@ Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to
}
return Variant();
}
+
Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
diff --git a/core/math/aabb.h b/core/math/aabb.h
index acf903eeba..9d5837ad37 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -31,7 +31,6 @@
#ifndef AABB_H
#define AABB_H
-#include "core/math/math_defs.h"
#include "core/math/plane.h"
#include "core/math/vector3.h"
@@ -64,6 +63,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
@@ -101,7 +101,7 @@ struct _NO_DISCARD_ AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
- return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs());
+ return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 4b163409ce..9b8188eed8 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -31,7 +31,7 @@
#include "basis.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#define cofac(row1, col1, row2, col2) \
(rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
@@ -142,8 +142,8 @@ bool Basis::is_symmetric() const {
#endif
Basis Basis::diagonalize() {
-//NOTE: only implemented for symmetric matrices
-//with the Jacobi iterative method
+// NOTE: only implemented for symmetric matrices
+// with the Jacobi iterative method
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_symmetric(), Basis());
#endif
@@ -691,6 +691,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
+bool Basis::is_finite() const {
+ return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
+}
+
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
diff --git a/core/math/basis.h b/core/math/basis.h
index cc2924f5ff..69bef5a7be 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -134,6 +134,7 @@ struct _NO_DISCARD_ Basis {
}
bool is_equal_approx(const Basis &p_basis) const;
+ bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index 8291394b31..3836e92a83 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -43,7 +43,6 @@
#include "core/math/bvh_abb.h"
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/pooled_list.h"
#include <limits.h>
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 4bdeafd2f2..f223853f6b 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -32,85 +32,85 @@
#include "color_names.inc"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/templates/rb_map.h"
#include "thirdparty/misc/ok_color.h"
uint32_t Color::to_argb32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
return c;
}
uint32_t Color::to_abgr32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
return c;
}
uint32_t Color::to_rgba32() const {
- uint32_t c = (uint8_t)Math::round(r * 255);
+ uint32_t c = (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(a * 255);
+ c |= (uint8_t)Math::round(a * 255.0f);
return c;
}
uint64_t Color::to_abgr64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
return c;
}
uint64_t Color::to_argb64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
return c;
}
uint64_t Color::to_rgba64() const {
- uint64_t c = (uint16_t)Math::round(r * 65535);
+ uint64_t c = (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(a * 65535);
+ c |= (uint16_t)Math::round(a * 65535.0f);
return c;
}
String _to_hex(float p_val) {
- int v = Math::round(p_val * 255);
+ int v = Math::round(p_val * 255.0f);
v = CLAMP(v, 0, 255);
String ret;
@@ -150,8 +150,8 @@ float Color::get_h() const {
float delta = max - min;
- if (delta == 0) {
- return 0;
+ if (delta == 0.0f) {
+ return 0.0f;
}
float h;
@@ -164,7 +164,7 @@ float Color::get_h() const {
}
h /= 6.0f;
- if (h < 0) {
+ if (h < 0.0f) {
h += 1.0f;
}
@@ -179,7 +179,7 @@ float Color::get_s() const {
float delta = max - min;
- return (max != 0) ? (delta / max) : 0;
+ return (max != 0.0f) ? (delta / max) : 0.0f;
}
float Color::get_v() const {
@@ -193,7 +193,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
float f, p, q, t;
a = p_alpha;
- if (p_s == 0) {
+ if (p_s == 0.0f) {
// Achromatic (grey)
r = g = b = p_v;
return;
@@ -204,9 +204,9 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
i = Math::floor(p_h);
f = p_h - i;
- p = p_v * (1 - p_s);
- q = p_v * (1 - p_s * f);
- t = p_v * (1 - p_s * (1 - f));
+ p = p_v * (1.0f - p_s);
+ q = p_v * (1.0f - p_s * f);
+ t = p_v * (1.0f - p_s * (1.0f - f));
switch (i) {
case 0: // Red is the dominant color
@@ -347,7 +347,7 @@ Color Color::html(const String &p_rgba) {
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
- float r, g, b, a = 1.0;
+ float r, g, b, a = 1.0f;
if (is_shorthand) {
r = _parse_col4(color, 0) / 15.0f;
g = _parse_col4(color, 1) / 15.0f;
@@ -363,10 +363,10 @@ Color Color::html(const String &p_rgba) {
a = _parse_col8(color, 6) / 255.0f;
}
}
- ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(a < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
return Color(r, g, b, a);
}
@@ -474,7 +474,7 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
float g = (p_rgbe >> 9) & 0x1ff;
float b = (p_rgbe >> 18) & 0x1ff;
float e = (p_rgbe >> 27);
- float m = Math::pow(2, e - 15.0f - 9.0f);
+ float m = Math::pow(2.0f, e - 15.0f - 9.0f);
float rd = r * m;
float gd = g * m;
diff --git a/core/math/color.h b/core/math/color.h
index 65036f74cc..a23a4953ce 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -32,7 +32,8 @@
#define COLOR_H
#include "core/math/math_funcs.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Color {
union {
@@ -55,11 +56,11 @@ struct _NO_DISCARD_ Color {
float get_h() const;
float get_s() const;
float get_v() const;
- void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
+ void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
float get_ok_hsl_h() const;
float get_ok_hsl_s() const;
float get_ok_hsl_l() const;
- void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
_FORCE_INLINE_ float &operator[](int p_idx) {
return components[p_idx];
@@ -175,9 +176,9 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
- r < 0.04045f ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- g < 0.04045f ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- b < 0.04045f ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
+ r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
a);
}
_FORCE_INLINE_ Color linear_to_srgb() const {
@@ -198,11 +199,11 @@ struct _NO_DISCARD_ Color {
static String get_named_color_name(int p_idx);
static Color get_named_color(int p_idx);
static Color from_string(const String &p_string, const Color &p_default);
- static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
- static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
+ static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
- _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
+ _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
// For the binder.
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 996f4f4d67..561970d2ee 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -62,6 +62,7 @@ subject to the following restrictions:
#include "core/math/aabb.h"
#include "core/math/math_defs.h"
#include "core/os/memory.h"
+#include "core/templates/oa_hash_map.h"
#include "core/templates/paged_allocator.h"
#include <string.h>
@@ -2252,19 +2253,62 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
r_mesh.vertices = ch.vertices;
+ // Tag which face each edge belongs to
+ LocalVector<int32_t> edge_faces;
+ edge_faces.resize(ch.edges.size());
+
+ for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ edge_faces[i] = -1;
+ }
+
+ for (uint32_t i = 0; i < ch.faces.size(); i++) {
+ const Edge *e_start = &ch.edges[ch.faces[i]];
+ const Edge *e = e_start;
+ do {
+ int64_t ofs = e - ch.edges.ptr();
+ edge_faces[ofs] = i;
+
+ e = e->get_next_edge_of_face();
+ } while (e != e_start);
+ }
+
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
r_mesh.edges.resize(ch.edges.size() / 2);
+ OAHashMap<uint64_t, int32_t> edge_map;
+ edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert
+
uint32_t edges_copied = 0;
for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ ERR_CONTINUE(edge_faces[i] == -1); // Sanity check
+
uint32_t a = (&ch.edges[i])->get_source_vertex();
uint32_t b = (&ch.edges[i])->get_target_vertex();
if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false.
ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size());
- r_mesh.edges.write[edges_copied].a = a;
- r_mesh.edges.write[edges_copied].b = b;
+ r_mesh.edges[edges_copied].vertex_a = a;
+ r_mesh.edges[edges_copied].vertex_b = b;
+ r_mesh.edges[edges_copied].face_a = edge_faces[i];
+ r_mesh.edges[edges_copied].face_b = -1;
+
+ uint64_t key = a;
+ key <<= 32;
+ key |= b;
+ edge_map.insert(key, edges_copied);
+
edges_copied++;
+ } else {
+ uint64_t key = b;
+ key <<= 32;
+ key |= a;
+ int32_t index;
+ if (!edge_map.lookup(key, index)) {
+ ERR_PRINT("Invalid edge");
+ } else {
+ r_mesh.edges[index].face_b = edge_faces[i];
+ }
}
}
+
if (edges_copied != (uint32_t)r_mesh.edges.size()) {
ERR_PRINT("Invalid edge count.");
}
@@ -2273,7 +2317,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
for (uint32_t i = 0; i < ch.faces.size(); i++) {
const Edge *e_start = &ch.edges[ch.faces[i]];
const Edge *e = e_start;
- Geometry3D::MeshData::Face &face = r_mesh.faces.write[i];
+ Geometry3D::MeshData::Face &face = r_mesh.faces[i];
do {
face.indices.push_back(e->get_target_vertex());
@@ -2284,8 +2328,8 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
// reverse indices: Godot wants clockwise, but this is counter-clockwise
if (face.indices.size() > 2) {
// reverse all but the first index.
- int *indices = face.indices.ptrw();
- for (int c = 0; c < (face.indices.size() - 1) / 2; c++) {
+ int *indices = face.indices.ptr();
+ for (uint32_t c = 0; c < (face.indices.size() - 1) / 2; c++) {
SWAP(indices[c + 1], indices[face.indices.size() - 1 - c]);
}
}
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h
index cc41a794bd..ab6671a7d0 100644
--- a/core/math/convex_hull.h
+++ b/core/math/convex_hull.h
@@ -62,6 +62,10 @@ public:
friend class ConvexHullComputer;
public:
+ int32_t get_next_relative() const {
+ return next;
+ }
+
int32_t get_source_vertex() const {
return (this + reverse)->target_vertex;
}
@@ -86,7 +90,7 @@ public:
};
// Vertices of the output hull
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
// Edges of the output hull
LocalVector<Edge> edges;
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 898c3c2d91..3f8fe09445 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -35,7 +35,6 @@
#include "core/math/aabb.h"
#include "core/math/projection.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/vector.h"
@@ -186,25 +185,25 @@ class Delaunay3D {
Projection cm;
- cm.matrix[0][0] = p_points[p_simplex.points[0]].x;
- cm.matrix[0][1] = p_points[p_simplex.points[1]].x;
- cm.matrix[0][2] = p_points[p_simplex.points[2]].x;
- cm.matrix[0][3] = p_points[p_simplex.points[3]].x;
-
- cm.matrix[1][0] = p_points[p_simplex.points[0]].y;
- cm.matrix[1][1] = p_points[p_simplex.points[1]].y;
- cm.matrix[1][2] = p_points[p_simplex.points[2]].y;
- cm.matrix[1][3] = p_points[p_simplex.points[3]].y;
-
- cm.matrix[2][0] = p_points[p_simplex.points[0]].z;
- cm.matrix[2][1] = p_points[p_simplex.points[1]].z;
- cm.matrix[2][2] = p_points[p_simplex.points[2]].z;
- cm.matrix[2][3] = p_points[p_simplex.points[3]].z;
-
- cm.matrix[3][0] = 1.0;
- cm.matrix[3][1] = 1.0;
- cm.matrix[3][2] = 1.0;
- cm.matrix[3][3] = 1.0;
+ cm.columns[0][0] = p_points[p_simplex.points[0]].x;
+ cm.columns[0][1] = p_points[p_simplex.points[1]].x;
+ cm.columns[0][2] = p_points[p_simplex.points[2]].x;
+ cm.columns[0][3] = p_points[p_simplex.points[3]].x;
+
+ cm.columns[1][0] = p_points[p_simplex.points[0]].y;
+ cm.columns[1][1] = p_points[p_simplex.points[1]].y;
+ cm.columns[1][2] = p_points[p_simplex.points[2]].y;
+ cm.columns[1][3] = p_points[p_simplex.points[3]].y;
+
+ cm.columns[2][0] = p_points[p_simplex.points[0]].z;
+ cm.columns[2][1] = p_points[p_simplex.points[1]].z;
+ cm.columns[2][2] = p_points[p_simplex.points[2]].z;
+ cm.columns[2][3] = p_points[p_simplex.points[3]].z;
+
+ cm.columns[3][0] = 1.0;
+ cm.columns[3][1] = 1.0;
+ cm.columns[3][2] = 1.0;
+ cm.columns[3][3] = 1.0;
return ABS(cm.determinant()) <= CMP_EPSILON;
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index e230b69dc9..dcec3929fe 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -560,7 +560,7 @@ const char *Expression::token_name[TK_MAX] = {
};
Expression::ENode *Expression::_parse_expression() {
- Vector<ExpressionNode> expression;
+ Vector<ExpressionNode> expression_nodes;
while (true) {
//keep appending stuff to expression
@@ -838,14 +838,14 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = true;
e.op = Variant::OP_NEGATE;
- expression.push_back(e);
+ expression_nodes.push_back(e);
continue;
} break;
case TK_OP_NOT: {
ExpressionNode e;
e.is_op = true;
e.op = Variant::OP_NOT;
- expression.push_back(e);
+ expression_nodes.push_back(e);
continue;
} break;
@@ -960,7 +960,7 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = false;
e.node = expr;
- expression.push_back(e);
+ expression_nodes.push_back(e);
}
//ok finally look for an operator
@@ -1054,19 +1054,19 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = true;
e.op = op;
- expression.push_back(e);
+ expression_nodes.push_back(e);
}
}
/* Reduce the set of expressions and place them in an operator tree, respecting precedence */
- while (expression.size() > 1) {
+ while (expression_nodes.size() > 1) {
int next_op = -1;
int min_priority = 0xFFFFF;
bool is_unary = false;
- for (int i = 0; i < expression.size(); i++) {
- if (!expression[i].is_op) {
+ for (int i = 0; i < expression_nodes.size(); i++) {
+ if (!expression_nodes[i].is_op) {
continue;
}
@@ -1074,7 +1074,7 @@ Expression::ENode *Expression::_parse_expression() {
bool unary = false;
- switch (expression[i].op) {
+ switch (expression_nodes[i].op) {
case Variant::OP_POWER:
priority = 0;
break;
@@ -1130,7 +1130,7 @@ Expression::ENode *Expression::_parse_expression() {
priority = 14;
break;
default: {
- _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
+ _set_error("Parser bug, invalid operator in expression: " + itos(expression_nodes[i].op));
return nullptr;
}
}
@@ -1153,9 +1153,9 @@ Expression::ENode *Expression::_parse_expression() {
// OK! create operator..
if (is_unary) {
int expr_pos = next_op;
- while (expression[expr_pos].is_op) {
+ while (expression_nodes[expr_pos].is_op) {
expr_pos++;
- if (expr_pos == expression.size()) {
+ if (expr_pos == expression_nodes.size()) {
//can happen..
_set_error("Unexpected end of expression...");
return nullptr;
@@ -1165,29 +1165,29 @@ Expression::ENode *Expression::_parse_expression() {
//consecutively do unary operators
for (int i = expr_pos - 1; i >= next_op; i--) {
OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[i].op;
- op->nodes[0] = expression[i + 1].node;
+ op->op = expression_nodes[i].op;
+ op->nodes[0] = expression_nodes[i + 1].node;
op->nodes[1] = nullptr;
- expression.write[i].is_op = false;
- expression.write[i].node = op;
- expression.remove_at(i + 1);
+ expression_nodes.write[i].is_op = false;
+ expression_nodes.write[i].node = op;
+ expression_nodes.remove_at(i + 1);
}
} else {
- if (next_op < 1 || next_op >= (expression.size() - 1)) {
+ if (next_op < 1 || next_op >= (expression_nodes.size() - 1)) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[next_op].op;
+ op->op = expression_nodes[next_op].op;
- if (expression[next_op - 1].is_op) {
+ if (expression_nodes[next_op - 1].is_op) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
- if (expression[next_op + 1].is_op) {
+ if (expression_nodes[next_op + 1].is_op) {
// this is not invalid and can really appear
// but it becomes invalid anyway because no binary op
// can be followed by a unary op in a valid combination,
@@ -1197,17 +1197,17 @@ Expression::ENode *Expression::_parse_expression() {
return nullptr;
}
- op->nodes[0] = expression[next_op - 1].node; //expression goes as left
- op->nodes[1] = expression[next_op + 1].node; //next expression goes as right
+ op->nodes[0] = expression_nodes[next_op - 1].node; //expression goes as left
+ op->nodes[1] = expression_nodes[next_op + 1].node; //next expression goes as right
//replace all 3 nodes by this operator and make it an expression
- expression.write[next_op - 1].node = op;
- expression.remove_at(next_op);
- expression.remove_at(next_op);
+ expression_nodes.write[next_op - 1].node = op;
+ expression_nodes.remove_at(next_op);
+ expression_nodes.remove_at(next_op);
}
}
- return expression[0].node;
+ return expression_nodes[0].node;
}
bool Expression::_compile_expression() {
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 9238293b48..548b9e4620 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -30,8 +30,6 @@
#include "geometry_3d.h"
-#include "core/string/print_string.h"
-
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -143,21 +141,21 @@ real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, co
void Geometry3D::MeshData::optimize_vertices() {
HashMap<int, int> vtx_remap;
- for (int i = 0; i < faces.size(); i++) {
- for (int j = 0; j < faces[i].indices.size(); j++) {
+ for (uint32_t i = 0; i < faces.size(); i++) {
+ for (uint32_t j = 0; j < faces[i].indices.size(); j++) {
int idx = faces[i].indices[j];
if (!vtx_remap.has(idx)) {
int ni = vtx_remap.size();
vtx_remap[idx] = ni;
}
- faces.write[i].indices.write[j] = vtx_remap[idx];
+ faces[i].indices[j] = vtx_remap[idx];
}
}
- for (int i = 0; i < edges.size(); i++) {
- int a = edges[i].a;
- int b = edges[i].b;
+ for (uint32_t i = 0; i < edges.size(); i++) {
+ int a = edges[i].vertex_a;
+ int b = edges[i].vertex_b;
if (!vtx_remap.has(a)) {
int ni = vtx_remap.size();
@@ -168,16 +166,16 @@ void Geometry3D::MeshData::optimize_vertices() {
vtx_remap[b] = ni;
}
- edges.write[i].a = vtx_remap[a];
- edges.write[i].b = vtx_remap[b];
+ edges[i].vertex_a = vtx_remap[a];
+ edges[i].vertex_b = vtx_remap[b];
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
new_vertices.resize(vtx_remap.size());
- for (int i = 0; i < vertices.size(); i++) {
+ for (uint32_t i = 0; i < vertices.size(); i++) {
if (vtx_remap.has(i)) {
- new_vertices.write[vtx_remap[i]] = vertices[i];
+ new_vertices[vtx_remap[i]] = vertices[i];
}
}
vertices = new_vertices;
@@ -753,7 +751,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector3 center = p.center();
// make a quad clockwise
- Vector<Vector3> vertices = {
+ LocalVector<Vector3> vertices = {
center - up * subplane_size + right * subplane_size,
center - up * subplane_size - right * subplane_size,
center + up * subplane_size - right * subplane_size,
@@ -765,7 +763,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
continue;
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
Plane clip = p_planes[j];
if (clip.normal.dot(p.normal) > 0.95f) {
@@ -776,7 +774,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
break;
}
- for (int k = 0; k < vertices.size(); k++) {
+ for (uint32_t k = 0; k < vertices.size(); k++) {
int k_n = (k + 1) % vertices.size();
Vector3 edge0_A = vertices[k];
@@ -818,9 +816,9 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
MeshData::Face face;
// Add face indices.
- for (int j = 0; j < vertices.size(); j++) {
+ for (uint32_t j = 0; j < vertices.size(); j++) {
int idx = -1;
- for (int k = 0; k < mesh.vertices.size(); k++) {
+ for (uint32_t k = 0; k < mesh.vertices.size(); k++) {
if (mesh.vertices[k].distance_to(vertices[j]) < 0.001f) {
idx = k;
break;
@@ -839,28 +837,34 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
// Add edge.
- for (int j = 0; j < face.indices.size(); j++) {
+ for (uint32_t j = 0; j < face.indices.size(); j++) {
int a = face.indices[j];
int b = face.indices[(j + 1) % face.indices.size()];
bool found = false;
- for (int k = 0; k < mesh.edges.size(); k++) {
- if (mesh.edges[k].a == a && mesh.edges[k].b == b) {
+ int found_idx = -1;
+ for (uint32_t k = 0; k < mesh.edges.size(); k++) {
+ if (mesh.edges[k].vertex_a == a && mesh.edges[k].vertex_b == b) {
found = true;
+ found_idx = k;
break;
}
- if (mesh.edges[k].b == a && mesh.edges[k].a == b) {
+ if (mesh.edges[k].vertex_b == a && mesh.edges[k].vertex_a == b) {
found = true;
+ found_idx = k;
break;
}
}
if (found) {
+ mesh.edges[found_idx].face_b = j;
continue;
}
MeshData::Edge edge;
- edge.a = a;
- edge.b = b;
+ edge.vertex_a = a;
+ edge.vertex_b = b;
+ edge.face_a = j;
+ edge.face_b = -1;
mesh.edges.push_back(edge);
}
}
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index e5ace9db72..4b4c173a1e 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -33,6 +33,7 @@
#include "core/math/face3.h"
#include "core/object/object.h"
+#include "core/templates/local_vector.h"
#include "core/templates/vector.h"
class Geometry3D {
@@ -539,18 +540,19 @@ public:
struct MeshData {
struct Face {
Plane plane;
- Vector<int> indices;
+ LocalVector<int> indices;
};
- Vector<Face> faces;
+ LocalVector<Face> faces;
struct Edge {
- int a, b;
+ int vertex_a, vertex_b;
+ int face_a, face_b;
};
- Vector<Edge> edges;
+ LocalVector<Edge> edges;
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
void optimize_vertices();
};
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 726a2aeb97..7b30b9a98c 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -215,22 +215,22 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
case Variant::PROJECTION: {
SETUP_TYPE(Projection)
- /**/ TRY_TRANSFER_FIELD("xx", matrix[0].x)
- else TRY_TRANSFER_FIELD("xy", matrix[0].y)
- else TRY_TRANSFER_FIELD("xz", matrix[0].z)
- else TRY_TRANSFER_FIELD("xw", matrix[0].w)
- else TRY_TRANSFER_FIELD("yx", matrix[1].x)
- else TRY_TRANSFER_FIELD("yy", matrix[1].y)
- else TRY_TRANSFER_FIELD("yz", matrix[1].z)
- else TRY_TRANSFER_FIELD("yw", matrix[1].w)
- else TRY_TRANSFER_FIELD("zx", matrix[2].x)
- else TRY_TRANSFER_FIELD("zy", matrix[2].y)
- else TRY_TRANSFER_FIELD("zz", matrix[2].z)
- else TRY_TRANSFER_FIELD("zw", matrix[2].w)
- else TRY_TRANSFER_FIELD("xo", matrix[3].x)
- else TRY_TRANSFER_FIELD("yo", matrix[3].y)
- else TRY_TRANSFER_FIELD("zo", matrix[3].z)
- else TRY_TRANSFER_FIELD("wo", matrix[3].w)
+ /**/ TRY_TRANSFER_FIELD("xx", columns[0].x)
+ else TRY_TRANSFER_FIELD("xy", columns[0].y)
+ else TRY_TRANSFER_FIELD("xz", columns[0].z)
+ else TRY_TRANSFER_FIELD("xw", columns[0].w)
+ else TRY_TRANSFER_FIELD("yx", columns[1].x)
+ else TRY_TRANSFER_FIELD("yy", columns[1].y)
+ else TRY_TRANSFER_FIELD("yz", columns[1].z)
+ else TRY_TRANSFER_FIELD("yw", columns[1].w)
+ else TRY_TRANSFER_FIELD("zx", columns[2].x)
+ else TRY_TRANSFER_FIELD("zy", columns[2].y)
+ else TRY_TRANSFER_FIELD("zz", columns[2].z)
+ else TRY_TRANSFER_FIELD("zw", columns[2].w)
+ else TRY_TRANSFER_FIELD("xo", columns[3].x)
+ else TRY_TRANSFER_FIELD("yo", columns[3].y)
+ else TRY_TRANSFER_FIELD("zo", columns[3].z)
+ else TRY_TRANSFER_FIELD("wo", columns[3].w)
return target;
}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 7fa674a23d..0af529ad98 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -184,6 +184,9 @@ public:
#endif
}
+ static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); }
+ static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); }
+
static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 6881ad4014..a5d2fe5628 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -147,6 +147,7 @@ Variant Plane::intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) co
return Variant();
}
}
+
Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
@@ -155,6 +156,7 @@ Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir)
return Variant();
}
}
+
Variant Plane::intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const {
Vector3 inters;
if (intersects_segment(p_begin, p_end, &inters)) {
@@ -174,6 +176,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
+bool Plane::is_finite() const {
+ return normal.is_finite() && Math::is_finite(d);
+}
+
Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 73babfa496..77da59fb27 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -74,6 +74,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 863fe6ee79..70cc9b5f7c 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -35,27 +35,27 @@
#include "core/math/plane.h"
#include "core/math/rect2.h"
#include "core/math/transform_3d.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
float Projection::determinant() const {
- return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
- matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] +
- matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] -
- matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] +
- matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] -
- matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] +
- matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] -
- matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] +
- matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] -
- matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] +
- matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] -
- matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3];
+ return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
+ columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] +
+ columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] -
+ columns[0][3] * columns[1][2] * columns[2][0] * columns[3][1] + columns[0][2] * columns[1][3] * columns[2][0] * columns[3][1] +
+ columns[0][3] * columns[1][0] * columns[2][2] * columns[3][1] - columns[0][0] * columns[1][3] * columns[2][2] * columns[3][1] -
+ columns[0][2] * columns[1][0] * columns[2][3] * columns[3][1] + columns[0][0] * columns[1][2] * columns[2][3] * columns[3][1] +
+ columns[0][3] * columns[1][1] * columns[2][0] * columns[3][2] - columns[0][1] * columns[1][3] * columns[2][0] * columns[3][2] -
+ columns[0][3] * columns[1][0] * columns[2][1] * columns[3][2] + columns[0][0] * columns[1][3] * columns[2][1] * columns[3][2] +
+ columns[0][1] * columns[1][0] * columns[2][3] * columns[3][2] - columns[0][0] * columns[1][1] * columns[2][3] * columns[3][2] -
+ columns[0][2] * columns[1][1] * columns[2][0] * columns[3][3] + columns[0][1] * columns[1][2] * columns[2][0] * columns[3][3] +
+ columns[0][2] * columns[1][0] * columns[2][1] * columns[3][3] - columns[0][0] * columns[1][2] * columns[2][1] * columns[3][3] -
+ columns[0][1] * columns[1][0] * columns[2][2] * columns[3][3] + columns[0][0] * columns[1][1] * columns[2][2] * columns[3][3];
}
void Projection::set_identity() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- matrix[i][j] = (i == j) ? 1 : 0;
+ columns[i][j] = (i == j) ? 1 : 0;
}
}
}
@@ -63,7 +63,7 @@ void Projection::set_identity() {
void Projection::set_zero() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- matrix[i][j] = 0;
+ columns[i][j] = 0;
}
}
}
@@ -71,26 +71,26 @@ void Projection::set_zero() {
Plane Projection::xform4(const Plane &p_vec4) const {
Plane ret;
- ret.normal.x = matrix[0][0] * p_vec4.normal.x + matrix[1][0] * p_vec4.normal.y + matrix[2][0] * p_vec4.normal.z + matrix[3][0] * p_vec4.d;
- ret.normal.y = matrix[0][1] * p_vec4.normal.x + matrix[1][1] * p_vec4.normal.y + matrix[2][1] * p_vec4.normal.z + matrix[3][1] * p_vec4.d;
- ret.normal.z = matrix[0][2] * p_vec4.normal.x + matrix[1][2] * p_vec4.normal.y + matrix[2][2] * p_vec4.normal.z + matrix[3][2] * p_vec4.d;
- ret.d = matrix[0][3] * p_vec4.normal.x + matrix[1][3] * p_vec4.normal.y + matrix[2][3] * p_vec4.normal.z + matrix[3][3] * p_vec4.d;
+ ret.normal.x = columns[0][0] * p_vec4.normal.x + columns[1][0] * p_vec4.normal.y + columns[2][0] * p_vec4.normal.z + columns[3][0] * p_vec4.d;
+ ret.normal.y = columns[0][1] * p_vec4.normal.x + columns[1][1] * p_vec4.normal.y + columns[2][1] * p_vec4.normal.z + columns[3][1] * p_vec4.d;
+ ret.normal.z = columns[0][2] * p_vec4.normal.x + columns[1][2] * p_vec4.normal.y + columns[2][2] * p_vec4.normal.z + columns[3][2] * p_vec4.d;
+ ret.d = columns[0][3] * p_vec4.normal.x + columns[1][3] * p_vec4.normal.y + columns[2][3] * p_vec4.normal.z + columns[3][3] * p_vec4.d;
return ret;
}
Vector4 Projection::xform(const Vector4 &p_vec4) const {
return Vector4(
- matrix[0][0] * p_vec4.x + matrix[1][0] * p_vec4.y + matrix[2][0] * p_vec4.z + matrix[3][0] * p_vec4.w,
- matrix[0][1] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[2][1] * p_vec4.z + matrix[3][1] * p_vec4.w,
- matrix[0][2] * p_vec4.x + matrix[1][2] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[3][2] * p_vec4.w,
- matrix[0][3] * p_vec4.x + matrix[1][3] * p_vec4.y + matrix[2][3] * p_vec4.z + matrix[3][3] * p_vec4.w);
+ columns[0][0] * p_vec4.x + columns[1][0] * p_vec4.y + columns[2][0] * p_vec4.z + columns[3][0] * p_vec4.w,
+ columns[0][1] * p_vec4.x + columns[1][1] * p_vec4.y + columns[2][1] * p_vec4.z + columns[3][1] * p_vec4.w,
+ columns[0][2] * p_vec4.x + columns[1][2] * p_vec4.y + columns[2][2] * p_vec4.z + columns[3][2] * p_vec4.w,
+ columns[0][3] * p_vec4.x + columns[1][3] * p_vec4.y + columns[2][3] * p_vec4.z + columns[3][3] * p_vec4.w);
}
Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
return Vector4(
- matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w,
- matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w,
- matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w,
- matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w);
+ columns[0][0] * p_vec4.x + columns[0][1] * p_vec4.y + columns[0][2] * p_vec4.z + columns[0][3] * p_vec4.w,
+ columns[1][0] * p_vec4.x + columns[1][1] * p_vec4.y + columns[1][2] * p_vec4.z + columns[1][3] * p_vec4.w,
+ columns[2][0] * p_vec4.x + columns[2][1] * p_vec4.y + columns[2][2] * p_vec4.z + columns[2][3] * p_vec4.w,
+ columns[3][0] * p_vec4.x + columns[3][1] * p_vec4.y + columns[3][2] * p_vec4.z + columns[3][3] * p_vec4.w);
}
void Projection::adjust_perspective_znear(real_t p_new_znear) {
@@ -98,8 +98,8 @@ void Projection::adjust_perspective_znear(real_t p_new_znear) {
real_t znear = p_new_znear;
real_t deltaZ = zfar - znear;
- matrix[2][2] = -(zfar + znear) / deltaZ;
- matrix[3][2] = -2 * znear * zfar / deltaZ;
+ columns[2][2] = -(zfar + znear) / deltaZ;
+ columns[3][2] = -2 * znear * zfar / deltaZ;
}
Projection Projection::create_depth_correction(bool p_flip_y) {
@@ -169,7 +169,7 @@ Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const {
}
Plane Projection::get_projection_plane(Planes p_plane) const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
switch (p_plane) {
case PLANE_NEAR: {
@@ -267,12 +267,12 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
set_identity();
- matrix[0][0] = cotangent / p_aspect;
- matrix[1][1] = cotangent;
- matrix[2][2] = -(p_z_far + p_z_near) / deltaZ;
- matrix[2][3] = -1;
- matrix[3][2] = -2 * p_z_near * p_z_far / deltaZ;
- matrix[3][3] = 0;
+ columns[0][0] = cotangent / p_aspect;
+ columns[1][1] = cotangent;
+ columns[2][2] = -(p_z_far + p_z_near) / deltaZ;
+ columns[2][3] = -1;
+ columns[3][2] = -2 * p_z_near * p_z_far / deltaZ;
+ columns[3][3] = 0;
}
void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
@@ -309,7 +309,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
// translate matrix by (modeltranslation, 0.0, 0.0)
Projection cm;
cm.set_identity();
- cm.matrix[3][0] = modeltranslation;
+ cm.columns[3][0] = modeltranslation;
*this = *this * cm;
}
@@ -344,13 +344,13 @@ void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_di
void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
set_identity();
- matrix[0][0] = 2.0 / (p_right - p_left);
- matrix[3][0] = -((p_right + p_left) / (p_right - p_left));
- matrix[1][1] = 2.0 / (p_top - p_bottom);
- matrix[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
- matrix[2][2] = -2.0 / (p_zfar - p_znear);
- matrix[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
- matrix[3][3] = 1.0;
+ columns[0][0] = 2.0 / (p_right - p_left);
+ columns[3][0] = -((p_right + p_left) / (p_right - p_left));
+ columns[1][1] = 2.0 / (p_top - p_bottom);
+ columns[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
+ columns[2][2] = -2.0 / (p_zfar - p_znear);
+ columns[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
+ columns[3][3] = 1.0;
}
void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
@@ -366,7 +366,7 @@ void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, rea
ERR_FAIL_COND(p_top <= p_bottom);
ERR_FAIL_COND(p_far <= p_near);
- real_t *te = &matrix[0][0];
+ real_t *te = &columns[0][0];
real_t x = 2 * p_near / (p_right - p_left);
real_t y = 2 * p_near / (p_top - p_bottom);
@@ -402,7 +402,7 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r
}
real_t Projection::get_z_far() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
@@ -415,7 +415,7 @@ real_t Projection::get_z_far() const {
}
real_t Projection::get_z_near() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
@@ -426,7 +426,7 @@ real_t Projection::get_z_near() const {
}
Vector2 Projection::get_viewport_half_extents() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
///////--- Near Plane ---///////
Plane near_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
@@ -454,7 +454,7 @@ Vector2 Projection::get_viewport_half_extents() const {
}
Vector2 Projection::get_far_plane_half_extents() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
///////--- Far Plane ---///////
Plane far_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
@@ -496,7 +496,10 @@ bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8point
for (int i = 0; i < 8; i++) {
Vector3 point;
- bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]], planes[intersections[i][2]], &point);
+ Plane a = planes[intersections[i][0]];
+ Plane b = planes[intersections[i][1]];
+ Plane c = planes[intersections[i][2]];
+ bool res = a.intersect_3(b, c, &point);
ERR_FAIL_COND_V(!res, false);
p_8points[i] = p_transform.xform(point);
}
@@ -514,7 +517,7 @@ Vector<Plane> Projection::get_projection_planes(const Transform3D &p_transform)
Vector<Plane> planes;
planes.resize(6);
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane;
@@ -601,15 +604,15 @@ void Projection::invert() {
real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
- pvt_val = matrix[k][k]; /** Initialize for search **/
+ pvt_val = columns[k][k]; /** Initialize for search **/
pvt_i[k] = k;
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
- if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
+ if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
- pvt_val = matrix[i][j];
+ pvt_val = columns[i][j];
}
}
}
@@ -624,9 +627,9 @@ void Projection::invert() {
i = pvt_i[k];
if (i != k) { /** If rows are different **/
for (j = 0; j < 4; j++) {
- hold = -matrix[k][j];
- matrix[k][j] = matrix[i][j];
- matrix[i][j] = hold;
+ hold = -columns[k][j];
+ columns[k][j] = columns[i][j];
+ columns[i][j] = hold;
}
}
@@ -634,25 +637,25 @@ void Projection::invert() {
j = pvt_j[k];
if (j != k) { /** If columns are different **/
for (i = 0; i < 4; i++) {
- hold = -matrix[i][k];
- matrix[i][k] = matrix[i][j];
- matrix[i][j] = hold;
+ hold = -columns[i][k];
+ columns[i][k] = columns[i][j];
+ columns[i][j] = hold;
}
}
/** Divide column by minus pivot value **/
for (i = 0; i < 4; i++) {
if (i != k) {
- matrix[i][k] /= (-pvt_val);
+ columns[i][k] /= (-pvt_val);
}
}
/** Reduce the matrix **/
for (i = 0; i < 4; i++) {
- hold = matrix[i][k];
+ hold = columns[i][k];
for (j = 0; j < 4; j++) {
if (i != k && j != k) {
- matrix[i][j] += hold * matrix[k][j];
+ columns[i][j] += hold * columns[k][j];
}
}
}
@@ -660,12 +663,12 @@ void Projection::invert() {
/** Divide row by pivot **/
for (j = 0; j < 4; j++) {
if (j != k) {
- matrix[k][j] /= pvt_val;
+ columns[k][j] /= pvt_val;
}
}
/** Replace pivot by reciprocal (at last we can touch it). **/
- matrix[k][k] = 1.0 / pvt_val;
+ columns[k][k] = 1.0 / pvt_val;
}
/* That was most of the work, one final pass of row/column interchange */
@@ -674,18 +677,18 @@ void Projection::invert() {
i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
if (i != k) { /* If rows are different */
for (j = 0; j < 4; j++) {
- hold = matrix[k][j];
- matrix[k][j] = -matrix[i][j];
- matrix[i][j] = hold;
+ hold = columns[k][j];
+ columns[k][j] = -columns[i][j];
+ columns[i][j] = hold;
}
}
j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
if (j != k) { /* If columns are different */
for (i = 0; i < 4; i++) {
- hold = matrix[i][k];
- matrix[i][k] = -matrix[i][j];
- matrix[i][j] = hold;
+ hold = columns[i][k];
+ columns[i][k] = -columns[i][j];
+ columns[i][j] = hold;
}
}
}
@@ -693,7 +696,7 @@ void Projection::invert() {
void Projection::flip_y() {
for (int i = 0; i < 4; i++) {
- matrix[1][i] = -matrix[1][i];
+ columns[1][i] = -columns[1][i];
}
}
@@ -708,9 +711,9 @@ Projection Projection::operator*(const Projection &p_matrix) const {
for (int i = 0; i < 4; i++) {
real_t ab = 0;
for (int k = 0; k < 4; k++) {
- ab += matrix[k][i] * p_matrix.matrix[j][k];
+ ab += columns[k][i] * p_matrix.columns[j][k];
}
- new_matrix.matrix[j][i] = ab;
+ new_matrix.columns[j][i] = ab;
}
}
@@ -718,7 +721,7 @@ Projection Projection::operator*(const Projection &p_matrix) const {
}
void Projection::set_depth_correction(bool p_flip_y) {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = 1;
m[1] = 0.0;
@@ -739,7 +742,7 @@ void Projection::set_depth_correction(bool p_flip_y) {
}
void Projection::set_light_bias() {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = 0.5;
m[1] = 0.0;
@@ -760,7 +763,7 @@ void Projection::set_light_bias() {
}
void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = p_rect.size.width;
m[1] = 0.0;
@@ -784,7 +787,7 @@ Projection::operator String() const {
String str;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- str += String((j > 0) ? ", " : "\n") + rtos(matrix[i][j]);
+ str += String((j > 0) ? ", " : "\n") + rtos(columns[i][j]);
}
}
@@ -803,11 +806,11 @@ int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
}
bool Projection::is_orthogonal() const {
- return matrix[3][3] == 1.0;
+ return columns[3][3] == 1.0;
}
real_t Projection::get_fov() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane right_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
@@ -838,48 +841,49 @@ float Projection::get_lod_multiplier() const {
return 1.0 / (zn / width);
}
- //usage is lod_size / (lod_distance * multiplier) < threshold
+ // Usage is lod_size / (lod_distance * multiplier) < threshold
}
+
void Projection::make_scale(const Vector3 &p_scale) {
set_identity();
- matrix[0][0] = p_scale.x;
- matrix[1][1] = p_scale.y;
- matrix[2][2] = p_scale.z;
+ columns[0][0] = p_scale.x;
+ columns[1][1] = p_scale.y;
+ columns[2][2] = p_scale.z;
}
void Projection::scale_translate_to_fit(const AABB &p_aabb) {
Vector3 min = p_aabb.position;
Vector3 max = p_aabb.position + p_aabb.size;
- matrix[0][0] = 2 / (max.x - min.x);
- matrix[1][0] = 0;
- matrix[2][0] = 0;
- matrix[3][0] = -(max.x + min.x) / (max.x - min.x);
+ columns[0][0] = 2 / (max.x - min.x);
+ columns[1][0] = 0;
+ columns[2][0] = 0;
+ columns[3][0] = -(max.x + min.x) / (max.x - min.x);
- matrix[0][1] = 0;
- matrix[1][1] = 2 / (max.y - min.y);
- matrix[2][1] = 0;
- matrix[3][1] = -(max.y + min.y) / (max.y - min.y);
+ columns[0][1] = 0;
+ columns[1][1] = 2 / (max.y - min.y);
+ columns[2][1] = 0;
+ columns[3][1] = -(max.y + min.y) / (max.y - min.y);
- matrix[0][2] = 0;
- matrix[1][2] = 0;
- matrix[2][2] = 2 / (max.z - min.z);
- matrix[3][2] = -(max.z + min.z) / (max.z - min.z);
+ columns[0][2] = 0;
+ columns[1][2] = 0;
+ columns[2][2] = 2 / (max.z - min.z);
+ columns[3][2] = -(max.z + min.z) / (max.z - min.z);
- matrix[0][3] = 0;
- matrix[1][3] = 0;
- matrix[2][3] = 0;
- matrix[3][3] = 1;
+ columns[0][3] = 0;
+ columns[1][3] = 0;
+ columns[2][3] = 0;
+ columns[3][3] = 1;
}
void Projection::add_jitter_offset(const Vector2 &p_offset) {
- matrix[3][0] += p_offset.x;
- matrix[3][1] += p_offset.y;
+ columns[3][0] += p_offset.x;
+ columns[3][1] += p_offset.y;
}
Projection::operator Transform3D() const {
Transform3D tr;
- const real_t *m = &matrix[0][0];
+ const real_t *m = &columns[0][0];
tr.basis.rows[0][0] = m[0];
tr.basis.rows[1][0] = m[1];
@@ -899,15 +903,17 @@ Projection::operator Transform3D() const {
return tr;
}
+
Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) {
- matrix[0] = p_x;
- matrix[1] = p_y;
- matrix[2] = p_z;
- matrix[3] = p_w;
+ columns[0] = p_x;
+ columns[1] = p_y;
+ columns[2] = p_z;
+ columns[3] = p_w;
}
+
Projection::Projection(const Transform3D &p_transform) {
const Transform3D &tr = p_transform;
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = tr.basis.rows[0][0];
m[1] = tr.basis.rows[1][0];
diff --git a/core/math/projection.h b/core/math/projection.h
index f149d307b3..38fb9781ae 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -31,10 +31,11 @@
#ifndef PROJECTION_H
#define PROJECTION_H
-#include "core/math/math_defs.h"
#include "core/math/vector3.h"
#include "core/math/vector4.h"
-#include "core/templates/vector.h"
+
+template <class T>
+class Vector;
struct AABB;
struct Plane;
@@ -42,7 +43,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
-struct Projection {
+struct _NO_DISCARD_ Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
@@ -52,16 +53,16 @@ struct Projection {
PLANE_BOTTOM
};
- Vector4 matrix[4];
+ Vector4 columns[4];
_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 4);
- return matrix[p_axis];
+ return columns[p_axis];
}
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
- return matrix[p_axis];
+ return columns[p_axis];
}
float determinant() const;
@@ -135,7 +136,7 @@ struct Projection {
bool operator==(const Projection &p_cam) const {
for (uint32_t i = 0; i < 4; i++) {
for (uint32_t j = 0; j < 4; j++) {
- if (matrix[i][j] != p_cam.matrix[i][j]) {
+ if (columns[i][j] != p_cam.columns[i][j]) {
return false;
}
}
@@ -157,10 +158,10 @@ struct Projection {
Vector3 Projection::xform(const Vector3 &p_vec3) const {
Vector3 ret;
- ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
- ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
- ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
- real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
+ ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0];
+ ret.y = columns[0][1] * p_vec3.x + columns[1][1] * p_vec3.y + columns[2][1] * p_vec3.z + columns[3][1];
+ ret.z = columns[0][2] * p_vec3.x + columns[1][2] * p_vec3.y + columns[2][2] * p_vec3.z + columns[3][2];
+ real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3];
return ret / w;
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index c836a82e37..79a4e62b56 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -31,7 +31,7 @@
#include "quaternion.h"
#include "core/math/basis.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
@@ -79,6 +79,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
+bool Quaternion::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
@@ -326,7 +330,7 @@ Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
// (ax, ay, az), where ax is the angle of rotation around x axis,
// and similar for other axes.
// This implementation uses YXZ convention (Z is the first rotation).
-Quaternion::Quaternion(const Vector3 &p_euler) {
+Quaternion Quaternion::from_euler(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5f;
real_t half_a2 = p_euler.x * 0.5f;
real_t half_a3 = p_euler.z * 0.5f;
@@ -342,8 +346,9 @@ Quaternion::Quaternion(const Vector3 &p_euler) {
real_t cos_a3 = Math::cos(half_a3);
real_t sin_a3 = Math::sin(half_a3);
- x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
- y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
- z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
- w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+ return Quaternion(
+ sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3,
+ sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3,
+ -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3,
+ sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 43d7bffcfc..7497f1643e 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -31,10 +31,10 @@
#ifndef QUATERNION_H
#define QUATERNION_H
-#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "core/math/vector3.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Quaternion {
union {
@@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -68,6 +69,7 @@ struct _NO_DISCARD_ Quaternion {
Vector3 get_euler_xyz() const;
Vector3 get_euler_yxz() const;
Vector3 get_euler() const { return get_euler_yxz(); };
+ static Quaternion from_euler(const Vector3 &p_euler);
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
@@ -127,8 +129,6 @@ struct _NO_DISCARD_ Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
- Quaternion(const Vector3 &p_euler);
-
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -143,8 +143,7 @@ struct _NO_DISCARD_ Quaternion {
w = p_q.w;
}
- Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc
- {
+ Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index c7727a44a1..c194e1cc21 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -369,7 +369,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
Geometry3D::MeshData::Face &f = E->get();
- for (int i = 0; i < f.indices.size(); i++) {
+ for (uint32_t i = 0; i < f.indices.size(); i++) {
int a = E->get().indices[i];
int b = E->get().indices[(i + 1) % f.indices.size()];
Edge e(a, b);
@@ -436,17 +436,24 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
r_mesh.faces.clear();
r_mesh.faces.resize(ret_faces.size());
+ HashMap<List<Geometry3D::MeshData::Face>::Element *, int> face_indices;
+
int idx = 0;
- for (const Geometry3D::MeshData::Face &E : ret_faces) {
- r_mesh.faces.write[idx++] = E;
+ for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
+ face_indices[E] = idx;
+ r_mesh.faces[idx++] = E->get();
}
r_mesh.edges.resize(ret_edges.size());
idx = 0;
for (const KeyValue<Edge, RetFaceConnect> &E : ret_edges) {
Geometry3D::MeshData::Edge e;
- e.a = E.key.vertices[0];
- e.b = E.key.vertices[1];
- r_mesh.edges.write[idx++] = e;
+ e.vertex_a = E.key.vertices[0];
+ e.vertex_b = E.key.vertices[1];
+ ERR_CONTINUE(!face_indices.has(E.value.left));
+ ERR_CONTINUE(!face_indices.has(E.value.right));
+ e.face_a = face_indices[E.value.left];
+ e.face_b = face_indices[E.value.right];
+ r_mesh.edges[idx++] = e;
}
r_mesh.vertices = p_points;
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 9352bae0a6..bf67154cd6 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -57,7 +57,7 @@ public:
_FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
_FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
- RandomNumberGenerator() {}
+ RandomNumberGenerator() { randbase.randomize(); }
};
#endif // RANDOM_NUMBER_GENERATOR_H
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 9e78ead816..facf4eb3c4 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -38,6 +38,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
+bool Rect2::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 2d1be3d4f3..9863405d8e 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -178,7 +178,7 @@ struct _NO_DISCARD_ Rect2 {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
@@ -207,6 +207,7 @@ struct _NO_DISCARD_ Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
+ bool is_finite() const;
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
@@ -253,7 +254,7 @@ struct _NO_DISCARD_ Rect2 {
return r;
}
- inline void expand_to(const Vector2 &p_vector) { //in place function for speed
+ inline void expand_to(const Vector2 &p_vector) { // In place function for speed.
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
@@ -281,7 +282,7 @@ struct _NO_DISCARD_ Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
- return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
+ return Rect2(Point2(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0)), size.abs());
}
Vector2 get_support(const Vector2 &p_normal) const {
@@ -311,7 +312,7 @@ struct _NO_DISCARD_ Rect2 {
continue;
}
- //check inside
+ // Check inside.
Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
@@ -320,7 +321,7 @@ struct _NO_DISCARD_ Rect2 {
side_minus++;
}
- //check ray box
+ // Check ray box.
r /= l;
Vector2 ir(1.0f / r.x, 1.0f / r.y);
@@ -341,7 +342,7 @@ struct _NO_DISCARD_ Rect2 {
}
if (side_plus * side_minus == 0) {
- return true; //all inside
+ return true; // All inside.
} else {
return false;
}
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index 2b58dcdd98..c92f2cae02 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -121,7 +121,7 @@ struct _NO_DISCARD_ Rect2i {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 226076029b..548a82d254 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -168,6 +168,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
+bool Transform2D::is_finite() const {
+ return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
+}
+
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);
@@ -282,7 +286,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const
real_t dot = v1.dot(v2);
- dot = CLAMP(dot, -1.0f, 1.0f);
+ dot = CLAMP(dot, (real_t)-1.0, (real_t)1.0);
Vector2 v;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index f23f32867a..2b11f36535 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -98,6 +98,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
+ bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index 2de9e81b38..3285cbd664 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -31,7 +31,7 @@
#include "transform_3d.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
void Transform3D::affine_invert() {
basis.invert();
@@ -174,6 +174,10 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
+bool Transform3D::is_finite() const {
+ return basis.is_finite() && origin.is_finite();
+}
+
bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index c62e4a7b0e..cb347aa1c1 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -34,6 +34,7 @@
#include "core/math/aabb.h"
#include "core/math/basis.h"
#include "core/math/plane.h"
+#include "core/templates/vector.h"
struct _NO_DISCARD_ Transform3D {
Basis basis;
@@ -74,6 +75,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
+ bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 4433559e6d..6515c55a85 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -215,10 +215,8 @@ Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const {
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects(p_aabb);
- if (!valid) {
+ if (!b.aabb.intersects(p_aabb)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -302,12 +300,8 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_segment(p_begin, p_end);
- //bool valid = b.aabb.intersects(ray_aabb);
-
- if (!valid) {
+ if (!b.aabb.intersects_segment(p_begin, p_end)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -407,10 +401,8 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_ray(p_begin, p_dir);
- if (!valid) {
+ if (!b.aabb.intersects_ray(p_begin, p_dir)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -508,10 +500,8 @@ bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_cou
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count);
- if (!valid) {
+ if (!b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 56dbba393a..5366587126 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -186,6 +186,10 @@ bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y);
}
+bool Vector2::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 75364f72f0..5775d8e735 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -121,6 +121,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 55ba509144..b106200c4a 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -139,6 +139,10 @@ bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
}
+bool Vector3::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 62e810fb4d..19771eb312 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -136,6 +136,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
/* Operators */
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 55e51834df..3b189f7ed4 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -30,8 +30,7 @@
#include "vector4.h"
-#include "core/math/basis.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
Vector4::Axis Vector4::min_axis_index() const {
uint32_t min_index = 0;
@@ -65,6 +64,10 @@ bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
}
+bool Vector4::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
diff --git a/core/math/vector4.h b/core/math/vector4.h
index 426c473e13..7c4bdc1788 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -31,10 +31,10 @@
#ifndef VECTOR4_H
#define VECTOR4_H
-#include "core/math/math_defs.h"
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
-#include "core/math/vector3.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Vector4 {
static const int AXIS_COUNT = 4;
@@ -71,6 +71,7 @@ struct _NO_DISCARD_ Vector4 {
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 99b20560da..41585943b3 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -1528,7 +1528,10 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
c.native_extension = p_extension;
c.name = p_extension->class_name;
- c.creation_func = parent->creation_func;
+ c.is_virtual = p_extension->is_virtual;
+ if (!p_extension->is_abstract) {
+ c.creation_func = parent->creation_func;
+ }
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
@@ -1538,7 +1541,11 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
}
void ClassDB::unregister_extension_class(const StringName &p_class) {
- ERR_FAIL_COND(!classes.has(p_class));
+ ClassInfo *c = classes.getptr(p_class);
+ ERR_FAIL_COND_MSG(!c, "Class " + p_class + "does not exist");
+ for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
+ memdelete(F.value);
+ }
classes.erase(p_class);
}
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 0edc7a90c2..5381c596ce 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,9 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = _gen_argument_type_info(p_argument);
#ifdef DEBUG_METHODS_ENABLED
- info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ if (info.name.is_empty()) {
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ }
#endif
return info;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index 0d3e40f709..598e8a224d 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -292,11 +292,6 @@ class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -304,9 +299,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -367,11 +359,6 @@ class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -379,9 +366,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -444,11 +428,6 @@ class MethodBindTR : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -466,9 +445,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -531,11 +507,6 @@ class MethodBindTRC : public MethodBind {
(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -553,9 +524,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -615,11 +583,6 @@ class MethodBindTS : public MethodBind {
void (*function)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -627,9 +590,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -678,11 +638,6 @@ class MethodBindTRS : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -690,9 +645,6 @@ protected:
return GetTypeInfo<R>::VARIANT_TYPE;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
diff --git a/core/object/object.cpp b/core/object/object.cpp
index c275164b14..540b9a8f19 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -1468,8 +1468,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
- ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind);
- ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);
+ ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
+ ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
@@ -1856,6 +1856,46 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0) {
+ if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
+ List<MethodInfo> signals;
+ get_signal_list(&signals);
+ for (const MethodInfo &E : signals) {
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
+ List<MethodInfo> methods;
+ get_method_list(&methods);
+ for (const MethodInfo &E : methods) {
+ if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
+ continue;
+ }
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
+ List<PropertyInfo> properties;
+ get_property_list(&properties);
+ for (const PropertyInfo &E : properties) {
+ if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
+ r_options->push_back(E.name.quote());
+ }
+ }
+ } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ r_options->push_back(String(K.key).quote());
+ }
+ }
+ } else if (p_idx == 2) {
+ if (p_function == "connect") {
+ // Ideally, the constants should be inferred by the parameter.
+ // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
+ List<StringName> constants;
+ ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
+ for (const StringName &E : constants) {
+ r_options->push_back(String(E));
+ }
+ }
+ }
}
SpinLock ObjectDB::spin_lock;
diff --git a/core/object/object.h b/core/object/object.h
index 8ade5a204a..8c647cda40 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -50,7 +50,7 @@ class TypedArray;
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
@@ -89,8 +89,8 @@ enum PropertyHint {
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_INT_IS_OBJECTID,
- PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
+ PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
@@ -133,7 +133,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_ARRAY = 1 << 29, // Used in the inspector to group properties as elements of an array.
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR,
- PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNATIONALIZED,
+ PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNATIONALIZED,
PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE,
};
@@ -295,6 +295,8 @@ struct ObjectNativeExtension {
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
+ bool is_virtual = false;
+ bool is_abstract = false;
GDNativeExtensionClassSet set;
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
@@ -733,34 +735,12 @@ public:
template <class T>
static T *cast_to(Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
template <class T>
static const T *cast_to(const Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<const T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<const T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
enum {
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index e56d2e80b9..056c57a5f1 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -106,23 +106,23 @@ Dictionary Script::_get_script_constant_map() {
PropertyInfo Script::get_class_category() const {
String path = get_path();
- String name;
+ String scr_name;
if (is_built_in()) {
if (get_name().is_empty()) {
- name = TTR("Built-in script");
+ scr_name = TTR("Built-in script");
} else {
- name = vformat("%s (%s)", get_name(), TTR("Built-in"));
+ scr_name = vformat("%s (%s)", get_name(), TTR("Built-in"));
}
} else {
if (get_name().is_empty()) {
- name = path.get_file();
+ scr_name = path.get_file();
} else {
- name = get_name();
+ scr_name = get_name();
}
}
- return PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
+ return PropertyInfo(Variant::NIL, scr_name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
}
#endif // TOOLS_ENABLED
@@ -166,6 +166,7 @@ ScriptLanguage *ScriptServer::get_language(int p_idx) {
}
void ScriptServer::register_language(ScriptLanguage *p_language) {
+ ERR_FAIL_NULL(p_language);
ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
_languages[_language_count++] = p_language;
}
@@ -183,10 +184,10 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
}
void ScriptServer::init_languages() {
- { //load global classes
+ { // Load global classes.
global_classes_clear();
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+ Array script_classes = GLOBAL_GET("_global_script_classes");
for (int i = 0; i < script_classes.size(); i++) {
Dictionary c = script_classes[i];
@@ -304,7 +305,7 @@ void ScriptServer::save_global_classes() {
Array old;
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ old = GLOBAL_GET("_global_script_classes");
}
if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
return;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 7e74f6a2be..c32fb9d85b 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -82,9 +82,10 @@ public:
GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
Vector<DocData::ClassDoc> class_doc;
-#ifndef _MSC_VER
-#warning missing conversion from documentation to ClassDoc
-#endif
+ for (int i = 0; i < doc.size(); i++) {
+ class_doc.append(DocData::ClassDoc::from_dict(doc[i]));
+ }
+
return class_doc;
}
#endif // TOOLS_ENABLED
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index a96e1989f9..c0504a174c 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -65,21 +65,15 @@ void MainLoop::initialize() {
}
bool MainLoop::physics_process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_physics_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_physics_process, p_time, quit);
+ return quit;
}
bool MainLoop::process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_process, p_time, quit);
+ return quit;
}
void MainLoop::finalize() {
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 410b62068a..79eef95ef2 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -86,11 +86,6 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
if (length >= 2 + param_position) {
event->set_pitch(data[param_position]);
event->set_velocity(data[param_position + 1]);
-
- if (event->get_message() == MIDIMessage::NOTE_ON && event->get_velocity() == 0) {
- // https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on
- event->set_message(MIDIMessage::NOTE_OFF);
- }
}
break;
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 2bdede889f..bbb2a94fe7 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -38,6 +38,7 @@
#include "core/version_generated.gen.h"
#include <stdarg.h>
+#include <thread>
OS *OS::singleton = nullptr;
uint64_t OS::target_ticks = 0;
@@ -321,7 +322,7 @@ String OS::get_unique_id() const {
}
int OS::get_processor_count() const {
- return 1;
+ return std::thread::hardware_concurrency();
}
String OS::get_processor_name() const {
@@ -511,10 +512,10 @@ void OS::add_frame_delay(bool p_can_draw) {
if (is_in_low_processor_usage_mode() || !p_can_draw) {
dynamic_delay = get_low_processor_usage_mode_sleep_usec();
}
- const int target_fps = Engine::get_singleton()->get_target_fps();
- if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
+ const int max_fps = Engine::get_singleton()->get_max_fps();
+ if (max_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
// Override the low processor usage mode sleep delay if the target FPS is lower.
- dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps));
+ dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / max_fps));
}
if (dynamic_delay > 0) {
diff --git a/core/os/os.h b/core/os/os.h
index 1a5e45968d..af7b40f3ec 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -123,6 +123,8 @@ public:
int get_display_driver_id() const { return _display_driver_id; }
+ virtual Vector<String> get_video_adapter_driver_info() const = 0;
+
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);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index e8ebb4597f..712f4793eb 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -36,10 +36,7 @@
#include "core/object/script_language.h"
#include "core/templates/safe_refcount.h"
-Error (*Thread::set_name_func)(const String &) = nullptr;
-void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
-void (*Thread::init_func)() = nullptr;
-void (*Thread::term_func)() = nullptr;
+Thread::PlatformFunctions Thread::platform_functions;
uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
static std::hash<std::thread::id> hasher;
@@ -49,30 +46,27 @@ uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id());
thread_local Thread::ID Thread::caller_id = 0;
-void Thread::_set_platform_funcs(
- Error (*p_set_name_func)(const String &),
- void (*p_set_priority_func)(Thread::Priority),
- void (*p_init_func)(),
- void (*p_term_func)()) {
- Thread::set_name_func = p_set_name_func;
- Thread::set_priority_func = p_set_priority_func;
- Thread::init_func = p_init_func;
- Thread::term_func = p_term_func;
+void Thread::_set_platform_functions(const PlatformFunctions &p_functions) {
+ platform_functions = p_functions;
}
void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) {
Thread::caller_id = _thread_id_hash(p_self->thread.get_id());
- if (set_priority_func) {
- set_priority_func(p_settings.priority);
+ if (platform_functions.set_priority) {
+ platform_functions.set_priority(p_settings.priority);
}
- if (init_func) {
- init_func();
+ if (platform_functions.init) {
+ platform_functions.init();
+ }
+ ScriptServer::thread_enter(); // Scripts may need to attach a stack.
+ if (platform_functions.wrapper) {
+ platform_functions.wrapper(p_callback, p_userdata);
+ } else {
+ p_callback(p_userdata);
}
- ScriptServer::thread_enter(); //scripts may need to attach a stack
- p_callback(p_userdata);
ScriptServer::thread_exit();
- if (term_func) {
- term_func();
+ if (platform_functions.term) {
+ platform_functions.term();
}
}
@@ -105,8 +99,8 @@ void Thread::wait_to_finish() {
}
Error Thread::set_name(const String &p_name) {
- if (set_name_func) {
- return set_name_func(p_name);
+ if (platform_functions.set_name) {
+ return platform_functions.set_name(p_name);
}
return ERR_UNAVAILABLE;
diff --git a/core/os/thread.h b/core/os/thread.h
index 7462ec17fb..86442de760 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -63,6 +63,14 @@ public:
Settings() { priority = PRIORITY_NORMAL; }
};
+ struct PlatformFunctions {
+ Error (*set_name)(const String &) = nullptr;
+ void (*set_priority)(Thread::Priority) = nullptr;
+ void (*init)() = nullptr;
+ void (*wrapper)(Thread::Callback, void *) = nullptr;
+ void (*term)() = nullptr;
+ };
+
private:
friend class Main;
@@ -76,17 +84,10 @@ private:
static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata);
- static Error (*set_name_func)(const String &);
- static void (*set_priority_func)(Thread::Priority);
- static void (*init_func)();
- static void (*term_func)();
+ static PlatformFunctions platform_functions;
public:
- static void _set_platform_funcs(
- Error (*p_set_name_func)(const String &),
- void (*p_set_priority_func)(Thread::Priority),
- void (*p_init_func)() = nullptr,
- void (*p_term_func)() = nullptr);
+ static void _set_platform_functions(const PlatformFunctions &p_functions);
_FORCE_INLINE_ ID get_id() const { return id; }
// get the ID of the caller thread
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index 07302cc8c3..b130c2fc79 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -179,14 +179,14 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
}
bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name.operator String();
- if (name == "hash_table") {
+ String prop_name = p_name.operator String();
+ if (prop_name == "hash_table") {
hash_table = p_value;
- } else if (name == "bucket_table") {
+ } else if (prop_name == "bucket_table") {
bucket_table = p_value;
- } else if (name == "strings") {
+ } else if (prop_name == "strings") {
strings = p_value;
- } else if (name == "load_from") {
+ } else if (prop_name == "load_from") {
generate(p_value);
} else {
return false;
@@ -196,12 +196,12 @@ bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value
}
bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name.operator String();
- if (name == "hash_table") {
+ String prop_name = p_name.operator String();
+ if (prop_name == "hash_table") {
r_ret = hash_table;
- } else if (name == "bucket_table") {
+ } else if (prop_name == "bucket_table") {
r_ret = bucket_table;
- } else if (name == "strings") {
+ } else if (prop_name == "strings") {
r_ret = strings;
} else {
return false;
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 4748f1a0cb..2bed3543dc 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -293,31 +293,35 @@ void TranslationServer::init_locale_info() {
}
String TranslationServer::standardize_locale(const String &p_locale) const {
+ return _standardize_locale(p_locale, false);
+}
+
+String TranslationServer::_standardize_locale(const String &p_locale, bool p_add_defaults) const {
// Replaces '-' with '_' for macOS style locales.
String univ_locale = p_locale.replace("-", "_");
// Extract locale elements.
- String lang, script, country, variant;
+ String lang_name, script_name, country_name, variant_name;
Vector<String> locale_elements = univ_locale.get_slice("@", 0).split("_");
- lang = locale_elements[0];
+ lang_name = locale_elements[0];
if (locale_elements.size() >= 2) {
if (locale_elements[1].length() == 4 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_lower_case(locale_elements[1][1]) && is_ascii_lower_case(locale_elements[1][2]) && is_ascii_lower_case(locale_elements[1][3])) {
- script = locale_elements[1];
+ script_name = locale_elements[1];
}
if (locale_elements[1].length() == 2 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_upper_case(locale_elements[1][1])) {
- country = locale_elements[1];
+ country_name = locale_elements[1];
}
}
if (locale_elements.size() >= 3) {
if (locale_elements[2].length() == 2 && is_ascii_upper_case(locale_elements[2][0]) && is_ascii_upper_case(locale_elements[2][1])) {
- country = locale_elements[2];
- } else if (variant_map.has(locale_elements[2].to_lower()) && variant_map[locale_elements[2].to_lower()] == lang) {
- variant = locale_elements[2].to_lower();
+ country_name = locale_elements[2];
+ } else if (variant_map.has(locale_elements[2].to_lower()) && variant_map[locale_elements[2].to_lower()] == lang_name) {
+ variant_name = locale_elements[2].to_lower();
}
}
if (locale_elements.size() >= 4) {
- if (variant_map.has(locale_elements[3].to_lower()) && variant_map[locale_elements[3].to_lower()] == lang) {
- variant = locale_elements[3].to_lower();
+ if (variant_map.has(locale_elements[3].to_lower()) && variant_map[locale_elements[3].to_lower()] == lang_name) {
+ variant_name = locale_elements[3].to_lower();
}
}
@@ -325,74 +329,76 @@ String TranslationServer::standardize_locale(const String &p_locale) const {
Vector<String> script_extra = univ_locale.get_slice("@", 1).split(";");
for (int i = 0; i < script_extra.size(); i++) {
if (script_extra[i].to_lower() == "cyrillic") {
- script = "Cyrl";
+ script_name = "Cyrl";
break;
} else if (script_extra[i].to_lower() == "latin") {
- script = "Latn";
+ script_name = "Latn";
break;
} else if (script_extra[i].to_lower() == "devanagari") {
- script = "Deva";
+ script_name = "Deva";
break;
- } else if (variant_map.has(script_extra[i].to_lower()) && variant_map[script_extra[i].to_lower()] == lang) {
- variant = script_extra[i].to_lower();
+ } else if (variant_map.has(script_extra[i].to_lower()) && variant_map[script_extra[i].to_lower()] == lang_name) {
+ variant_name = script_extra[i].to_lower();
}
}
// Handles known non-ISO language names used e.g. on Windows.
- if (locale_rename_map.has(lang)) {
- lang = locale_rename_map[lang];
+ if (locale_rename_map.has(lang_name)) {
+ lang_name = locale_rename_map[lang_name];
}
// Handle country renames.
- if (country_rename_map.has(country)) {
- country = country_rename_map[country];
+ if (country_rename_map.has(country_name)) {
+ country_name = country_rename_map[country_name];
}
// Remove unsupported script codes.
- if (!script_map.has(script)) {
- script = "";
+ if (!script_map.has(script_name)) {
+ script_name = "";
}
// Add script code base on language and country codes for some ambiguous cases.
- if (script.is_empty()) {
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang) {
- if (country.is_empty() || info.supported_countries.has(country)) {
- script = info.script;
- break;
+ if (p_add_defaults) {
+ if (script_name.is_empty()) {
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name) {
+ if (country_name.is_empty() || info.supported_countries.has(country_name)) {
+ script_name = info.script;
+ break;
+ }
}
}
}
- }
- if (!script.is_empty() && country.is_empty()) {
- // Add conntry code based on script for some ambiguous cases.
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang && info.script == script) {
- country = info.default_country;
- break;
+ if (!script_name.is_empty() && country_name.is_empty()) {
+ // Add conntry code based on script for some ambiguous cases.
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name && info.script == script_name) {
+ country_name = info.default_country;
+ break;
+ }
}
}
}
// Combine results.
- String locale = lang;
- if (!script.is_empty()) {
- locale = locale + "_" + script;
+ String out = lang_name;
+ if (!script_name.is_empty()) {
+ out = out + "_" + script_name;
}
- if (!country.is_empty()) {
- locale = locale + "_" + country;
+ if (!country_name.is_empty()) {
+ out = out + "_" + country_name;
}
- if (!variant.is_empty()) {
- locale = locale + "_" + variant;
+ if (!variant_name.is_empty()) {
+ out = out + "_" + variant_name;
}
- return locale;
+ return out;
}
int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const {
- String locale_a = standardize_locale(p_locale_a);
- String locale_b = standardize_locale(p_locale_b);
+ String locale_a = _standardize_locale(p_locale_a, true);
+ String locale_b = _standardize_locale(p_locale_b, true);
if (locale_a == locale_b) {
// Exact match.
@@ -420,31 +426,29 @@ int TranslationServer::compare_locales(const String &p_locale_a, const String &p
}
String TranslationServer::get_locale_name(const String &p_locale) const {
- String locale = standardize_locale(p_locale);
-
- String lang, script, country;
- Vector<String> locale_elements = locale.split("_");
- lang = locale_elements[0];
+ String lang_name, script_name, country_name;
+ Vector<String> locale_elements = standardize_locale(p_locale).split("_");
+ lang_name = locale_elements[0];
if (locale_elements.size() >= 2) {
if (locale_elements[1].length() == 4 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_lower_case(locale_elements[1][1]) && is_ascii_lower_case(locale_elements[1][2]) && is_ascii_lower_case(locale_elements[1][3])) {
- script = locale_elements[1];
+ script_name = locale_elements[1];
}
if (locale_elements[1].length() == 2 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_upper_case(locale_elements[1][1])) {
- country = locale_elements[1];
+ country_name = locale_elements[1];
}
}
if (locale_elements.size() >= 3) {
if (locale_elements[2].length() == 2 && is_ascii_upper_case(locale_elements[2][0]) && is_ascii_upper_case(locale_elements[2][1])) {
- country = locale_elements[2];
+ country_name = locale_elements[2];
}
}
- String name = language_map[lang];
- if (!script.is_empty()) {
- name = name + " (" + script_map[script] + ")";
+ String name = language_map[lang_name];
+ if (!script_name.is_empty()) {
+ name = name + " (" + script_map[script_name] + ")";
}
- if (!country.is_empty()) {
- name = name + ", " + country_name_map[country];
+ if (!country_name.is_empty()) {
+ name = name + ", " + country_name_map[country_name];
}
return name;
}
@@ -630,12 +634,12 @@ TranslationServer *TranslationServer::singleton = nullptr;
bool TranslationServer::_load_translations(const String &p_from) {
if (ProjectSettings::get_singleton()->has_setting(p_from)) {
- Vector<String> translations = ProjectSettings::get_singleton()->get(p_from);
+ const Vector<String> &translation_names = GLOBAL_GET(p_from);
- int tcount = translations.size();
+ int tcount = translation_names.size();
if (tcount) {
- const String *r = translations.ptr();
+ const String *r = translation_names.ptr();
for (int i = 0; i < tcount; i++) {
Ref<Translation> tr = ResourceLoader::load(r[i]);
@@ -964,7 +968,6 @@ void TranslationServer::_bind_methods() {
}
void TranslationServer::load_translations() {
- String locale = get_locale();
_load_translations("internationalization/locale/translations"); //all
_load_translations("internationalization/locale/translations_" + locale.substr(0, 2));
diff --git a/core/string/translation.h b/core/string/translation.h
index 3f97a8d4fc..9a369b0b05 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -102,6 +102,7 @@ class TranslationServer : public Object {
static TranslationServer *singleton;
bool _load_translations(const String &p_from);
+ String _standardize_locale(const String &p_locale, bool p_add_defaults) const;
StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 6218c21cde..c86c8316fe 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1567,10 +1567,11 @@ String String::num_real(double p_num, bool p_trailing) {
#else
int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
+ // We want to align the digits to the above sane default, so we only need
+ // to subtract log10 for numbers with a positive power of ten magnitude.
+ double abs_num = Math::abs(p_num);
+ if (abs_num > 10) {
+ decimals -= (int)floor(log10(abs_num));
}
return num(p_num, decimals);
}
@@ -3667,29 +3668,43 @@ bool String::is_network_share_path() const {
String String::simplify_path() const {
String s = *this;
String drive;
- if (s.begins_with("local://")) {
- drive = "local://";
- s = s.substr(8, s.length());
- } else if (s.begins_with("res://")) {
- drive = "res://";
- s = s.substr(6, s.length());
- } else if (s.begins_with("user://")) {
- drive = "user://";
- s = s.substr(7, s.length());
- } else if (is_network_share_path()) {
- drive = s.substr(0, 2);
- s = s.substr(2, s.length() - 2);
- } else if (s.begins_with("/") || s.begins_with("\\")) {
- drive = s.substr(0, 1);
- s = s.substr(1, s.length() - 1);
- } else {
- int p = s.find(":/");
- if (p == -1) {
- p = s.find(":\\");
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = s.find("://");
+ bool found = false;
+ if (p > 0) {
+ bool only_chars = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(s[i])) {
+ only_chars = false;
+ break;
+ }
+ }
+ if (only_chars) {
+ found = true;
+ drive = s.substr(0, p + 3);
+ s = s.substr(p + 3);
}
- if (p != -1 && p < s.find("/")) {
- drive = s.substr(0, p + 2);
- s = s.substr(p + 2, s.length());
+ }
+ if (!found) {
+ if (is_network_share_path()) {
+ // Network path, beginning with // or \\.
+ drive = s.substr(0, 2);
+ s = s.substr(2);
+ } else if (s.begins_with("/") || s.begins_with("\\")) {
+ // Absolute path.
+ drive = s.substr(0, 1);
+ s = s.substr(1);
+ } else {
+ // Windows-style drive path, like C:/ or C:\.
+ p = s.find(":/");
+ if (p == -1) {
+ p = s.find(":\\");
+ }
+ if (p != -1 && p < s.find("/")) {
+ drive = s.substr(0, p + 2);
+ s = s.substr(p + 2);
+ }
}
}
@@ -4651,10 +4666,10 @@ String String::sprintf(const Array &values, bool *error) const {
double value = values[value_index];
bool is_negative = (value < 0);
String str = String::num(ABS(value), min_decimals);
- bool not_numeric = isinf(value) || isnan(value);
+ const bool is_finite = Math::is_finite(value);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
str = str.pad_decimals(min_decimals);
}
@@ -4662,7 +4677,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
} else {
@@ -4713,10 +4728,10 @@ String String::sprintf(const Array &values, bool *error) const {
for (int i = 0; i < count; i++) {
double val = vec[i];
String number_str = String::num(ABS(val), min_decimals);
- bool not_numeric = isinf(val) || isnan(val);
+ const bool is_finite = Math::is_finite(val);
// Pad decimals out.
- if (!not_numeric) {
+ if (is_finite) {
number_str = number_str.pad_decimals(min_decimals);
}
@@ -4724,7 +4739,7 @@ String String::sprintf(const Array &values, bool *error) const {
// Padding. Leave room for sign later if required.
int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
- String pad_char = (pad_with_zeros && !not_numeric) ? String("0") : String(" "); // Never pad NaN or inf with zeros
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
number_str = number_str.rpad(pad_chars_count, pad_char);
} else {
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index 320faebe98..a83ffa575f 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -335,15 +335,8 @@ public:
~RID_Alloc() {
if (alloc_count) {
- if (description) {
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + description + "' were leaked at exit.");
- } else {
-#ifdef NO_SAFE_CAST
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type 'unknown' were leaked at exit.");
-#else
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + typeid(T).name() + "' were leaked at exit.");
-#endif
- }
+ print_error(vformat("ERROR: %d RID allocations of type '%s' were leaked at exit.",
+ alloc_count, description ? description : typeid(T).name()));
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index c1bdd6a6bc..c6bbd43dc4 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -31,6 +31,7 @@
#include "array.h"
#include "container_type_validate.h"
+#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hashfuncs.h"
@@ -299,6 +300,11 @@ Variant Array::back() const {
return operator[](_p->array.size() - 1);
}
+Variant Array::pick_random() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](Math::rand() % _p->array.size());
+}
+
int Array::find(const Variant &p_value, int p_from) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
return _p->array.find(p_value, p_from);
@@ -402,6 +408,7 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array result;
+ result._p->typed = _p->typed;
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
@@ -433,6 +440,7 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array Array::filter(const Callable &p_callable) const {
Array new_arr;
new_arr.resize(size());
+ new_arr._p->typed = _p->typed;
int accepted_count = 0;
const Variant *argptrs[1];
diff --git a/core/variant/array.h b/core/variant/array.h
index 3d9a794969..ee265a9ffd 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -79,6 +79,7 @@ public:
Variant front() const;
Variant back() const;
+ Variant pick_random() const;
void sort();
void sort_custom(const Callable &p_callable);
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index b35e2f004b..79532d9aca 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -402,33 +402,33 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
}
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
- Object *object = get_object();
- ERR_FAIL_COND_V(!object, ERR_UNCONFIGURED);
+ Object *obj = get_object();
+ ERR_FAIL_COND_V(!obj, ERR_UNCONFIGURED);
- return object->connect(name, p_callable, p_flags);
+ return obj->connect(name, p_callable, p_flags);
}
void Signal::disconnect(const Callable &p_callable) {
- Object *object = get_object();
- ERR_FAIL_COND(!object);
- object->disconnect(name, p_callable);
+ Object *obj = get_object();
+ ERR_FAIL_COND(!obj);
+ obj->disconnect(name, p_callable);
}
bool Signal::is_connected(const Callable &p_callable) const {
- Object *object = get_object();
- ERR_FAIL_COND_V(!object, false);
+ Object *obj = get_object();
+ ERR_FAIL_COND_V(!obj, false);
- return object->is_connected(name, p_callable);
+ return obj->is_connected(name, p_callable);
}
Array Signal::get_connections() const {
- Object *object = get_object();
- if (!object) {
+ Object *obj = get_object();
+ if (!obj) {
return Array();
}
List<Object::Connection> connections;
- object->get_signal_connection_list(name, &connections);
+ obj->get_signal_connection_list(name, &connections);
Array arr;
for (const Object::Connection &E : connections) {
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 6171c8c88f..427a337aab 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -79,9 +79,12 @@ struct ContainerTypeValidate {
return true;
}
- ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
if (type != p_variant.get_type()) {
- return false;
+ if (p_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
+ return true;
+ }
+
+ ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
}
if (type != Variant::OBJECT) {
@@ -90,7 +93,7 @@ struct ContainerTypeValidate {
#ifdef DEBUG_ENABLED
ObjectID object_id = p_variant;
if (object_id == ObjectID()) {
- return true; //fine its null;
+ return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
@@ -101,7 +104,7 @@ struct ContainerTypeValidate {
}
#endif
if (class_name == StringName()) {
- return true; //all good, no class type requested
+ return true; // All good, no class type requested.
}
StringName obj_class = object->get_class_name();
@@ -110,12 +113,12 @@ struct ContainerTypeValidate {
}
if (script.is_null()) {
- return true; //all good
+ return true; // All good, no script requested.
}
Ref<Script> other_script = object->get_script();
- //check base script..
+ // Check base script..
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index f24ffeb1a9..b4528e67d1 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -47,146 +47,126 @@ String Variant::get_type_name(Variant::Type p_type) {
switch (p_type) {
case NIL: {
return "Nil";
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return "bool";
- } break;
+ }
case INT: {
return "int";
-
- } break;
+ }
case FLOAT: {
return "float";
-
- } break;
+ }
case STRING: {
return "String";
- } break;
+ }
- // math types
+ // Math types.
case VECTOR2: {
return "Vector2";
- } break;
+ }
case VECTOR2I: {
return "Vector2i";
- } break;
+ }
case RECT2: {
return "Rect2";
- } break;
+ }
case RECT2I: {
return "Rect2i";
- } break;
+ }
case TRANSFORM2D: {
return "Transform2D";
- } break;
+ }
case VECTOR3: {
return "Vector3";
- } break;
+ }
case VECTOR3I: {
return "Vector3i";
- } break;
+ }
case VECTOR4: {
return "Vector4";
- } break;
+ }
case VECTOR4I: {
return "Vector4i";
- } break;
+ }
case PLANE: {
return "Plane";
-
- } break;
+ }
case AABB: {
return "AABB";
- } break;
+ }
case QUATERNION: {
return "Quaternion";
-
- } break;
+ }
case BASIS: {
return "Basis";
-
- } break;
+ }
case TRANSFORM3D: {
return "Transform3D";
-
- } break;
+ }
case PROJECTION: {
return "Projection";
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return "Color";
-
- } break;
+ }
case RID: {
return "RID";
- } break;
+ }
case OBJECT: {
return "Object";
- } break;
+ }
case CALLABLE: {
return "Callable";
- } break;
+ }
case SIGNAL: {
return "Signal";
- } break;
+ }
case STRING_NAME: {
return "StringName";
-
- } break;
+ }
case NODE_PATH: {
return "NodePath";
-
- } break;
+ }
case DICTIONARY: {
return "Dictionary";
-
- } break;
+ }
case ARRAY: {
return "Array";
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return "PackedByteArray";
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return "PackedInt32Array";
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return "PackedInt64Array";
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return "PackedFloat32Array";
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return "PackedFloat64Array";
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return "PackedStringArray";
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return "PackedVector2Array";
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return "PackedVector3Array";
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return "PackedColorArray";
-
- } break;
+ }
default: {
}
}
@@ -880,157 +860,126 @@ bool Variant::is_zero() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return !(_data._bool);
- } break;
+ }
case INT: {
return _data._int == 0;
-
- } break;
+ }
case FLOAT: {
return _data._float == 0;
-
- } break;
+ }
case STRING: {
return *reinterpret_cast<const String *>(_data._mem) == String();
+ }
- } break;
-
- // math types
+ // Math types.
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2();
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i();
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2();
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i();
-
- } break;
+ }
case TRANSFORM2D: {
return *_data._transform2d == Transform2D();
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3();
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i();
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4();
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i();
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane();
-
- } break;
+ }
case AABB: {
return *_data._aabb == ::AABB();
- } break;
+ }
case QUATERNION: {
return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion();
-
- } break;
+ }
case BASIS: {
return *_data._basis == Basis();
-
- } break;
+ }
case TRANSFORM3D: {
return *_data._transform3d == Transform3D();
-
- } break;
+ }
case PROJECTION: {
return *_data._projection == Projection();
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color();
-
- } break;
+ }
case RID: {
return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID();
- } break;
+ }
case OBJECT: {
return _get_obj().obj == nullptr;
- } break;
+ }
case CALLABLE: {
return reinterpret_cast<const Callable *>(_data._mem)->is_null();
- } break;
+ }
case SIGNAL: {
return reinterpret_cast<const Signal *>(_data._mem)->is_null();
- } break;
+ }
case STRING_NAME: {
return *reinterpret_cast<const StringName *>(_data._mem) != StringName();
-
- } break;
+ }
case NODE_PATH: {
return reinterpret_cast<const NodePath *>(_data._mem)->is_empty();
-
- } break;
+ }
case DICTIONARY: {
return reinterpret_cast<const Dictionary *>(_data._mem)->is_empty();
-
- } break;
+ }
case ARRAY: {
return reinterpret_cast<const Array *>(_data._mem)->is_empty();
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return PackedArrayRef<uint8_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return PackedArrayRef<int32_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return PackedArrayRef<int64_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return PackedArrayRef<float>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return PackedArrayRef<double>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return PackedArrayRef<String>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return PackedArrayRef<Vector2>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return PackedArrayRef<Vector3>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return PackedArrayRef<Color>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
default: {
}
}
@@ -1042,67 +991,54 @@ bool Variant::is_one() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
case BOOL: {
return _data._bool;
- } break;
+ }
case INT: {
return _data._int == 1;
-
- } break;
+ }
case FLOAT: {
return _data._float == 1;
+ }
- } break;
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(1, 1);
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(1, 1);
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(1, 1, 1, 1);
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(1, 1, 1);
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(1, 1, 1);
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i(1, 1, 1, 1);
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane(1, 1, 1, 1);
+ }
- } break;
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color(1, 1, 1, 1);
-
- } break;
+ }
default: {
return !is_zero();
}
}
-
- return false;
}
bool Variant::is_null() const {
@@ -1135,10 +1071,10 @@ void Variant::reference(const Variant &p_variant) {
switch (p_variant.type) {
case NIL: {
- // none
+ // None.
} break;
- // atomic types
+ // Atomic types.
case BOOL: {
_data._bool = p_variant._data._bool;
} break;
@@ -1152,7 +1088,7 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem)));
} break;
- // math types
+ // Math types.
case VECTOR2: {
memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem)));
} break;
@@ -1204,10 +1140,9 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._projection, Projection(*p_variant._data._projection));
} break;
- // misc types
+ // Miscellaneous types.
case COLOR: {
memnew_placement(_data._mem, Color(*reinterpret_cast<const Color *>(p_variant._data._mem)));
-
} break;
case RID: {
memnew_placement(_data._mem, ::RID(*reinterpret_cast<const ::RID *>(p_variant._data._mem)));
@@ -1226,7 +1161,6 @@ void Variant::reference(const Variant &p_variant) {
_get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
_get_obj().id = p_variant._get_obj().id;
-
} break;
case CALLABLE: {
memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem)));
@@ -1236,84 +1170,71 @@ void Variant::reference(const Variant &p_variant) {
} break;
case STRING_NAME: {
memnew_placement(_data._mem, StringName(*reinterpret_cast<const StringName *>(p_variant._data._mem)));
-
} break;
case NODE_PATH: {
memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem)));
-
} break;
case DICTIONARY: {
memnew_placement(_data._mem, Dictionary(*reinterpret_cast<const Dictionary *>(p_variant._data._mem)));
-
} break;
case ARRAY: {
memnew_placement(_data._mem, Array(*reinterpret_cast<const Array *>(p_variant._data._mem)));
-
} break;
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<uint8_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<uint8_t>::create();
}
-
} break;
case PACKED_INT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int32_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int32_t>::create();
}
-
} break;
case PACKED_INT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int64_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int64_t>::create();
}
-
} break;
case PACKED_FLOAT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<float> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<float>::create();
}
-
} break;
case PACKED_FLOAT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<double> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<double>::create();
}
-
} break;
case PACKED_STRING_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<String> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<String>::create();
}
-
} break;
case PACKED_VECTOR2_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector2> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector2>::create();
}
-
} break;
case PACKED_VECTOR3_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector3> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector3>::create();
}
-
} break;
case PACKED_COLOR_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Color> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Color>::create();
}
-
} break;
default: {
}
@@ -1333,6 +1254,7 @@ void Variant::zero() {
case FLOAT:
this->_data._float = 0;
break;
+
case VECTOR2:
*reinterpret_cast<Vector2 *>(this->_data._mem) = Vector2();
break;
@@ -1363,9 +1285,11 @@ void Variant::zero() {
case QUATERNION:
*reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion();
break;
+
case COLOR:
*reinterpret_cast<Color *>(this->_data._mem) = Color();
break;
+
default:
this->clear();
break;
@@ -1377,15 +1301,8 @@ void Variant::_clear_internal() {
case STRING: {
reinterpret_cast<String *>(_data._mem)->~String();
} break;
- /*
- // no point, they don't allocate memory
- VECTOR3,
- PLANE,
- QUATERNION,
- COLOR,
- VECTOR2,
- RECT2
- */
+
+ // Math types.
case TRANSFORM2D: {
if (_data._transform2d) {
_data._transform2d->~Transform2D();
@@ -1421,7 +1338,8 @@ void Variant::_clear_internal() {
_data._projection = nullptr;
}
} break;
- // misc types
+
+ // Miscellaneous types.
case STRING_NAME: {
reinterpret_cast<StringName *>(_data._mem)->~StringName();
} break;
@@ -1430,7 +1348,7 @@ void Variant::_clear_internal() {
} break;
case OBJECT: {
if (_get_obj().id.is_ref_counted()) {
- //we are safe that there is a reference here
+ // We are safe that there is a reference here.
RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
if (ref_counted->unreference()) {
memdelete(ref_counted);
@@ -1440,8 +1358,8 @@ void Variant::_clear_internal() {
_get_obj().id = ObjectID();
} break;
case RID: {
- // not much need probably
- // Can't seem to use destructor + scoping operator, so hack.
+ // Not much need probably.
+ // HACK: Can't seem to use destructor + scoping operator, so hack.
typedef ::RID RID_Class;
reinterpret_cast<RID_Class *>(_data._mem)->~RID_Class();
} break;
@@ -1457,7 +1375,8 @@ void Variant::_clear_internal() {
case ARRAY: {
reinterpret_cast<Array *>(_data._mem)->~Array();
} break;
- // arrays
+
+ // Arrays.
case PACKED_BYTE_ARRAY: {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
@@ -1486,7 +1405,9 @@ void Variant::_clear_internal() {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
default: {
- } /* not needed */
+ // Not needed, there is no point. The following do not allocate memory:
+ // VECTOR2, VECTOR3, RECT2, PLANE, QUATERNION, COLOR.
+ }
}
}
@@ -1835,11 +1756,13 @@ String Variant::stringify(int recursion_count) const {
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Max recursion reached");
- return "{...}";
+ ERR_PRINT("Maximum dictionary recursion reached!");
+ return "{ ... }";
}
- String str("{");
+ // Add leading and trailing space to Dictionary printing. This distinguishes it
+ // from array printing on fonts that have similar-looking {} and [] characters.
+ String str("{ ");
List<Variant> keys;
d.get_key_list(&keys);
@@ -1858,49 +1781,48 @@ String Variant::stringify(int recursion_count) const {
if (i > 0) {
str += ", ";
}
- str += pairs[i].key + ":" + pairs[i].value;
+ str += pairs[i].key + ": " + pairs[i].value;
}
- str += "}";
+ str += " }";
return str;
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return stringify_vector(operator Vector<Vector2>(), recursion_count);
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return stringify_vector(operator Vector<Vector3>(), recursion_count);
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return stringify_vector(operator Vector<Color>(), recursion_count);
- } break;
+ }
case PACKED_STRING_ARRAY: {
return stringify_vector(operator Vector<String>(), recursion_count);
- } break;
+ }
case PACKED_BYTE_ARRAY: {
return stringify_vector(operator Vector<uint8_t>(), recursion_count);
- } break;
+ }
case PACKED_INT32_ARRAY: {
return stringify_vector(operator Vector<int32_t>(), recursion_count);
- } break;
+ }
case PACKED_INT64_ARRAY: {
return stringify_vector(operator Vector<int64_t>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return stringify_vector(operator Vector<float>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return stringify_vector(operator Vector<double>(), recursion_count);
- } break;
+ }
case ARRAY: {
Array arr = operator Array();
if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Max recursion reached");
+ ERR_PRINT("Maximum array recursion reached!");
return "[...]";
}
return stringify_vector(arr, recursion_count);
-
- } break;
+ }
case OBJECT: {
if (_get_obj().obj) {
if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
@@ -1911,31 +1833,27 @@ String Variant::stringify(int recursion_count) const {
} else {
return "<Object#null>";
}
-
- } break;
+ }
case CALLABLE: {
const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
return c;
- } break;
+ }
case SIGNAL: {
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
return s;
- } break;
+ }
case RID: {
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
return "RID(" + itos(s.get_id()) + ")";
- } break;
+ }
default: {
return "<" + get_type_name(type) + ">";
}
}
-
- return "";
}
String Variant::to_json_string() const {
- JSON json;
- return json.stringify(*this);
+ return JSON::stringify(*this);
}
Variant::operator Vector2() const {
@@ -3121,22 +3039,22 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
case PROJECTION: {
uint32_t h = HASH_MURMUR3_SEED;
const Projection &t = *_data._projection;
- h = hash_murmur3_one_real(t.matrix[0].x, h);
- h = hash_murmur3_one_real(t.matrix[0].y, h);
- h = hash_murmur3_one_real(t.matrix[0].z, h);
- h = hash_murmur3_one_real(t.matrix[0].w, h);
- h = hash_murmur3_one_real(t.matrix[1].x, h);
- h = hash_murmur3_one_real(t.matrix[1].y, h);
- h = hash_murmur3_one_real(t.matrix[1].z, h);
- h = hash_murmur3_one_real(t.matrix[1].w, h);
- h = hash_murmur3_one_real(t.matrix[2].x, h);
- h = hash_murmur3_one_real(t.matrix[2].y, h);
- h = hash_murmur3_one_real(t.matrix[2].z, h);
- h = hash_murmur3_one_real(t.matrix[2].w, h);
- h = hash_murmur3_one_real(t.matrix[3].x, h);
- h = hash_murmur3_one_real(t.matrix[3].y, h);
- h = hash_murmur3_one_real(t.matrix[3].z, h);
- h = hash_murmur3_one_real(t.matrix[3].w, h);
+ h = hash_murmur3_one_real(t.columns[0].x, h);
+ h = hash_murmur3_one_real(t.columns[0].y, h);
+ h = hash_murmur3_one_real(t.columns[0].z, h);
+ h = hash_murmur3_one_real(t.columns[0].w, h);
+ h = hash_murmur3_one_real(t.columns[1].x, h);
+ h = hash_murmur3_one_real(t.columns[1].y, h);
+ h = hash_murmur3_one_real(t.columns[1].z, h);
+ h = hash_murmur3_one_real(t.columns[1].w, h);
+ h = hash_murmur3_one_real(t.columns[2].x, h);
+ h = hash_murmur3_one_real(t.columns[2].y, h);
+ h = hash_murmur3_one_real(t.columns[2].z, h);
+ h = hash_murmur3_one_real(t.columns[2].w, h);
+ h = hash_murmur3_one_real(t.columns[3].x, h);
+ h = hash_murmur3_one_real(t.columns[3].y, h);
+ h = hash_murmur3_one_real(t.columns[3].z, h);
+ h = hash_murmur3_one_real(t.columns[3].w, h);
return hash_fmix32(h);
} break;
// misc types
@@ -3507,7 +3425,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
const Projection *r = p_variant._data._projection;
for (int i = 0; i < 4; i++) {
- if (!(hash_compare_vector4(l->matrix[i], r->matrix[i]))) {
+ if (!(hash_compare_vector4(l->columns[i], r->columns[i]))) {
return false;
}
}
@@ -3571,8 +3489,6 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
evaluate(OP_EQUAL, *this, p_variant, r, v);
return r;
}
-
- return false;
}
bool Variant::is_ref_counted() const {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 1831f7b72a..087ce09215 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1606,6 +1606,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
bind_method(Vector2, is_zero_approx, sarray(), varray());
+ bind_method(Vector2, is_finite, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
@@ -1653,6 +1654,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, is_finite, sarray(), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
bind_method(Rect2, intersection, sarray("b"), varray());
@@ -1695,6 +1697,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
bind_method(Vector3, is_zero_approx, sarray(), varray());
+ bind_method(Vector3, is_finite, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1759,6 +1762,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
bind_method(Vector4, is_zero_approx, sarray(), varray());
+ bind_method(Vector4, is_finite, sarray(), varray());
/* Vector4i */
@@ -1775,6 +1779,7 @@ static void _register_variant_builtin_methods() {
bind_method(Plane, normalized, sarray(), varray());
bind_method(Plane, center, sarray(), varray());
bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_finite, sarray(), varray());
bind_method(Plane, is_point_over, sarray("point"), varray());
bind_method(Plane, distance_to, sarray("point"), varray());
bind_method(Plane, has_point, sarray("point", "tolerance"), varray(CMP_EPSILON));
@@ -1790,6 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, normalized, sarray(), varray());
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
+ bind_method(Quaternion, is_finite, sarray(), varray());
bind_method(Quaternion, inverse, sarray(), varray());
bind_method(Quaternion, log, sarray(), varray());
bind_method(Quaternion, exp, sarray(), varray());
@@ -1800,6 +1806,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Quaternion, get_euler, sarray(), varray());
+ bind_static_method(Quaternion, from_euler, sarray("euler"), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
@@ -1829,10 +1836,6 @@ static void _register_variant_builtin_methods() {
bind_static_method(Color, hex64, sarray("hex"), varray());
bind_static_method(Color, html, sarray("rgba"), varray());
bind_static_method(Color, html_is_valid, sarray("color"), varray());
- bind_static_method(Color, find_named_color, sarray("name"), varray());
- bind_static_method(Color, get_named_color_count, sarray(), varray());
- bind_static_method(Color, get_named_color_name, sarray("idx"), varray());
- bind_static_method(Color, get_named_color, sarray("idx"), varray());
bind_static_method(Color, from_string, sarray("str", "default"), varray());
bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0));
bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0));
@@ -1909,6 +1912,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform2D, is_finite, sarray(), varray());
bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
bind_method(Transform2D, set_scale, sarray("scale"), varray());
bind_method(Transform2D, set_skew, sarray("skew"), varray());
@@ -1923,16 +1927,17 @@ static void _register_variant_builtin_methods() {
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
- bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_method(Basis, get_euler, sarray("order"), varray((int64_t)Basis::EULER_ORDER_YXZ));
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, is_finite, sarray(), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_static_method(Basis, from_scale, sarray("scale"), varray());
- bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_static_method(Basis, from_euler, sarray("euler", "order"), varray((int64_t)Basis::EULER_ORDER_YXZ));
/* AABB */
@@ -1943,6 +1948,7 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(AABB, is_finite, sarray(), varray());
bind_method(AABB, intersects, sarray("with"), varray());
bind_method(AABB, encloses, sarray("with"), varray());
bind_method(AABB, intersects_plane, sarray("plane"), varray());
@@ -1975,6 +1981,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform3D, is_finite, sarray(), varray());
/* Projection */
@@ -2043,6 +2050,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
+ bind_method(Array, pick_random, sarray(), varray());
bind_method(Array, find, sarray("what", "from"), varray(0));
bind_method(Array, rfind, sarray("what", "from"), varray(-1));
bind_method(Array, find_last, sarray("value"), varray());
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3b88dc11ca..ae9727fe79 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -141,7 +141,6 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
- add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz"));
add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp
index ab8303f3ae..5117c33e2b 100644
--- a/core/variant/variant_destruct.cpp
+++ b/core/variant/variant_destruct.cpp
@@ -41,13 +41,8 @@ static void add_destructor() {
void Variant::_register_variant_destructors() {
add_destructor<VariantDestruct<String>>();
- add_destructor<VariantDestruct<Transform2D>>();
- add_destructor<VariantDestruct<::AABB>>();
- add_destructor<VariantDestruct<Basis>>();
- add_destructor<VariantDestruct<Transform3D>>();
add_destructor<VariantDestruct<StringName>>();
add_destructor<VariantDestruct<NodePath>>();
- add_destructor<VariantDestruct<::RID>>();
add_destructor<VariantDestruct<Callable>>();
add_destructor<VariantDestruct<Signal>>();
add_destructor<VariantDestruct<Dictionary>>();
diff --git a/core/variant/variant_destruct.h b/core/variant/variant_destruct.h
index 5e3478635d..2730110c0f 100644
--- a/core/variant/variant_destruct.h
+++ b/core/variant/variant_destruct.h
@@ -50,13 +50,8 @@ struct VariantDestruct {};
}
MAKE_PTRDESTRUCT(String);
-MAKE_PTRDESTRUCT(Transform2D);
-MAKE_PTRDESTRUCT(AABB);
-MAKE_PTRDESTRUCT(Basis);
-MAKE_PTRDESTRUCT(Transform3D);
MAKE_PTRDESTRUCT(StringName);
MAKE_PTRDESTRUCT(NodePath);
-MAKE_PTRDESTRUCT(RID);
MAKE_PTRDESTRUCT(Callable);
MAKE_PTRDESTRUCT(Signal);
MAKE_PTRDESTRUCT(Dictionary);
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 874a183d29..636710c934 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -826,7 +826,7 @@ VARIANT_ACCESSOR_NUMBER(Projection::Planes)
template <>
struct VariantInternalAccessor<Basis::EulerOrder> {
static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); }
- static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; }
+ static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; }
};
template <>
@@ -1047,7 +1047,7 @@ struct VariantInternalAccessor<PackedColorArray> {
template <>
struct VariantInternalAccessor<Object *> {
static _FORCE_INLINE_ Object *get(const Variant *v) { return const_cast<Object *>(*VariantInternal::get_object(v)); }
- static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { *VariantInternal::get_object(v) = const_cast<Object *>(p_value); }
+ static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { VariantInternal::object_assign(v, p_value); }
};
template <>
@@ -1532,27 +1532,4 @@ struct VariantTypeConstructor {
}
};
-template <>
-struct VariantTypeConstructor<Object *> {
- _FORCE_INLINE_ static void variant_from_type(void *p_variant, void *p_value) {
- Variant *variant = reinterpret_cast<Variant *>(p_variant);
- VariantInitializer<Object *>::init(variant);
- Object *object = *(reinterpret_cast<Object **>(p_value));
- if (object) {
- if (object->is_ref_counted()) {
- if (!VariantInternal::initialize_ref(object)) {
- return;
- }
- }
- VariantInternalAccessor<Object *>::set(variant, object);
- VariantInternalAccessor<ObjectID>::set(variant, object->get_instance_id());
- }
- }
-
- _FORCE_INLINE_ static void type_from_variant(void *p_value, void *p_variant) {
- Object **value = reinterpret_cast<Object **>(p_value);
- *value = VariantInternalAccessor<Object *>::get(reinterpret_cast<Variant *>(p_variant));
- }
-};
-
#endif // VARIANT_INTERNAL_H
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 6cca7955ae..25bc241e9b 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -240,8 +240,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT);
register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT);
register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
@@ -384,10 +382,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorDivNZ<Vector2, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT);
register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
-
register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
@@ -498,8 +492,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
- register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
-
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
@@ -567,6 +559,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -603,6 +596,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH);
@@ -688,6 +682,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -724,6 +719,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 8151ff2102..d2e4d752a4 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1651,7 +1651,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
- s += rtos_fix(t.matrix[i][j]);
+ s += rtos_fix(t.columns[i][j]);
}
}
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index ff67b187ef..188103ee5e 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -826,7 +826,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .columns, 3)
INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_column, get_column, 3)
-INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Projection, Vector4, .matrix, 4)
+INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Projection, Vector4, .columns, 4)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t)
diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h
index 570277dc7a..d151a85a6e 100644
--- a/core/variant/variant_setget.h
+++ b/core/variant/variant_setget.h
@@ -325,10 +325,10 @@ SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_column, get_column, 2)
SETGET_STRUCT(Transform3D, Basis, basis)
SETGET_STRUCT(Transform3D, Vector3, origin)
-SETGET_STRUCT_CUSTOM(Projection, Vector4, x, matrix[0])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, y, matrix[1])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, z, matrix[2])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, w, matrix[3])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, x, columns[0])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, y, columns[1])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, z, columns[2])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, w, columns[3])
SETGET_NUMBER_STRUCT(Color, double, r)
SETGET_NUMBER_STRUCT(Color, double, g)
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 670b66d53e..3843c32bcc 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -310,6 +310,10 @@ struct VariantUtilityFunctions {
return Math::is_zero_approx(x);
}
+ static inline bool is_finite(double x) {
+ return Math::is_finite(x);
+ }
+
static inline double ease(float x, float curve) {
return Math::ease(x, curve);
}
@@ -1420,6 +1424,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_finite, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 5bb10d162f..e30034495c 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -16,7 +16,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = abs(-1)
# a is 1
@@ -114,7 +114,7 @@
<param index="3" name="end" type="float" />
<param index="4" name="t" type="float" />
<description>
- Returns the point at the given [param t] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
+ Returns the point at the given [param t] on a one-dimensional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
<method name="bytes_to_var">
@@ -143,7 +143,7 @@
i = ceil(1.001) # i is 2.0
[/codeblock]
See also [method floor], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] or [method Vector4.ceil] instead.
+ [b]Note:[/b] For better type safety, see [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] and [method Vector4.ceil].
</description>
</method>
<method name="ceilf">
@@ -151,7 +151,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil], specialzied in floats.
+ A type-safe version of [method ceil], returning a [float].
</description>
</method>
<method name="ceili">
@@ -159,7 +159,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
- A type-safe version of [method ceil] that returns integer.
+ A type-safe version of [method ceil], returning an [int].
</description>
</method>
<method name="clamp">
@@ -168,7 +168,7 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Clamps the [Variant] [param value] and returns a value not less than [param min] and not more than [param max]. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Clamps the [param value], returning a [Variant] not less than [param min] and not more than [param max]. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = clamp(-10, -1, 5)
# a is -1
@@ -196,15 +196,13 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Clamps the float [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning a [float] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42.1
- # a is 20.0
- var a = clampf(speed, 1.0, 20.0)
+ var a = clampf(speed, 1.0, 20.5) # a is 20.5
speed = -10.0
- # a is -1.0
- a = clampf(speed, -1.0, 1.0)
+ var b = clampf(speed, -1.0, 1.0) # b is -1.0
[/codeblock]
</description>
</method>
@@ -214,15 +212,13 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Clamps the integer [param value] and returns a value not less than [param min] and not more than [param max].
+ Clamps the [param value], returning an [int] not less than [param min] and not more than [param max].
[codeblock]
var speed = 42
- # a is 20
- var a = clampi(speed, 1, 20)
+ var a = clampi(speed, 1, 20) # a is 20
speed = -10
- # a is -1
- a = clampi(speed, -1, 1)
+ var b = clampi(speed, -1, 1) # b is -1
[/codeblock]
</description>
</method>
@@ -244,8 +240,7 @@
<description>
Returns the hyperbolic cosine of [param x] in radians.
[codeblock]
- # Prints 1.543081
- print(cosh(1))
+ print(cosh(1)) # Prints 1.543081
[/codeblock]
</description>
</method>
@@ -257,7 +252,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
</description>
</method>
<method name="cubic_interpolate_angle">
@@ -268,7 +263,7 @@
<param index="3" name="post" type="float" />
<param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
</description>
</method>
<method name="cubic_interpolate_angle_in_time">
@@ -282,7 +277,7 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with [param pre] and [param post] values. See also [method lerp_angle].
It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
@@ -297,8 +292,8 @@
<param index="6" name="pre_t" type="float" />
<param index="7" name="post_t" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
- It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ Cubic interpolates between two values by the factor defined in [param weight] with [param pre] and [param post] values.
+ It can perform smoother interpolation than [method cubic_interpolate] by the time values.
</description>
</method>
<method name="db_to_linear">
@@ -314,8 +309,7 @@
<description>
Converts an angle expressed in degrees to radians.
[codeblock]
- # r is 3.141593
- var r = deg_to_rad(180)
+ var r = deg_to_rad(180) # r is 3.141593
[/codeblock]
</description>
</method>
@@ -342,7 +336,13 @@
<return type="String" />
<param index="0" name="error" type="int" />
<description>
- Returns a human-readable name for the given error code.
+ Returns a human-readable name for the given [enum Error] code.
+ [codeblock]
+ print(OK) # Prints 0
+ print(error_string(OK)) # Prints OK
+ print(error_string(ERR_BUSY)) # Prints Busy
+ print(error_string(ERR_OUT_OF_MEMORY)) # Prints Out of memory
+ [/codeblock]
</description>
</method>
<method name="exp">
@@ -363,13 +363,11 @@
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x]. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
- # a is 2.0
- var a = floor(2.99)
- # a is -3.0
- a = floor(-2.99)
+ var a = floor(2.99) # a is 2.0
+ a = floor(-2.99) # a is -3.0
[/codeblock]
See also [method ceil], [method round], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] or [method Vector4.floor] instead.
+ [b]Note:[/b] For better type safety, see [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] and [method Vector4.floor].
</description>
</method>
<method name="floorf">
@@ -377,7 +375,7 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- A type-safe version of [method floor], specialzied in floats.
+ A type-safe version of [method floor], returning a [float].
</description>
</method>
<method name="floori">
@@ -385,7 +383,8 @@
<param index="0" name="x" type="float" />
<description>
Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
- Equivalent of doing [code]int(x)[/code].
+ A type-safe version of [method floor], returning an [int].
+ [b]Note:[/b] This function is [i]not[/i] the same as [code]int(x)[/code], which rounds towards 0.
</description>
</method>
<method name="fmod">
@@ -393,10 +392,9 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point remainder of [code]x/y[/code], keeping the sign of [param x].
+ Returns the floating-point remainder of [param x] divided by [param y], keeping the sign of [param x].
[codeblock]
- # Remainder is 1.5
- var remainder = fmod(7, 5.5)
+ var remainder = fmod(7, 5.5) # remainder is 1.5
[/codeblock]
For the integer remainder operation, use the [code]%[/code] operator.
</description>
@@ -406,21 +404,23 @@
<param index="0" name="x" type="float" />
<param index="1" name="y" type="float" />
<description>
- Returns the floating-point modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the floating-point modulus of [param x] divided by [param y], wrapping equally in positive and negative.
[codeblock]
+ print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
for i in 7:
- var x = 0.5 * i - 1.5
- print("%4.1f %4.1f %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
+ var x = i * 0.5 - 1.5
+ print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
[/codeblock]
Produces:
[codeblock]
- -1.5 -0.0 0.0
- -1.0 -1.0 0.5
- -0.5 -0.5 1.0
- 0.0 0.0 0.0
- 0.5 0.5 0.5
- 1.0 1.0 1.0
- 1.5 0.0 0.0
+ (x) (fmod(x, 1.5)) (fposmod(x, 1.5))
+ -1.5 -0.0 | 0.0
+ -1.0 -1.0 | 0.5
+ -0.5 -0.5 | 1.0
+ 0.0 0.0 | 0.0
+ 0.5 0.5 | 0.5
+ 1.0 1.0 | 1.0
+ 1.5 0.0 | 0.0
[/codeblock]
</description>
</method>
@@ -428,7 +428,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the integer hash of the variable passed.
+ Returns the integer hash of the passed [param variable].
[codeblock]
print(hash("a")) # Prints 177670
[/codeblock]
@@ -438,7 +438,7 @@
<return type="Object" />
<param index="0" name="instance_id" type="int" />
<description>
- Returns the Object that corresponds to [param instance_id]. All Objects have a unique instance ID.
+ Returns the [Object] that corresponds to [param instance_id]. All Objects have a unique instance ID. See also [method Object.get_instance_id].
[codeblock]
var foo = "bar"
func _ready():
@@ -458,12 +458,13 @@
[codeblock]
# The interpolation ratio in the `lerp()` call below is 0.75.
var middle = lerp(20, 30, 0.75)
- # `middle` is now 27.5.
+ # middle is now 27.5.
+
# Now, we pretend to have forgotten the original ratio and want to get it back.
var ratio = inverse_lerp(20, 30, 27.5)
- # `ratio` is now 0.75.
+ # ratio is now 0.75.
[/codeblock]
- See also [method lerp] which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
+ See also [method lerp], which performs the reverse of this operation, and [method remap] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
@@ -472,15 +473,22 @@
<param index="1" name="b" type="float" />
<description>
Returns [code]true[/code] if [param a] and [param b] are approximately equal to each other.
- Here, approximately equal means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
+ Here, "approximately equal" means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
Infinity values of the same sign are considered equal.
</description>
</method>
+ <method name="is_finite">
+ <return type="bool" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Returns whether [code]x[/code] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity.
+ </description>
+ </method>
<method name="is_inf">
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is an infinity value (either positive infinity or negative infinity).
+ Returns [code]true[/code] if [param x] is either positive infinity or negative infinity.
</description>
</method>
<method name="is_instance_id_valid">
@@ -494,14 +502,14 @@
<return type="bool" />
<param index="0" name="instance" type="Variant" />
<description>
- Returns whether [param instance] is a valid object (e.g. has not been deleted from memory).
+ Returns [code]true[/code] if [param instance] is a valid Object (e.g. has not been deleted from memory).
</description>
</method>
<method name="is_nan">
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [param x] is a NaN ("Not a Number" or invalid) value.
+ Returns [code]true[/code] if [param x] is a NaN ("Not a Number" or invalid) value.
</description>
</method>
<method name="is_zero_approx">
@@ -509,7 +517,7 @@
<param index="0" name="x" type="float" />
<description>
Returns [code]true[/code] if [param x] is zero or almost zero.
- This method is faster than using [method is_equal_approx] with one value as zero.
+ This function is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
<method name="lerp">
@@ -518,13 +526,13 @@
<param index="1" name="to" type="Variant" />
<param index="2" name="weight" type="Variant" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. Use [method clamp] on the result of [method lerp] if this is not desired.
- Both [param from] and [param to] must have matching types. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clamp] on the result of this function.
+ Both [param from] and [param to] must be the same type. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method remap] to map a continuous series of values to another.
- [b]Note:[/b] For better type safety, you can use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp] instead.
+ [b]Note:[/b] For better type safety, use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp].
</description>
</method>
<method name="lerp_angle">
@@ -533,7 +541,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two angles (in radians) by a normalized value.
+ Linearly interpolates between two angles (in radians) by a [param weight] value between 0.0 and 1.0.
Similar to [method lerp], but interpolates correctly when the angles wrap around [constant @GDScript.TAU]. To perform eased interpolation with [method lerp_angle], combine it with [method ease] or [method smoothstep].
[codeblock]
extends Sprite
@@ -544,7 +552,7 @@
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
[/codeblock]
- [b]Note:[/b] This method lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
+ [b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
</description>
</method>
<method name="lerpf">
@@ -553,7 +561,7 @@
<param index="1" name="to" type="float" />
<param index="2" name="weight" type="float" />
<description>
- Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. If this is not desired, use [method clampf] on the result of this function.
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
@@ -577,7 +585,7 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
+ Returns the natural logarithm of [param x]. This is the amount of time needed to reach a certain level of continuous growth.
[b]Note:[/b] This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
[codeblock]
log(10) # Returns 2.302585
@@ -588,7 +596,7 @@
<method name="max" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the maximum of the given values. This method can take any number of arguments.
+ Returns the maximum of the given values. This function can take any number of arguments.
[codeblock]
max(1, 7, 3, -6, 5) # Returns 7
[/codeblock]
@@ -599,9 +607,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the maximum of two float values.
+ Returns the maximum of two [float] values.
[codeblock]
- maxf(3.6, 24) # Returns 24.0
+ maxf(3.6, 24) # Returns 24.0
maxf(-3.99, -4) # Returns -3.99
[/codeblock]
</description>
@@ -611,9 +619,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the maximum of two int values.
+ Returns the maximum of two [int] values.
[codeblock]
- maxi(1, 2) # Returns 2
+ maxi(1, 2) # Returns 2
maxi(-3, -4) # Returns -3
[/codeblock]
</description>
@@ -621,7 +629,7 @@
<method name="min" qualifiers="vararg">
<return type="Variant" />
<description>
- Returns the minimum of the given values. This method can take any number of arguments.
+ Returns the minimum of the given values. This function can take any number of arguments.
[codeblock]
min(1, 7, 3, -6, 5) # Returns -6
[/codeblock]
@@ -632,9 +640,9 @@
<param index="0" name="a" type="float" />
<param index="1" name="b" type="float" />
<description>
- Returns the minimum of two float values.
+ Returns the minimum of two [float] values.
[codeblock]
- minf(3.6, 24) # Returns 3.6
+ minf(3.6, 24) # Returns 3.6
minf(-3.99, -4) # Returns -4.0
[/codeblock]
</description>
@@ -644,9 +652,9 @@
<param index="0" name="a" type="int" />
<param index="1" name="b" type="int" />
<description>
- Returns the minimum of two int values.
+ Returns the minimum of two [int] values.
[codeblock]
- mini(1, 2) # Returns 1
+ mini(1, 2) # Returns 1
mini(-3, -4) # Returns -4
[/codeblock]
</description>
@@ -660,8 +668,8 @@
Moves [param from] toward [param to] by the [param delta] value.
Use a negative [param delta] value to move away.
[codeblock]
- move_toward(5, 10, 4) # Returns 9
- move_toward(10, 5, 4) # Returns 6
+ move_toward(5, 10, 4) # Returns 9
+ move_toward(10, 5, 4) # Returns 6
move_toward(10, 5, -1.5) # Returns 11.5
[/codeblock]
</description>
@@ -670,17 +678,17 @@
<return type="int" />
<param index="0" name="value" type="int" />
<description>
- Returns the nearest equal or larger power of 2 for integer [param value].
+ Returns the nearest equal or larger power of 2 for the integer [param value].
In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
[codeblock]
nearest_po2(3) # Returns 4
nearest_po2(4) # Returns 4
nearest_po2(5) # Returns 8
- nearest_po2(0) # Returns 0 (this may not be what you expect)
- nearest_po2(-1) # Returns 0 (this may not be what you expect)
+ nearest_po2(0) # Returns 0 (this may not be expected)
+ nearest_po2(-1) # Returns 0 (this may not be expected)
[/codeblock]
- [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [param value] (in reality, 1 is the smallest integer power of 2).
+ [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for negative values of [param value] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
<method name="pingpong">
@@ -688,18 +696,18 @@
<param index="0" name="value" type="float" />
<param index="1" name="length" type="float" />
<description>
- Returns the [param value] wrapped between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
+ Wraps [param value] between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returns is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
[codeblock]
- pingpong(-3.0, 3.0) # Returns 3
- pingpong(-2.0, 3.0) # Returns 2
- pingpong(-1.0, 3.0) # Returns 1
- pingpong(0.0, 3.0) # Returns 0
- pingpong(1.0, 3.0) # Returns 1
- pingpong(2.0, 3.0) # Returns 2
- pingpong(3.0, 3.0) # Returns 3
- pingpong(4.0, 3.0) # Returns 2
- pingpong(5.0, 3.0) # Returns 1
- pingpong(6.0, 3.0) # Returns 0
+ pingpong(-3.0, 3.0) # Returns 3.0
+ pingpong(-2.0, 3.0) # Returns 2.0
+ pingpong(-1.0, 3.0) # Returns 1.0
+ pingpong(0.0, 3.0) # Returns 0.0
+ pingpong(1.0, 3.0) # Returns 1.0
+ pingpong(2.0, 3.0) # Returns 2.0
+ pingpong(3.0, 3.0) # Returns 3.0
+ pingpong(4.0, 3.0) # Returns 2.0
+ pingpong(5.0, 3.0) # Returns 1.0
+ pingpong(6.0, 3.0) # Returns 0.0
[/codeblock]
</description>
</method>
@@ -708,20 +716,22 @@
<param index="0" name="x" type="int" />
<param index="1" name="y" type="int" />
<description>
- Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ Returns the integer modulus of [param x] divided by [param y] that wraps equally in positive and negative.
[codeblock]
+ print("#(i) (i % 3) (posmod(i, 3))")
for i in range(-3, 4):
- print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
+ print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
[/codeblock]
Produces:
[codeblock]
- -3 0 0
- -2 -2 1
- -1 -1 2
- 0 0 0
- 1 1 1
- 2 2 2
- 3 0 0
+ (i) (i % 3) (posmod(i, 3))
+ -3 0 | 0
+ -2 -2 | 1
+ -1 -1 | 2
+ 0 0 | 0
+ 1 1 | 1
+ 2 2 | 2
+ 3 0 | 0
[/codeblock]
</description>
</method>
@@ -731,6 +741,7 @@
<param index="1" name="exp" type="float" />
<description>
Returns the result of [param base] raised to the power of [param exp].
+ In GDScript, this is the equivalent of the [code]**[/code] operator.
[codeblock]
pow(2, 5) # Returns 32
[/codeblock]
@@ -743,7 +754,7 @@
var a = [1, 2, 3]
print("a", "b", a) # Prints ab[1, 2, 3]
[/codeblock]
- [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
+ [b]Note:[/b] Consider using [method push_error] and [method push_warning] to print error and warning messages instead of [method print] or [method print_rich]. This distinguishes them from print messages used for debugging purposes, while also displaying a stack trace when an error or warning is printed.
</description>
</method>
<method name="print_rich" qualifiers="vararg">
@@ -771,11 +782,12 @@
</method>
<method name="printraw" qualifiers="vararg">
<description>
- Prints one or more arguments to strings in the best way possible to console. No newline is added at the end.
+ Prints one or more arguments to strings in the best way possible to console. Unlike [method print], no newline is automatically added at the end.
[codeblock]
printraw("A")
printraw("B")
- # Prints AB
+ printraw("C")
+ # Prints ABC
[/codeblock]
[b]Note:[/b] Due to limitations with Godot's built-in console, this only prints to the terminal. If you need to print in the editor, use another method, such as [method print].
</description>
@@ -802,7 +814,7 @@
[codeblock]
push_error("test error") # Prints "test error" to debugger and terminal as error call
[/codeblock]
- [b]Note:[/b] Errors printed this way will not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
+ [b]Note:[/b] This function does not pause project execution. To print an error message and pause project execution in debug builds, use [code]assert(false, "test error")[/code] instead.
</description>
</method>
<method name="push_warning" qualifiers="vararg">
@@ -820,6 +832,8 @@
Converts an angle expressed in radians to degrees.
[codeblock]
rad_to_deg(0.523599) # Returns 30
+ rad_to_deg(PI) # Returns 180
+ rad_to_deg(PI * 2) # Returns 360
[/codeblock]
</description>
</method>
@@ -827,7 +841,14 @@
<return type="PackedInt64Array" />
<param index="0" name="seed" type="int" />
<description>
- Random from seed: pass a [param seed], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
+ Given a [param seed], returns a [PackedInt64Array] of size [code]2[/code], where its first element is the randomised [int] value, and the second element is the same as [param seed]. Passing the same [param seed] consistently returns the same array.
+ [b]Note:[/b] "Seed" here refers to the internal state of the pseudo random number generator, currently implemented as a 64 bit integer.
+ [codeblock]
+ var a = rand_from_seed(4)
+
+ print(a[0]) # Prints 2879024997
+ print(a[1]) # Prints 4
+ [/codeblock]
</description>
</method>
<method name="randf">
@@ -844,9 +865,10 @@
<param index="0" name="from" type="float" />
<param index="1" name="to" type="float" />
<description>
- Returns a random floating point value on the interval between [param from] and [param to] (inclusive).
+ Returns a random floating point value between [param from] and [param to] (inclusive).
[codeblock]
- prints(randf_range(-10, 10), randf_range(-10, 10)) # Prints e.g. -3.844535 7.45315
+ randf_range(0, 20.5) # Returns e.g. 7.45315
+ randf_range(-10, 10) # Returns e.g. -3.844535
[/codeblock]
</description>
</method>
@@ -877,15 +899,15 @@
<description>
Returns a random signed 32-bit integer between [param from] and [param to] (inclusive). If [param to] is lesser than [param from], they are swapped.
[codeblock]
- print(randi_range(0, 1)) # Prints 0 or 1
- print(randi_range(-10, 1000)) # Prints any number from -10 to 1000
+ randi_range(0, 1) # Returns either 0 or 1
+ randi_range(-10, 1000) # Returns random integer between -10 and 1000
[/codeblock]
</description>
</method>
<method name="randomize">
<description>
- Randomizes the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- [b]Note:[/b] This method is called automatically when the project is run. If you need to fix the seed to have reproducible results, use [method seed] to initialize the random number generator.
+ Randomizes the seed (or the internal state) of the random number generator. The current implementation uses a number based on the device's time.
+ [b]Note:[/b] This function is called automatically when the project is run. If you need to fix the seed to have consistent, reproducible results, use [method seed] to initialize the random number generator.
</description>
</method>
<method name="remap">
@@ -896,63 +918,67 @@
<param index="3" name="ostart" type="float" />
<param index="4" name="ostop" type="float" />
<description>
- Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method remap] if this is not desired.
+ Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. If this is not desired, use [method clamp] on the result of this function.
[codeblock]
remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
- For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
+ For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
</description>
</method>
<method name="rid_allocate_id">
<return type="int" />
<description>
- Allocate a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
+ Allocates a unique ID which can be used by the implementation to construct a RID. This is used mainly from native extensions to implement servers.
</description>
</method>
<method name="rid_from_int64">
<return type="RID" />
<param index="0" name="base" type="int" />
<description>
- Create a RID from an int64. This is used mainly from native extensions to build servers.
+ Creates a RID from a [param base]. This is used mainly from native extensions to build servers.
</description>
</method>
<method name="round">
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
round(2.4) # Returns 2
round(2.5) # Returns 3
round(2.6) # Returns 3
[/codeblock]
See also [method floor], [method ceil], and [method snapped].
- [b]Note:[/b] For better type safety, you can use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round] instead.
+ [b]Note:[/b] For better type safety, use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round], instead.
</description>
</method>
<method name="roundf">
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round], specialzied in floats.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning a [float].
</description>
</method>
<method name="roundi">
<return type="int" />
<param index="0" name="x" type="float" />
<description>
- Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
- A type-safe version of [method round] that returns integer.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from 0.
+ A type-safe version of [method round], returning an [int].
</description>
</method>
<method name="seed">
<param index="0" name="base" type="int" />
<description>
- Sets seed for the random number generator.
+ Sets the seed for the random number generator to [param base]. Setting the seed manually can ensure consistent, repeatable results for most random functions.
[codeblock]
- var my_seed = "Godot Rocks"
- seed(my_seed.hash())
+ var my_seed = "Godot Rocks".hash()
+ seed(my_seed)
+ var a = randf() + randi()
+ seed(my_seed)
+ var b = randf() + randi()
+ # a and b are now identical
[/codeblock]
</description>
</method>
@@ -960,7 +986,7 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectivelu. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectively. Variant types [int], [float], [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
sign(-6.0) # Returns -1
sign(0.0) # Returns 0
@@ -974,11 +1000,11 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Returns the sign of [param x] as a float: -1.0 or 1.0. Returns 0.0 if [param x] is 0.
+ Returns the sign of [param x] as a [float]: -1.0 or 1.0. Returns 0.0 if [param x] is 0.0.
[codeblock]
- sign(-6.0) # Returns -1.0
+ sign(-6.5) # Returns -1.0
sign(0.0) # Returns 0.0
- sign(6.0) # Returns 1.0
+ sign(6.5) # Returns 1.0
[/codeblock]
</description>
</method>
@@ -986,7 +1012,7 @@
<return type="int" />
<param index="0" name="x" type="int" />
<description>
- Returns the sign of [param x] as an integer: -1 or 1. Returns 0 if [param x] is 0.
+ Returns the sign of [param x] as an [int]: -1 or 1. Returns 0 if [param x] is 0.
[codeblock]
sign(-6) # Returns -1
sign(0) # Returns 0
@@ -1040,7 +1066,7 @@
<param index="0" name="x" type="float" />
<param index="1" name="step" type="float" />
<description>
- Snaps float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
+ Snaps the float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
[codeblock]
snapped(100, 32) # Returns 96
snapped(3.14159, 0.01) # Returns 3.14
@@ -1054,9 +1080,11 @@
<description>
Returns the square root of [param x], where [param x] is a non-negative number.
[codeblock]
- sqrt(9) # Returns 3
+ sqrt(9) # Returns 3
+ sqrt(10.24) # Returns 3.2
+ sqrt(-1) # Returns NaN
[/codeblock]
- [b]Note:[/b] Negative values of [param x] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
+ [b]Note:[/b] Negative values of [param x] return NaN ("Not a Number"). in C#, if you need negative inputs, use [code]System.Numerics.Complex[/code].
</description>
</method>
<method name="step_decimals">
@@ -1065,30 +1093,27 @@
<description>
Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
[codeblock]
- # n is 0
- var n = step_decimals(5)
- # n is 4
- n = step_decimals(1.0005)
- # n is 9
- n = step_decimals(0.000000005)
+ var n = step_decimals(5) # n is 0
+ n = step_decimals(1.0005) # n is 4
+ n = step_decimals(0.000000005) # n is 9
[/codeblock]
</description>
</method>
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments of any type to string in the best way possible.
+ Converts one or more arguments of any [Variant] type to [String] in the best way possible.
</description>
</method>
<method name="str_to_var">
<return type="Variant" />
<param index="0" name="string" type="String" />
<description>
- Converts a formatted [param string] that was returned by [method var_to_str] to the original value.
+ Converts a formatted [param string] that was returned by [method var_to_str] to the original [Variant].
[codeblock]
- var a = '{ "a": 1, "b": 2 }'
- var b = str_to_var(a)
- print(b["a"]) # Prints 1
+ var a = '{ "a": 1, "b": 2 }' # a is a String
+ var b = str_to_var(a) # b is a Dictionary
+ print(b["a"]) # Prints 1
[/codeblock]
</description>
</method>
@@ -1109,7 +1134,7 @@
Returns the hyperbolic tangent of [param x].
[codeblock]
var a = log(2.0) # Returns 0.693147
- tanh(a) # Returns 0.6
+ tanh(a) # Returns 0.6
[/codeblock]
</description>
</method>
@@ -1117,7 +1142,7 @@
<return type="int" />
<param index="0" name="variable" type="Variant" />
<description>
- Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
+ Returns the internal type of the given [param variable], using the [enum Variant.Type] values.
[codeblock]
var json = JSON.new()
json.parse('["a", "b", "c"]')
@@ -1141,19 +1166,19 @@
<return type="PackedByteArray" />
<param index="0" name="variable" type="Variant" />
<description>
- Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include code). Deserialization can be done with [method bytes_to_var_with_objects].
+ Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include executable code). Deserialization can be done with [method bytes_to_var_with_objects].
</description>
</method>
<method name="var_to_str">
<return type="String" />
<param index="0" name="variable" type="Variant" />
<description>
- Converts a Variant [param variable] to a formatted string that can later be parsed using [method str_to_var].
+ Converts a [Variant] [param variable] to a formatted [String] that can then be parsed using [method str_to_var].
[codeblock]
a = { "a": 1, "b": 2 }
print(var_to_str(a))
[/codeblock]
- prints
+ Prints:
[codeblock]
{
"a": 1,
@@ -1166,7 +1191,7 @@
<return type="Variant" />
<param index="0" name="obj" type="Variant" />
<description>
- Returns a weak reference to an object, or [code]null[/code] if the argument is invalid.
+ Returns a weak reference to an object, or [code]null[/code] if [param obj] is invalid.
A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
</description>
</method>
@@ -1176,9 +1201,8 @@
<param index="1" name="min" type="Variant" />
<param index="2" name="max" type="Variant" />
<description>
- Wraps the [Variant] [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
- Variant types [int] and [float] (real) are supported. If any of the argument is [float] the result will be [float], otherwise it is [int].
+ Wraps the [Variant] [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
+ Variant types [int] and [float] are supported. If any of the arguments is [float] this function returns a [float], otherwise it returns an [int].
[codeblock]
var a = wrap(4, 5, 10)
# a is 9 (int)
@@ -1197,8 +1221,7 @@
<param index="1" name="min" type="float" />
<param index="2" name="max" type="float" />
<description>
- Wraps float [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the float [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5.0 and 9.9
value = wrapf(value + 0.1, 5.0, 10.0)
@@ -1221,8 +1244,7 @@
<param index="1" name="min" type="int" />
<param index="2" name="max" type="int" />
<description>
- Wraps integer [param value] between [param min] and [param max].
- Usable for creating loop-alike behavior or infinite surfaces.
+ Wraps the integer [param value] between [param min] and [param max]. Can be used for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5 and 9
frame = wrapi(frame + 1, 5, 10)
@@ -1283,6 +1305,7 @@
The [Marshalls] singleton.
</member>
<member name="NativeExtensionManager" type="NativeExtensionManager" setter="" getter="">
+ The [NativeExtensionManager] singleton.
</member>
<member name="NavigationMeshGenerator" type="NavigationMeshGenerator" setter="" getter="">
The [NavigationMeshGenerator] singleton.
@@ -1377,8 +1400,10 @@
General horizontal alignment, usually used for [Separator], [ScrollBar], [Slider], etc.
</constant>
<constant name="CLOCKWISE" value="0" enum="ClockDirection">
+ Clockwise rotation. Used by some methods (e.g. [method Image.rotate_90]).
</constant>
<constant name="COUNTERCLOCKWISE" value="1" enum="ClockDirection">
+ Counter-clockwise rotation. Used by some methods (e.g. [method Image.rotate_90]).
</constant>
<constant name="HORIZONTAL_ALIGNMENT_LEFT" value="0" enum="HorizontalAlignment">
Horizontal left alignment, usually for text-derived classes.
@@ -1873,34 +1898,34 @@
/ key.
</constant>
<constant name="KEY_0" value="48" enum="Key">
- Number 0.
+ Number 0 key.
</constant>
<constant name="KEY_1" value="49" enum="Key">
- Number 1.
+ Number 1 key.
</constant>
<constant name="KEY_2" value="50" enum="Key">
- Number 2.
+ Number 2 key.
</constant>
<constant name="KEY_3" value="51" enum="Key">
- Number 3.
+ Number 3 key.
</constant>
<constant name="KEY_4" value="52" enum="Key">
- Number 4.
+ Number 4 key.
</constant>
<constant name="KEY_5" value="53" enum="Key">
- Number 5.
+ Number 5 key.
</constant>
<constant name="KEY_6" value="54" enum="Key">
- Number 6.
+ Number 6 key.
</constant>
<constant name="KEY_7" value="55" enum="Key">
- Number 7.
+ Number 7 key.
</constant>
<constant name="KEY_8" value="56" enum="Key">
- Number 8.
+ Number 8 key.
</constant>
<constant name="KEY_9" value="57" enum="Key">
- Number 9.
+ Number 9 key.
</constant>
<constant name="KEY_COLON" value="58" enum="Key">
: key.
@@ -2260,10 +2285,10 @@
Enum value which doesn't correspond to any mouse button. This is used to initialize [enum MouseButton] properties with a generic state.
</constant>
<constant name="MOUSE_BUTTON_LEFT" value="1" enum="MouseButton">
- Left mouse button.
+ Primary mouse button, usually assigned to the left button.
</constant>
<constant name="MOUSE_BUTTON_RIGHT" value="2" enum="MouseButton">
- Right mouse button.
+ Secondary mouse button, usually assigned to the right button.
</constant>
<constant name="MOUSE_BUTTON_MIDDLE" value="3" enum="MouseButton">
Middle mouse button.
@@ -2281,16 +2306,16 @@
Mouse wheel right button (only present on some mice).
</constant>
<constant name="MOUSE_BUTTON_XBUTTON1" value="8" enum="MouseButton">
- Extra mouse button 1 (only present on some mice).
+ Extra mouse button 1. This is sometimes present, usually to the sides of the mouse.
</constant>
<constant name="MOUSE_BUTTON_XBUTTON2" value="9" enum="MouseButton">
- Extra mouse button 2 (only present on some mice).
+ Extra mouse button 2. This is sometimes present, usually to the sides of the mouse.
</constant>
<constant name="MOUSE_BUTTON_MASK_LEFT" value="1" enum="MouseButton">
- Left mouse button mask.
+ Primary mouse button mask, usually for the left button.
</constant>
<constant name="MOUSE_BUTTON_MASK_RIGHT" value="2" enum="MouseButton">
- Right mouse button mask.
+ Secondary mouse button mask, usually for the right button.
</constant>
<constant name="MOUSE_BUTTON_MASK_MIDDLE" value="4" enum="MouseButton">
Middle mouse button mask.
@@ -2350,7 +2375,7 @@
Game controller D-pad right button.
</constant>
<constant name="JOY_BUTTON_MISC1" value="15" enum="JoyButton">
- Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo capture button.
+ Game controller SDL miscellaneous button. Corresponds to Xbox share button, PS5 microphone button, Nintendo Switch capture button.
</constant>
<constant name="JOY_BUTTON_PADDLE1" value="16" enum="JoyButton">
Game controller SDL paddle 1 button.
@@ -2372,9 +2397,9 @@
</constant>
<constant name="JOY_BUTTON_MAX" value="128" enum="JoyButton">
The maximum number of game controller buttons supported by the engine. The actual limit may be lower on specific platforms:
- - Android: Up to 36 buttons.
- - Linux: Up to 80 buttons.
- - Windows and macOS: Up to 128 buttons.
+ - [b]Android:[/b] Up to 36 buttons.
+ - [b]Linux:[/b] Up to 80 buttons.
+ - [b]Windows[/b] and [b]macOS:[/b] Up to 128 buttons.
</constant>
<constant name="JOY_AXIS_INVALID" value="-1" enum="JoyAxis">
An invalid game controller axis.
@@ -2461,16 +2486,18 @@
MIDI system reset message. Reset all receivers in the system to power-up status. It should not be sent on power-up itself.
</constant>
<constant name="OK" value="0" enum="Error">
- Methods that return [enum Error] return [constant OK] when no error occurred. Note that many functions don't return an error code but will print error messages to standard output.
- Since [constant OK] has value 0, and all other failure codes are positive integers, it can also be used in boolean checks, e.g.:
+ Methods that return [enum Error] return [constant OK] when no error occurred.
+ Since [constant OK] has value 0, and all other error constants are positive integers, it can also be used in boolean checks. For example:
[codeblock]
- var err = method_that_returns_error()
- if err != OK:
- print("Failure!")
- # Or, equivalent:
- if err:
- print("Still failing!")
+ var error = method_that_returns_error()
+ if error != OK:
+ printerr("Failure!")
+
+ # Or, alternatively:
+ if error:
+ printerr("Still failing!")
[/codeblock]
+ [b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
</constant>
<constant name="FAILED" value="1" enum="Error">
Generic error.
@@ -2608,100 +2635,101 @@
Skip error.
</constant>
<constant name="ERR_HELP" value="46" enum="Error">
- Help error.
+ Help error. Used internally when passing [code]--version[/code] or [code]--help[/code] as executable options.
</constant>
<constant name="ERR_BUG" value="47" enum="Error">
- Bug error.
+ Bug error, caused by an implementation issue in the method.
+ [b]Note:[/b] If a built-in method returns this code, please open an issue on [url=https://github.com/godotengine/godot/issues]the GitHub Issue Tracker[/url].
</constant>
<constant name="ERR_PRINTER_ON_FIRE" value="48" enum="Error">
- Printer on fire error. (This is an easter egg, no engine methods return this error code.)
+ Printer on fire error (This is an easter egg, no built-in methods return this error code).
</constant>
<constant name="PROPERTY_HINT_NONE" value="0" enum="PropertyHint">
- No hint for the edited property.
+ The property has no hint for the editor.
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint">
- Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_less"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_less"[/code].
- Additionally, other keywords can be included: [code]"exp"[/code] for exponential range editing, [code]"radians"[/code] for editing radian angles in degrees, [code]"degrees"[/code] to hint at an angle and [code]"no_slider"[/code] to hide the slider.
+ Hints that an [int] or [float] property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_less"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_less"[/code].
+ Additionally, other keywords can be included: [code]"exp"[/code] for exponential range editing, [code]"radians"[/code] for editing radian angles in degrees, [code]"degrees"[/code] to hint at an angle and [code]"hide_slider"[/code] to hide the slider.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint">
- Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
- The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code].
+ Hints that an [int], [float], or [String] property is an enumerated value to pick in a list specified via a hint string.
+ The hint string is a comma separated list of names such as [code]"Hello,Something,Else"[/code]. Whitespaces are [b]not[/b] removed from either end of a name. For integer and float properties, the first name in the list has value 0, the next 1, and so on. Explicit values can also be specified by appending [code]:integer[/code] to the name, e.g. [code]"Zero,One,Three:3,Four,Six:6"[/code].
</constant>
<constant name="PROPERTY_HINT_ENUM_SUGGESTION" value="3" enum="PropertyHint">
- Hints that a string property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
- Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
+ Hints that a [String] property can be an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code].
+ Unlike [constant PROPERTY_HINT_ENUM], a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
</constant>
<constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint">
- Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"positive_only"[/code] to exclude in/out easing and limit values to be greater than or equal to zero.
+ Hints that a [float] property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"positive_only"[/code] to exclude in/out easing and limit values to be greater than or equal to zero.
</constant>
<constant name="PROPERTY_HINT_LINK" value="5" enum="PropertyHint">
- Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together).
+ Hints that a vector property should allow its components to be linked. For example, this allows [member Vector2.x] and [member Vector2.y] to be edited together.
</constant>
<constant name="PROPERTY_HINT_FLAGS" value="6" enum="PropertyHint">
- Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
+ Hints that an [int] property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code].
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="7" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D render layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D render layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="8" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D physics layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D physics layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="9" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 2D navigation layers.
+ Hints that an [int] property is a bitmask using the optionally named 2D navigation layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="10" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D render layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D render layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="11" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D physics layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D physics layers.
</constant>
<constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="12" enum="PropertyHint">
- Hints that an integer property is a bitmask using the optionally named 3D navigation layers.
+ Hints that an [int] property is a bitmask using the optionally named 3D navigation layers.
</constant>
<constant name="PROPERTY_HINT_FILE" value="13" enum="PropertyHint">
- Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
+ Hints that a [String] property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
</constant>
<constant name="PROPERTY_HINT_DIR" value="14" enum="PropertyHint">
- Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path.
+ Hints that a [String] property is a path to a directory. Editing it will show a file dialog for picking the path.
</constant>
<constant name="PROPERTY_HINT_GLOBAL_FILE" value="15" enum="PropertyHint">
- Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code].
+ Hints that a [String] property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards, like [code]"*.png,*.jpg"[/code].
</constant>
<constant name="PROPERTY_HINT_GLOBAL_DIR" value="16" enum="PropertyHint">
- Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
+ Hints that a [String] property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path.
</constant>
<constant name="PROPERTY_HINT_RESOURCE_TYPE" value="17" enum="PropertyHint">
Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture2D"[/code]). Editing it will show a popup menu of valid resource types to instantiate.
</constant>
<constant name="PROPERTY_HINT_MULTILINE_TEXT" value="18" enum="PropertyHint">
- Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
+ Hints that a [String] property is text with line breaks. Editing it will show a text input field where line breaks can be typed.
</constant>
<constant name="PROPERTY_HINT_EXPRESSION" value="19" enum="PropertyHint">
- Hints that a string property is an [Expression].
+ Hints that a [String] property is an [Expression].
</constant>
<constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="20" enum="PropertyHint">
- Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use.
+ Hints that a [String] property should show a placeholder text on its input field, if empty. The hint string is the placeholder text to use.
</constant>
<constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="21" enum="PropertyHint">
- Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited.
+ Hints that a [Color] property should be edited without affecting its transparency ([member Color.a] is not editable).
</constant>
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="22" enum="PropertyHint">
- Hints that an image is compressed using lossy compression.
+ Hints that an image is compressed using lossy compression. The editor does not internally use this property hint.
</constant>
<constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint">
- Hints that an image is compressed using lossless compression.
+ Hints that an image is compressed using lossless compression. The editor does not internally use this property hint.
</constant>
<constant name="PROPERTY_HINT_OBJECT_ID" value="24" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_TYPE_STRING" value="25" enum="PropertyHint">
- Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance:
+ Hints that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For example:
[codeblock]
- hint_string = "%s:" % [TYPE_INT] # Array of inteters.
+ hint_string = "%s:" % [TYPE_INT] # Array of integers.
hint_string = "%s:%s:" % [TYPE_ARRAY, TYPE_REAL] # Two-dimensional array of floats.
hint_string = "%s/%s:Resource" % [TYPE_OBJECT, TYPE_OBJECT] # Array of resources.
hint_string = "%s:%s/%s:Resource" % [TYPE_ARRAY, TYPE_OBJECT, TYPE_OBJECT] # Two-dimensional array of resources.
[/codeblock]
- [b]Note:[/b] The final colon is required to specify for properly detecting built-in types.
+ [b]Note:[/b] The final colon is required for properly detecting built-in types.
</constant>
<constant name="PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE" value="26" enum="PropertyHint">
</constant>
@@ -2722,6 +2750,7 @@
<constant name="PROPERTY_HINT_PROPERTY_OF_SCRIPT" value="34" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_OBJECT_TOO_BIG" value="35" enum="PropertyHint">
+ Hints that a property's size (in bytes) is too big to be displayed, when debugging a running project. The debugger uses this hint internally.
</constant>
<constant name="PROPERTY_HINT_NODE_PATH_VALID_TYPES" value="36" enum="PropertyHint">
</constant>
@@ -2731,39 +2760,42 @@
</constant>
<constant name="PROPERTY_HINT_INT_IS_OBJECTID" value="39" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_INT_IS_POINTER" value="41" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_INT_IS_POINTER" value="40" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_ARRAY_TYPE" value="40" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_ARRAY_TYPE" value="41" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_LOCALE_ID" value="42" enum="PropertyHint">
- Hints that a string property is a locale code. Editing it will show a locale dialog for picking language and country.
+ Hints that a [String] property is a locale code. Editing it will show a locale dialog for picking language and country.
</constant>
<constant name="PROPERTY_HINT_LOCALIZABLE_STRING" value="43" enum="PropertyHint">
- Hints that a dictionary property is string translation map. Dictionary keys are locale codes and, values are translated strings.
+ Hints that a [Dictionary] property is string translation map. Dictionary keys are locale codes and, values are translated strings.
</constant>
<constant name="PROPERTY_HINT_NODE_TYPE" value="44" enum="PropertyHint">
</constant>
<constant name="PROPERTY_HINT_HIDE_QUATERNION_EDIT" value="45" enum="PropertyHint">
- Hints that a quaternion property should disable the temporary euler editor.
+ Hints that a [Quaternion] property should disable the temporary euler editor.
</constant>
<constant name="PROPERTY_HINT_PASSWORD" value="46" enum="PropertyHint">
- Hints that a string property is a password, and every character is replaced with the secret character.
+ Hints that a [String] property is a password. Every character of the string is displayed as the secret character (typically [code]*[/code]).
+ An optional placeholder text can be shown on its input field, similarly to [constant PROPERTY_HINT_PLACEHOLDER_TEXT].
</constant>
<constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">
+ Represents the size of the [enum PropertyHint] enum.
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
+ The property is not stored, and does not display in the editor. This is the default for non-exported properties.
</constant>
<constant name="PROPERTY_USAGE_STORAGE" value="2" enum="PropertyUsageFlags">
The property is serialized and saved in the scene file (default).
</constant>
<constant name="PROPERTY_USAGE_EDITOR" value="4" enum="PropertyUsageFlags">
- The property is shown in the editor inspector (default).
+ The property is shown in the [EditorInspector] (default).
</constant>
<constant name="PROPERTY_USAGE_CHECKABLE" value="8" enum="PropertyUsageFlags">
- The property can be checked in the editor inspector.
+ The property can be checked in the [EditorInspector].
</constant>
<constant name="PROPERTY_USAGE_CHECKED" value="16" enum="PropertyUsageFlags">
- The property is checked in the editor inspector.
+ The property is checked in the [EditorInspector].
</constant>
<constant name="PROPERTY_USAGE_INTERNATIONALIZED" value="32" enum="PropertyUsageFlags">
The property is a translatable string.
@@ -2803,8 +2835,10 @@
<constant name="PROPERTY_USAGE_INTERNAL" value="524288" enum="PropertyUsageFlags">
</constant>
<constant name="PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE" value="1048576" enum="PropertyUsageFlags">
+ If the property is a [Resource], a new copy of it is always created when calling [method Node.duplicate] or [method Resource.duplicate].
</constant>
<constant name="PROPERTY_USAGE_HIGH_END_GFX" value="2097152" enum="PropertyUsageFlags">
+ The property is only shown in the editor if modern renderers are supported (GLES3 is excluded).
</constant>
<constant name="PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT" value="4194304" enum="PropertyUsageFlags">
</constant>
@@ -2819,9 +2853,10 @@
<constant name="PROPERTY_USAGE_EDITOR_BASIC_SETTING" value="134217728" enum="PropertyUsageFlags">
</constant>
<constant name="PROPERTY_USAGE_READ_ONLY" value="268435456" enum="PropertyUsageFlags">
- The property is read-only in the editor inspector.
+ The property is read-only in the [EditorInspector].
</constant>
<constant name="PROPERTY_USAGE_ARRAY" value="536870912" enum="PropertyUsageFlags">
+ The property is an array.
</constant>
<constant name="PROPERTY_USAGE_DEFAULT" value="6" enum="PropertyUsageFlags">
Default usage (storage, editor and network).
@@ -2845,14 +2880,16 @@
Flag for a virtual method.
</constant>
<constant name="METHOD_FLAG_VARARG" value="16" enum="MethodFlags">
+ Flag for a method with a variable number of arguments.
</constant>
<constant name="METHOD_FLAG_STATIC" value="32" enum="MethodFlags">
+ Flag for a static method.
</constant>
<constant name="METHOD_FLAG_OBJECT_CORE" value="64" enum="MethodFlags">
- Used internally. Allows to not dump core virtuals such as [code]_notification[/code] to the JSON API.
+ Used internally. Allows to not dump core virtual methods (such as [method Object._notification]) to the JSON API.
</constant>
<constant name="METHOD_FLAGS_DEFAULT" value="1" enum="MethodFlags">
- Default method flags.
+ Default method flags (normal).
</constant>
<constant name="TYPE_NIL" value="0" enum="Variant.Type">
Variable is [code]null[/code].
@@ -2864,7 +2901,7 @@
Variable is of type [int].
</constant>
<constant name="TYPE_FLOAT" value="3" enum="Variant.Type">
- Variable is of type [float] (real).
+ Variable is of type [float].
</constant>
<constant name="TYPE_STRING" value="4" enum="Variant.Type">
Variable is of type [String].
@@ -2891,8 +2928,10 @@
Variable is of type [Transform2D].
</constant>
<constant name="TYPE_VECTOR4" value="12" enum="Variant.Type">
+ Variable is of type [Vector4].
</constant>
<constant name="TYPE_VECTOR4I" value="13" enum="Variant.Type">
+ Variable is of type [Vector4i].
</constant>
<constant name="TYPE_PLANE" value="14" enum="Variant.Type">
Variable is of type [Plane].
@@ -2910,6 +2949,7 @@
Variable is of type [Transform3D].
</constant>
<constant name="TYPE_PROJECTION" value="19" enum="Variant.Type">
+ Variable is of type [Projection].
</constant>
<constant name="TYPE_COLOR" value="20" enum="Variant.Type">
Variable is of type [Color].
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 23dd41f275..ca454cafa3 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -188,6 +188,7 @@
<param index="0" name="from" type="Vector3" />
<param index="1" name="dir" type="Vector3" />
<description>
+ Returns [code]true[/code] if the given ray intersects with this [AABB]. Ray length is infinite.
</description>
</method>
<method name="intersects_segment" qualifiers="const">
@@ -205,6 +206,12 @@
Returns [code]true[/code] if this [AABB] and [param aabb] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this [AABB] is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="merge" qualifiers="const">
<return type="AABB" />
<param index="0" name="with" type="AABB" />
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index 6e76df647e..2414b068e6 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -271,7 +271,7 @@
<return type="void" />
<param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, such as points on a grid. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index 45b1019bab..4e8394195d 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -298,7 +298,7 @@
<return type="void" />
<param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points. Useful if you're adding a known large number of points at once, such as points on a grid. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index df0fb11ac7..008296713d 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -26,6 +26,7 @@
[/csharp]
[/codeblocks]
Animations are just data containers, and must be added to nodes such as an [AnimationPlayer] to be played back. Animation tracks have different types, each with its own set of dedicated methods. Check [enum TrackType] to see available types.
+ [b]Note:[/b] For 3D position/rotation/scale, using the dedicated [constant TYPE_POSITION_3D], [constant TYPE_ROTATION_3D] and [constant TYPE_SCALE_3D] track types instead of [constant TYPE_VALUE] is recommended for performance reasons.
</description>
<tutorials>
<link title="Animation documentation index">$DOCS_URL/tutorials/animation/index.html</link>
@@ -209,6 +210,7 @@
<param index="1" name="time" type="float" />
<param index="2" name="amount" type="float" />
<description>
+ Inserts a key in a given blend shape track. Returns the key index.
</description>
</method>
<method name="clear">
@@ -223,6 +225,8 @@
<param index="1" name="fps" type="int" default="120" />
<param index="2" name="split_tolerance" type="float" default="4.0" />
<description>
+ Compress the animation and all its tracks in-place. This will make [method track_is_compressed] return [code]true[/code] once called on this [Animation]. Compressed tracks require less memory to be played, and are designed to be used for complex 3D animations (such as cutscenes) imported from external 3D software. Compression is lossy, but the difference is usually not noticeable in real world conditions.
+ [b]Note:[/b] Compressed tracks have various limitations (such as not being editable from the editor), so only use compressed animations if you actually need them.
</description>
</method>
<method name="copy_track">
@@ -278,6 +282,7 @@
<param index="1" name="time" type="float" />
<param index="2" name="position" type="Vector3" />
<description>
+ Inserts a key in a given 3D position track. Returns the key index.
</description>
</method>
<method name="remove_track">
@@ -293,6 +298,7 @@
<param index="1" name="time" type="float" />
<param index="2" name="rotation" type="Quaternion" />
<description>
+ Inserts a key in a given 3D rotation track. Returns the key index.
</description>
</method>
<method name="scale_track_insert_key">
@@ -301,6 +307,7 @@
<param index="1" name="time" type="float" />
<param index="2" name="scale" type="Vector3" />
<description>
+ Inserts a key in a given 3D scale track. Returns the key index.
</description>
</method>
<method name="track_find_key" qualifiers="const">
@@ -385,6 +392,7 @@
<return type="bool" />
<param index="0" name="track_idx" type="int" />
<description>
+ Returns [code]true[/code] if the track is compressed, [code]false[/code] otherwise. See also [method compress].
</description>
</method>
<method name="track_is_enabled" qualifiers="const">
@@ -569,15 +577,19 @@
</signals>
<constants>
<constant name="TYPE_VALUE" value="0" enum="TrackType">
- Value tracks set values in node properties, but only those which can be Interpolated.
+ Value tracks set values in node properties, but only those which can be interpolated. For 3D position/rotation/scale, using the dedicated [constant TYPE_POSITION_3D], [constant TYPE_ROTATION_3D] and [constant TYPE_SCALE_3D] track types instead of [constant TYPE_VALUE] is recommended for performance reasons.
</constant>
<constant name="TYPE_POSITION_3D" value="1" enum="TrackType">
+ 3D position track (values are stored in [Vector3]s).
</constant>
<constant name="TYPE_ROTATION_3D" value="2" enum="TrackType">
+ 3D rotation track (values are stored in [Quaternion]s).
</constant>
<constant name="TYPE_SCALE_3D" value="3" enum="TrackType">
+ 3D scale track (values are stored in [Vector3]s).
</constant>
<constant name="TYPE_BLEND_SHAPE" value="4" enum="TrackType">
+ Blend shape track.
</constant>
<constant name="TYPE_METHOD" value="5" enum="TrackType">
Method tracks call functions with given arguments per key.
@@ -598,7 +610,7 @@
Linear interpolation.
</constant>
<constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType">
- Cubic interpolation.
+ Cubic interpolation. This looks smoother than linear interpolation, but is more expensive to interpolate. Stick to [constant INTERPOLATION_LINEAR] for complex 3D animations imported from external software, even if it requires using a higher animation framerate in return.
</constant>
<constant name="INTERPOLATION_LINEAR_ANGLE" value="3" enum="InterpolationType">
Linear interpolation with shortest path rotation.
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 1b5a795b3c..4c2a30030b 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -22,9 +22,6 @@
<member name="advance_expression" type="String" setter="set_advance_expression" getter="get_advance_expression" default="&quot;&quot;">
Use an expression as a condition for state machine transitions. It is possible to create complex animation advance conditions for switching between states and gives much greater flexibility for creating complex state machines by directly interfacing with the script code.
</member>
- <member name="advance_expression_base_node" type="NodePath" setter="set_advance_expression_base_node" getter="get_advance_expression_base_node" default="NodePath(&quot;&quot;)">
- The path to the [Node] used to evaluate an [Expression] if one is not explicitly specified internally.
- </member>
<member name="auto_advance" type="bool" setter="set_auto_advance" getter="has_auto_advance" default="false">
Turn on the transition automatically when this state is reached. This works best with [constant SWITCH_MODE_AT_END].
</member>
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index b7ac1ff7f8..9efd3ac939 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -217,7 +217,7 @@
</member>
<member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation" default="&quot;&quot;">
The key of the currently playing animation. If no animation is playing, the property's value is an empty string. Changing this value does not restart the animation. See [method play] for more information on playing animations.
- [b]Note:[/b] while this property appears in the inspector, it's not meant to be edited, and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
+ [b]Note:[/b] While this property appears in the Inspector, it's not meant to be edited, and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
</member>
<member name="current_animation_length" type="float" setter="" getter="get_current_animation_length">
The length (in seconds) of the currently playing animation.
@@ -242,7 +242,7 @@
The process notification in which to update animations.
</member>
<member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The speed scaling ratio. For instance, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
+ The speed scaling ratio. For example, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
</member>
<member name="reset_on_save" type="bool" setter="set_reset_on_save_enabled" getter="is_reset_on_save_enabled" default="true">
This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation (the animation with the key [code]"RESET"[/code]) applied as if it had been seeked to time 0, with the editor keeping the values that the scene had before saving.
@@ -268,6 +268,11 @@
[b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
+ <signal name="animation_libraries_updated">
+ <description>
+ Notifies when the animation libraries have changed.
+ </description>
+ </signal>
<signal name="animation_list_changed">
<description>
Notifies when an animation list is changed.
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index ce49be9bc1..ea8cab324d 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -110,11 +110,11 @@
<member name="reverb_bus_amount" type="float" setter="set_reverb_amount" getter="get_reverb_amount" default="0.0">
The degree to which this area applies reverb to its associated audio. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
</member>
- <member name="reverb_bus_enable" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus" default="false">
+ <member name="reverb_bus_enabled" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus" default="false">
If [code]true[/code], the area applies reverb to its associated audio.
</member>
- <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="&amp;&quot;Master&quot;">
- The reverb bus name to use for this area's associated audio.
+ <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus_name" getter="get_reverb_bus_name" default="&amp;&quot;Master&quot;">
+ The name of the reverb bus to use for this area's associated audio.
</member>
<member name="reverb_bus_uniformity" type="float" setter="set_reverb_uniformity" getter="get_reverb_uniformity" default="0.0">
The degree to which this area's reverb is a uniform effect. Ranges from [code]0[/code] to [code]1[/code] with [code]0.1[/code] precision.
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index d8c4b8fdb5..b8e0ac0c2a 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -58,6 +58,7 @@
<param index="2" name="class_name" type="StringName" />
<param index="3" name="script" type="Variant" />
<description>
+ Creates a typed array from the [param base] array. The base array can't be already typed. See [method set_typed] for more details.
</description>
</constructor>
<constructor name="Array">
@@ -271,6 +272,7 @@
array.Fill(0); // Initialize the 10 elements to 0.
[/csharp]
[/codeblocks]
+ [b]Note:[/b] If [param value] is of a reference type ([Object]-derived, [Array], [Dictionary], etc.) then the array is filled with the references to the same object, i.e. no duplicates are created.
</description>
</method>
<method name="filter" qualifiers="const">
@@ -315,16 +317,19 @@
<method name="get_typed_builtin" qualifiers="const">
<return type="int" />
<description>
+ Returns the [code]TYPE[/code] constant for a typed array. If the [Array] is not typed, returns [constant @GlobalScope.TYPE_NIL].
</description>
</method>
<method name="get_typed_class_name" qualifiers="const">
<return type="StringName" />
<description>
+ Returns a class name of a typed [Array] of type [constant @GlobalScope.TYPE_OBJECT].
</description>
</method>
<method name="get_typed_script" qualifiers="const">
<return type="Variant" />
<description>
+ Returns the script associated with a typed array tied to a class name.
</description>
</method>
<method name="has" qualifiers="const">
@@ -393,11 +398,13 @@
<method name="is_read_only" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the array is read-only. See [method set_read_only]. Arrays are automatically read-only if declared with [code]const[/code] keyword.
</description>
</method>
<method name="is_typed" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the array is typed. Typed arrays can only store elements of their associated type and provide type safety for the [code][][/code] operator. Methods of typed array still return [Variant].
</description>
</method>
<method name="map" qualifiers="const">
@@ -429,6 +436,16 @@
Returns the minimum value contained in the array if all elements are of comparable types. If the elements can't be compared, [code]null[/code] is returned.
</description>
</method>
+ <method name="pick_random" qualifiers="const">
+ <return type="Variant" />
+ <description>
+ Returns a random value from the target array.
+ [codeblock]
+ var array: Array[int] = [1, 2, 3, 4]
+ print(array.pick_random()) # Prints either of the four numbers.
+ [/codeblock]
+ </description>
+ </method>
<method name="pop_at">
<return type="Variant" />
<param index="0" name="position" type="int" />
@@ -517,6 +534,7 @@
<return type="void" />
<param index="0" name="enable" type="bool" />
<description>
+ Makes the [Array] read-only, i.e. disabled modifying of the array's elements. Does not apply to nested content, e.g. content of nested arrays.
</description>
</method>
<method name="set_typed">
@@ -525,6 +543,8 @@
<param index="1" name="class_name" type="StringName" />
<param index="2" name="script" type="Variant" />
<description>
+ Makes the [Array] typed. The [param type] should be one of the [@GlobalScope] [code]TYPE[/code] constants. [param class_name] is optional and can only be provided for [constant @GlobalScope.TYPE_OBJECT]. [param script] can only be provided if [param class_name] is not empty.
+ The method fails if an array is already typed.
</description>
</method>
<method name="shuffle">
@@ -557,6 +577,7 @@
<return type="void" />
<description>
Sorts the array.
+ [b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/wiki/Sorting_algorithm#Stability]stable[/url]. This means that values considered equal may have their order changed when using [method sort].
[b]Note:[/b] Strings are sorted in alphabetical order (as opposed to natural order). This may lead to unexpected behavior when sorting an array of strings ending with a sequence of numbers. Consider the following example:
[codeblocks]
[gdscript]
@@ -581,7 +602,8 @@
<param index="0" name="func" type="Callable" />
<description>
Sorts the array using a custom method. The custom method receives two arguments (a pair of elements from the array) and must return either [code]true[/code] or [code]false[/code]. For two elements [code]a[/code] and [code]b[/code], if the given method returns [code]true[/code], element [code]b[/code] will be after element [code]a[/code] in the array.
- [b]Note:[/b] You cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior.
+ [b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/wiki/Sorting_algorithm#Stability]stable[/url]. This means that values considered equal may have their order changed when using [method sort_custom].
+ [b]Note:[/b] You cannot randomize the return value as the heapsort algorithm expects a deterministic result. Randomizing the return value will result in unexpected behavior.
[codeblocks]
[gdscript]
func sort_ascending(a, b):
@@ -608,6 +630,7 @@
<return type="bool" />
<param index="0" name="array" type="Array" />
<description>
+ Assigns a different [Array] to this array reference. It the array is typed, the new array's type must be compatible and its elements will be automatically converted.
</description>
</method>
</methods>
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 759acff773..809d983a9d 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -1,26 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AtlasTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Crops out one part of a texture, such as a texture from a texture atlas.
+ A texture that crops out part of another Texture2D.
</brief_description>
<description>
- [Texture2D] resource that crops out one part of the [member atlas] texture, defined by [member region]. The main use case is cropping out textures from a texture atlas, which is a big texture file that packs multiple smaller textures. Consists of a [Texture2D] for the [member atlas], a [member region] that defines the area of [member atlas] to use, and a [member margin] that defines the border width.
- [AtlasTexture] cannot be used in an [AnimatedTexture], cannot be tiled in nodes such as [TextureRect], and does not work properly if used inside of other [AtlasTexture] resources. Multiple [AtlasTexture] resources can be used to crop multiple textures from the atlas. Using a texture atlas helps to optimize video memory costs and render calls compared to using multiple small files.
+ [Texture2D] resource that draws only part of its [member atlas] texture, as defined by the [member region]. An additional [member margin] can also be set, which is useful for small adjustments.
+ Multiple [AtlasTexture] resources can be cropped from the same [member atlas]. Packing many smaller textures into a singular large texture helps to optimize video memory costs and render calls.
+ [b]Note:[/b] [AtlasTexture] cannot be used in an [AnimatedTexture], and may not tile properly in nodes such as [TextureRect], when inside other [AtlasTexture] resources.
</description>
<tutorials>
</tutorials>
<members>
<member name="atlas" type="Texture2D" setter="set_atlas" getter="get_atlas">
- The texture that contains the atlas. Can be any [Texture2D] subtype.
+ The texture that contains the atlas. Can be any type inheriting from [Texture2D], including another [AtlasTexture].
</member>
<member name="filter_clip" type="bool" setter="set_filter_clip" getter="has_filter_clip" default="false">
- If [code]true[/code], clips the area outside of the region to avoid bleeding of the surrounding texture pixels.
+ If [code]true[/code], the area outside of the [member region] is clipped to avoid bleeding of the surrounding texture pixels.
</member>
<member name="margin" type="Rect2" setter="set_margin" getter="get_margin" default="Rect2(0, 0, 0, 0)">
- The margin around the region. The [Rect2]'s [member Rect2.size] parameter ("w" and "h" in the editor) resizes the texture so it fits within the margin.
+ The margin around the [member region]. Useful for small adjustments. If the [member Rect2.size] of this property ("w" and "h" in the editor) is set, the drawn texture is resized to fit within the margin.
</member>
<member name="region" type="Rect2" setter="set_region" getter="get_region" default="Rect2(0, 0, 0, 0)">
- The AtlasTexture's used region.
+ The region used to draw the [member atlas].
</member>
</members>
</class>
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index 1c02dbd3ce..c16198c5c6 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -27,7 +27,7 @@
<method name="get_frames_available" qualifiers="const">
<return type="int" />
<description>
- Returns the number of audio data frames left to play. If this returned number reaches [code]0[/code], the audio will stop playing until frames are added again. Therefore, make sure your script can always generate and push new audio frames fast enough to avoid audio cracking.
+ Returns the number of frames that can be pushed to the audio sample data buffer without overflowing it. If the result is [code]0[/code], the buffer is full.
</description>
</method>
<method name="get_skips" qualifiers="const">
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 02192a9b7c..11d6e9cc7a 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -7,7 +7,7 @@
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space. For greater realism, a low-pass filter is automatically applied to distant sounds. This can be disabled by setting [member attenuation_filter_cutoff_hz] to [code]20500[/code].
By default, audio is heard from the camera position. This can be changed by adding an [AudioListener3D] node to the scene and enabling it by calling [method AudioListener3D.make_current] on it.
See also [AudioStreamPlayer] to play a sound non-positionally.
- [b]Note:[/b] Hiding an [AudioStreamPlayer3D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer3D]'s audio output, set [member unit_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
+ [b]Note:[/b] Hiding an [AudioStreamPlayer3D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer3D]'s audio output, set [member volume_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
<tutorials>
<link title="Audio streams">$DOCS_URL/tutorials/audio/audio_streams.html</link>
@@ -102,12 +102,12 @@
<member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false">
If [code]true[/code], the playback is paused. You can resume it by setting [member stream_paused] to [code]false[/code].
</member>
- <member name="unit_db" type="float" setter="set_unit_db" getter="get_unit_db" default="0.0">
- The base sound level unaffected by dampening, in decibels.
- </member>
<member name="unit_size" type="float" setter="set_unit_size" getter="get_unit_size" default="10.0">
The factor for the attenuation effect. Higher values make the sound audible over a larger distance.
</member>
+ <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db" default="0.0">
+ The base sound level unaffected by dampening, in decibels.
+ </member>
</members>
<signals>
<signal name="finished">
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 629675132a..638934bc9e 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -68,8 +68,8 @@
<member name="shortcut" type="Shortcut" setter="set_shortcut" getter="get_shortcut">
[Shortcut] associated to the button.
</member>
- <member name="shortcut_context" type="Node" setter="set_shortcut_context" getter="get_shortcut_context">
- The [Node] which must be a parent of the focused GUI [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
+ <member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback">
+ If [code]true[/code], the button will appear pressed when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate the button without appearing to press the button.
</member>
<member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled">
If [code]true[/code], the button will add information about its shortcut in the tooltip.
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index cbb58a3e1e..de980eab0c 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -115,7 +115,7 @@
The color used by the backlight effect. Represents the light passing through an object.
</member>
<member name="backlight_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
- If [code]true[/code], the backlight effect is enabled.
+ If [code]true[/code], the backlight effect is enabled. See also [member subsurf_scatter_transmittance_enabled].
</member>
<member name="backlight_texture" type="Texture2D" setter="set_texture" getter="get_texture">
Texture used to control the backlight effect per-pixel. Added to [member backlight].
@@ -289,6 +289,7 @@
[b]Note:[/b] If [member detail_enabled] is [code]true[/code], the [member detail_albedo] texture is drawn [i]below[/i] the [member normal_texture]. To display a normal map [i]above[/i] the [member detail_albedo] texture, use [member detail_normal] instead.
</member>
<member name="orm_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ The Occlusion/Roughness/Metallic texture to use. This is a more efficient replacement of [member ao_texture], [member roughness_texture] and [member metallic_texture] in [ORMMaterial3D]. Ambient occlusion is stored in the red channel. Roughness map is stored in the green channel. Metallic map is stored in the blue channel. The alpha channel is ignored.
</member>
<member name="particles_anim_h_frames" type="int" setter="set_particles_anim_h_frames" getter="get_particles_anim_h_frames">
The number of horizontal frames in the particle sprite sheet. Only enabled when using [constant BILLBOARD_PARTICLES]. See [member billboard_mode].
@@ -305,7 +306,7 @@
<member name="proximity_fade_distance" type="float" setter="set_proximity_fade_distance" getter="get_proximity_fade_distance" default="1.0">
Distance over which the fade effect takes place. The larger the distance the longer it takes for an object to fade.
</member>
- <member name="proximity_fade_enable" type="bool" setter="set_proximity_fade" getter="is_proximity_fade_enabled" default="false">
+ <member name="proximity_fade_enabled" type="bool" setter="set_proximity_fade_enabled" getter="is_proximity_fade_enabled" default="false">
If [code]true[/code], the proximity fade effect is enabled. The proximity fade effect fades out each pixel based on its distance to another object.
</member>
<member name="refraction_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
@@ -350,13 +351,13 @@
</member>
<member name="specular_mode" type="int" setter="set_specular_mode" getter="get_specular_mode" enum="BaseMaterial3D.SpecularMode" default="0">
The method for rendering the specular blob. See [enum SpecularMode].
- [b]Note:[/b] Only applies to the specular blob. Does not affect specular reflections from the Sky, SSR, or ReflectionProbes.
+ [b]Note:[/b] [member specular_mode] only applies to the specular blob. It does not affect specular reflections from the sky, screen-space reflections, [VoxelGI], SDFGI or [ReflectionProbe]s. To disable reflections from these sources as well, set [member metallic_specular] to [code]0.0[/code] instead.
</member>
<member name="subsurf_scatter_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
If [code]true[/code], subsurface scattering is enabled. Emulates light that penetrates an object's surface, is scattered, and then emerges.
</member>
<member name="subsurf_scatter_skin_mode" type="bool" setter="set_flag" getter="get_flag" default="false">
- If [code]true[/code], subsurface scattering will use a special mode optimized for the color and density of human skin.
+ If [code]true[/code], subsurface scattering will use a special mode optimized for the color and density of human skin, such as boosting the intensity of the red channel in subsurface scattering.
</member>
<member name="subsurf_scatter_strength" type="float" setter="set_subsurface_scattering_strength" getter="get_subsurface_scattering_strength" default="0.0">
The strength of the subsurface scattering effect.
@@ -365,14 +366,19 @@
Texture used to control the subsurface scattering strength. Stored in the red texture channel. Multiplied by [member subsurf_scatter_strength].
</member>
<member name="subsurf_scatter_transmittance_boost" type="float" setter="set_transmittance_boost" getter="get_transmittance_boost" default="0.0">
+ The intensity of the subsurface scattering transmittance effect.
</member>
<member name="subsurf_scatter_transmittance_color" type="Color" setter="set_transmittance_color" getter="get_transmittance_color" default="Color(1, 1, 1, 1)">
+ The color to multiply the subsurface scattering transmittance effect with. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code].
</member>
<member name="subsurf_scatter_transmittance_depth" type="float" setter="set_transmittance_depth" getter="get_transmittance_depth" default="0.1">
+ The depth of the subsurface scattering transmittance effect.
</member>
<member name="subsurf_scatter_transmittance_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
+ If [code]true[/code], enables subsurface scattering transmittance. Only effective if [member subsurf_scatter_enabled] is [code]true[/code]. See also [member backlight_enabled].
</member>
<member name="subsurf_scatter_transmittance_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ The texture to use for multiplying the intensity of the subsurface scattering transmitteance intensity. See also [member subsurf_scatter_texture]. Ignored if [member subsurf_scatter_skin_mode] is [code]true[/code].
</member>
<member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="BaseMaterial3D.TextureFilter" default="3">
Filter flags for the texture. See [enum TextureFilter] for options.
@@ -385,6 +391,7 @@
If [code]true[/code], transparency is enabled on the body. See also [member blend_mode].
</member>
<member name="use_particle_trails" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], enables parts of the shader required for [GPUParticles3D] trails to function. This also requires using a mesh with appropriate skinning, such as [RibbonTrailMesh] or [TubeTrailMesh]. Enabling this feature outside of materials used in [GPUParticles3D] meshes will break material rendering.
</member>
<member name="use_point_size" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], render point size can be changed.
@@ -682,6 +689,7 @@
Enables the skin mode for subsurface scattering which is used to improve the look of subsurface scattering when used for human skin.
</constant>
<constant name="FLAG_PARTICLE_TRAILS_MODE" value="19" enum="Flags">
+ Enables parts of the shader required for [GPUParticles3D] trails to function. This also requires using a mesh with appropriate skinning, such as [RibbonTrailMesh] or [TubeTrailMesh]. Enabling this feature outside of materials used in [GPUParticles3D] meshes will break material rendering.
</constant>
<constant name="FLAG_ALBEDO_TEXTURE_MSDF" value="20" enum="Flags">
Enables multichannel signed distance field rendering shader.
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 6d9b679fbc..652d6d2407 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -70,6 +70,7 @@
<param index="0" name="euler" type="Vector3" />
<param index="1" name="order" type="int" default="2" />
<description>
+ Constructs a pure rotation Basis matrix from Euler angles in the specified Euler rotation order. By default, use YXZ order (most common).
</description>
</method>
<method name="from_scale" qualifiers="static">
@@ -112,6 +113,12 @@
Returns [code]true[/code] if this basis and [param b] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this basis is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="static">
<return type="Basis" />
<param index="0" name="target" type="Vector3" />
@@ -191,16 +198,22 @@
</members>
<constants>
<constant name="EULER_ORDER_XYZ" value="0">
+ Euler angle composing/decomposing order where X component is first, then Y, then Z.
</constant>
<constant name="EULER_ORDER_XZY" value="1">
+ Euler angle composing/decomposing order where X component is first, then Z, then Y.
</constant>
<constant name="EULER_ORDER_YXZ" value="2">
+ Euler angle composing/decomposing order where Y component is first, then X, then Z.
</constant>
<constant name="EULER_ORDER_YZX" value="3">
+ Euler angle composing/decomposing order where Y component is first, then Z, then X.
</constant>
<constant name="EULER_ORDER_ZXY" value="4">
+ Euler angle composing/decomposing order where Z component is first, then X, then Y.
</constant>
<constant name="EULER_ORDER_ZYX" value="5">
+ Euler angle composing/decomposing order where Z component is first, then Y, then X.
</constant>
<constant name="IDENTITY" value="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)">
The identity basis, with no rotation or scaling applied.
diff --git a/doc/classes/BoneMap.xml b/doc/classes/BoneMap.xml
index f7a4845b7d..7135406d3c 100644
--- a/doc/classes/BoneMap.xml
+++ b/doc/classes/BoneMap.xml
@@ -8,6 +8,7 @@
By assigning the actual [Skeleton3D] bone name as the key value, it maps the [Skeleton3D] to the [SkeletonProfile].
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<methods>
<method name="find_profile_bone_name" qualifiers="const">
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index e78cdfc951..1ff51b48be 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -11,7 +11,7 @@
func _ready():
var button = Button.new()
button.text = "Click me"
- button.connect("pressed", self, "_button_pressed")
+ button.pressed.connect(self._button_pressed)
add_child(button)
func _button_pressed():
@@ -22,7 +22,7 @@
{
var button = new Button();
button.Text = "Click me";
- button.Connect("pressed", this, nameof(ButtonPressed));
+ button.Pressed += ButtonPressed;
AddChild(button);
}
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 906789d09f..314e46d9d0 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -29,12 +29,14 @@
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
+ Returns the maximum value range for the given parameter.
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
+ Returns the minimum value range for the given parameter.
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
@@ -63,6 +65,7 @@
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<param index="1" name="value" type="float" />
<description>
+ Sets the maximum value for the given parameter.
</description>
</method>
<method name="set_param_min">
@@ -70,6 +73,7 @@
<param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<param index="1" name="value" type="float" />
<description>
+ Sets the minimum value for the given parameter.
</description>
</method>
<method name="set_particle_flag">
@@ -89,29 +93,38 @@
Each particle's rotation will be animated along this [Curve].
</member>
<member name="angle_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial rotation applied to each particle, in degrees.
</member>
<member name="angle_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member angle_max].
</member>
<member name="angular_velocity_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's angular velocity will vary along this [Curve].
</member>
<member name="angular_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second.
</member>
<member name="angular_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member angular_velocity_max].
</member>
<member name="anim_offset_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's animation offset will vary along this [Curve].
</member>
<member name="anim_offset_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum animation offset that corresponds to frame index in the texture. [code]0[/code] is the first frame, [code]1[/code] is the last one. See [member CanvasItemMaterial.particles_animation].
</member>
<member name="anim_offset_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member anim_offset_max].
</member>
<member name="anim_speed_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Each particle's animation speed will vary along this [Curve].
</member>
<member name="anim_speed_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum particle animation speed. Animation speed of [code]1[/code] means that the particles will make full [code]0[/code] to [code]1[/code] offset cycle during lifetime, [code]2[/code] means [code]2[/code] cycles etc.
+ With animation speed greater than [code]1[/code], remember to enable [member CanvasItemMaterial.particles_anim_loop] property if you want the animation to repeat.
</member>
<member name="anim_speed_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member anim_speed_max].
</member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
Each particle's initial color. If [member texture] is defined, it will be multiplied by this color.
@@ -126,8 +139,10 @@
Damping will vary along this [Curve].
</member>
<member name="damping_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ The maximum rate at which particles lose velocity. For example value of [code]100[/code] means that the particle will go from [code]100[/code] velocity to [code]0[/code] in [code]1[/code] second.
</member>
<member name="damping_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member damping_max].
</member>
<member name="direction" type="Vector2" setter="set_direction" getter="get_direction" default="Vector2(1, 0)">
Unit vector specifying the particles' emission direction.
@@ -160,7 +175,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
@@ -172,12 +187,16 @@
Each particle's hue will vary along this [Curve].
</member>
<member name="hue_variation_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial hue variation applied to each particle. It will shift the particle color's hue.
</member>
<member name="hue_variation_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member hue_variation_max].
</member>
<member name="initial_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread].
</member>
<member name="initial_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member initial_velocity_max].
</member>
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
@@ -189,8 +208,10 @@
Each particle's linear acceleration will vary along this [Curve].
</member>
<member name="linear_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum linear acceleration applied to each particle in the direction of motion.
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member linear_accel_max].
</member>
<member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated.
@@ -202,8 +223,10 @@
Each particle's orbital velocity will vary along this [Curve].
</member>
<member name="orbit_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum orbital velocity applied to each particle. Makes the particles circle around origin. Specified in number of full rotations around origin per second.
</member>
<member name="orbit_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member orbit_velocity_max].
</member>
<member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false">
Align Y axis of particle with the direction of its velocity.
@@ -215,8 +238,10 @@
Each particle's radial acceleration will vary along this [Curve].
</member>
<member name="radial_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum radial acceleration applied to each particle. Makes particle accelerate away from the origin or towards it if negative.
</member>
<member name="radial_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member radial_accel_max].
</member>
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
Emission lifetime randomness ratio.
@@ -225,17 +250,24 @@
Each particle's scale will vary along this [Curve].
</member>
<member name="scale_amount_max" type="float" setter="set_param_max" getter="get_param_max" default="1.0">
+ Maximum initial scale applied to each particle.
</member>
<member name="scale_amount_min" type="float" setter="set_param_min" getter="get_param_min" default="1.0">
+ Minimum equivalent of [member scale_amount_max].
</member>
<member name="scale_curve_x" type="Curve" setter="set_scale_curve_x" getter="get_scale_curve_x">
+ Each particle's horizontal scale will vary along this [Curve].
+ [member split_scale] must be enabled.
</member>
<member name="scale_curve_y" type="Curve" setter="set_scale_curve_y" getter="get_scale_curve_y">
+ Each particle's vertical scale will vary along this [Curve].
+ [member split_scale] must be enabled.
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
Particle system's running speed scaling ratio. A value of [code]0[/code] can be used to pause the particles.
</member>
<member name="split_scale" type="bool" setter="set_split_scale" getter="get_split_scale" default="false">
+ If [code]true[/code], the scale curve will be split into x and y components. See [member scale_curve_x] and [member scale_curve_y].
</member>
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
@@ -244,8 +276,10 @@
Each particle's tangential acceleration will vary along this [Curve].
</member>
<member name="tangential_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion.
</member>
<member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum equivalent of [member tangential_accel_max].
</member>
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
Particle texture. If [code]null[/code], particles will be squares.
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index 6b39c08b3f..3a15a117f5 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -28,12 +28,14 @@
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
+ Returns the maximum value range for the given parameter.
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
+ Returns the minimum value range for the given parameter.
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
@@ -62,7 +64,7 @@
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<param index="1" name="value" type="float" />
<description>
- Sets the maximum value for the given parameter
+ Sets the maximum value for the given parameter.
</description>
</method>
<method name="set_param_min">
@@ -70,7 +72,7 @@
<param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<param index="1" name="value" type="float" />
<description>
- Sets the minimum value for the given parameter
+ Sets the minimum value for the given parameter.
</description>
</method>
<method name="set_particle_flag">
@@ -187,7 +189,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="0">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the particle system itself.
</member>
<member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0">
Amount of [member spread] in Y/Z plane. A value of [code]1[/code] restricts particles to X/Z plane.
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index a1d24f778d..9315a85e1f 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -52,14 +52,14 @@
<return type="Vector2" />
<description>
Returns this camera's target position, in global coordinates.
- [b]Note:[/b] The returned value is not the same as [member Node2D.global_position], as it is affected by the drag properties. It is also not the same as the current position if [member smoothing_enabled] is [code]true[/code] (see [method get_screen_center_position]).
+ [b]Note:[/b] The returned value is not the same as [member Node2D.global_position], as it is affected by the drag properties. It is also not the same as the current position if [member position_smoothing_enabled] is [code]true[/code] (see [method get_screen_center_position]).
</description>
</method>
<method name="reset_smoothing">
<return type="void" />
<description>
Sets the camera's position immediately to its current smoothing destination.
- This method has no effect if [member smoothing_enabled] is [code]false[/code].
+ This method has no effect if [member position_smoothing_enabled] is [code]false[/code].
</description>
</method>
<method name="set_drag_margin">
@@ -138,7 +138,7 @@
</member>
<member name="limit_smoothed" type="bool" setter="set_limit_smoothing_enabled" getter="is_limit_smoothing_enabled" default="false">
If [code]true[/code], the camera smoothly stops when reaches its limits.
- This property has no effect if [member smoothing_enabled] is [code]false[/code].
+ This property has no effect if [member position_smoothing_enabled] is [code]false[/code].
[b]Note:[/b] To immediately update the camera's position to be within limits without smoothing, even with this setting enabled, invoke [method reset_smoothing].
</member>
<member name="limit_top" type="int" setter="set_limit" getter="get_limit" default="-10000000">
@@ -147,14 +147,21 @@
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
The camera's relative offset. Useful for looking around or camera shake animations. The offsetted camera can go past the limits defined in [member limit_top], [member limit_bottom], [member limit_left] and [member limit_right].
</member>
+ <member name="position_smoothing_enabled" type="bool" setter="set_position_smoothing_enabled" getter="is_position_smoothing_enabled" default="false">
+ If [code]true[/code], the camera's view smoothly moves towards its target position at [member position_smoothing_speed].
+ </member>
+ <member name="position_smoothing_speed" type="float" setter="set_position_smoothing_speed" getter="get_position_smoothing_speed" default="5.0">
+ Speed in pixels per second of the camera's smoothing effect when [member position_smoothing_enabled] is [code]true[/code].
+ </member>
<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="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 name="rotation_smoothing_enabled" type="bool" setter="set_rotation_smoothing_enabled" getter="is_rotation_smoothing_enabled" default="false">
+ If [code]true[/code], the camera's view smoothly rotates, via asymptotic smoothing, to align with its target rotation at [member rotation_smoothing_speed].
+ [b]Note:[/b] This property has no effect if [member ignore_rotation] is [code]true[/code].
</member>
- <member name="smoothing_speed" type="float" setter="set_follow_smoothing" getter="get_follow_smoothing" default="5.0">
- Speed in pixels per second of the camera's smoothing effect when [member smoothing_enabled] is [code]true[/code].
+ <member name="rotation_smoothing_speed" type="float" setter="set_rotation_smoothing_speed" getter="get_rotation_smoothing_speed" default="5.0">
+ The angular, asymptotic speed of the camera's rotation smoothing effect when [member rotation_smoothing_enabled] is [code]true[/code].
</member>
<member name="zoom" type="Vector2" setter="set_zoom" getter="get_zoom" default="Vector2(1, 1)">
The camera's zoom. A zoom of [code]Vector(2, 2)[/code] doubles the size seen in the viewport. A zoom of [code]Vector(0.5, 0.5)[/code] halves the size seen in the viewport.
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index d74f49c897..ee09b016ac 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -416,7 +416,7 @@
<method name="get_global_transform" qualifiers="const">
<return type="Transform2D" />
<description>
- Returns the global transform matrix of this item.
+ Returns the global transform matrix of this item, i.e. the combined transform up to the topmost [CanvasItem] node. The topmost item is a [CanvasItem] that either has no parent, has non-[CanvasItem] parent or it has [member top_level] enabled.
</description>
</method>
<method name="get_global_transform_with_canvas" qualifiers="const">
@@ -456,6 +456,13 @@
Returns this item's transform in relation to the viewport.
</description>
</method>
+ <method name="get_visibility_layer_bit" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns an individual bit on the rendering visibility layer.
+ </description>
+ </method>
<method name="get_world_2d" qualifiers="const">
<return type="World2D" />
<description>
@@ -527,6 +534,14 @@
If [param enable] is [code]true[/code], this node will receive [constant NOTIFICATION_TRANSFORM_CHANGED] when its global transform changes.
</description>
</method>
+ <method name="set_visibility_layer_bit">
+ <return type="void" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="enabled" type="bool" />
+ <description>
+ Set/clear individual bits on the rendering visibility layer. This simplifies editing this [CanvasItem]'s visibility layer.
+ </description>
+ </method>
<method name="show">
<return type="void" />
<description>
@@ -535,7 +550,8 @@
</method>
</methods>
<members>
- <member name="clip_children" type="bool" setter="set_clip_children" getter="is_clipping_children" default="false">
+ <member name="clip_children" type="int" setter="set_clip_children_mode" getter="get_clip_children_mode" enum="CanvasItem.ClipChildrenMode" default="0">
+ Allows the current node to clip children nodes, essentially acting as a mask.
</member>
<member name="light_mask" type="int" setter="set_light_mask" getter="get_light_mask" default="1">
The rendering layers in which this [CanvasItem] responds to [Light2D] nodes.
@@ -564,6 +580,9 @@
<member name="use_parent_material" type="bool" setter="set_use_parent_material" getter="get_use_parent_material" default="false">
If [code]true[/code], the parent [CanvasItem]'s [member material] property is used as this one's material.
</member>
+ <member name="visibility_layer" type="int" setter="set_visibility_layer" getter="get_visibility_layer" default="1">
+ The rendering layer in which this [CanvasItem] is rendered by [Viewport] nodes. A [Viewport] will render a [CanvasItem] if it and all its parents share a layer with the [Viewport]'s canvas cull mask.
+ </member>
<member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true">
If [code]true[/code], this [CanvasItem] is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]).
[b]Note:[/b] For controls that inherit [Popup], the correct way to make them visible is to call one of the multiple [code]popup*()[/code] functions instead.
@@ -652,5 +671,13 @@
<constant name="TEXTURE_REPEAT_MAX" value="4" enum="TextureRepeat">
Represents the size of the [enum TextureRepeat] enum.
</constant>
+ <constant name="CLIP_CHILDREN_DISABLED" value="0" enum="ClipChildrenMode">
+ </constant>
+ <constant name="CLIP_CHILDREN_ONLY" value="1" enum="ClipChildrenMode">
+ </constant>
+ <constant name="CLIP_CHILDREN_AND_DRAW" value="2" enum="ClipChildrenMode">
+ </constant>
+ <constant name="CLIP_CHILDREN_MAX" value="3" enum="ClipChildrenMode">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index 50c0860d1f..7c1b19b961 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Canvas drawing layer. [CanvasItem] nodes that are direct or indirect children of a [CanvasLayer] will be drawn in that layer. The layer is a numeric index that defines the draw order. The default 2D scene renders with index 0, so a [CanvasLayer] with index -1 will be drawn below, and one with index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or above), or backgrounds (in layer -1 or below).
+ Embedded [Window]s are placed in layer 1024. CanvasItems in layer 1025 or above appear in front of embedded windows, CanvasItems in layer 1023 or below appear behind embedded windows.
</description>
<tutorials>
<link title="Viewport and canvas transforms">$DOCS_URL/tutorials/2d/2d_transforms.html</link>
diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml
index ac18c2d474..2dc83790c7 100644
--- a/doc/classes/CanvasTexture.xml
+++ b/doc/classes/CanvasTexture.xml
@@ -1,25 +1,36 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CanvasTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Texture with optional normal and specular maps for use in 2D rendering.
</brief_description>
<description>
+ [CanvasTexture] is an alternative to [ImageTexture] for 2D rendering. It allows using normal maps and specular maps in any node that inherits from [CanvasItem]. [CanvasTexture] also allows overriding the texture's filter and repeat mode independently of the node's properties (or the project settings).
+ [b]Note:[/b] [CanvasTexture] cannot be used in 3D rendering. For physically-based materials in 3D, use [BaseMaterial3D] instead.
</description>
<tutorials>
</tutorials>
<members>
<member name="diffuse_texture" type="Texture2D" setter="set_diffuse_texture" getter="get_diffuse_texture">
+ The diffuse (color) texture to use. This is the main texture you want to set in most cases.
</member>
<member name="normal_texture" type="Texture2D" setter="set_normal_texture" getter="get_normal_texture">
+ The normal map texture to use. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
+ [b]Note:[/b] Godot expects the normal map to use X+, Y+, and Z+ coordinates. See [url=http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates]this page[/url] for a comparison of normal map coordinates expected by popular engines.
</member>
<member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color(1, 1, 1, 1)">
+ The multiplier for specular reflection colors. The [Light2D]'s color is also taken into account when determining the reflection color. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
</member>
<member name="specular_shininess" type="float" setter="set_specular_shininess" getter="get_specular_shininess" default="1.0">
+ The specular exponent for [Light2D] specular reflections. Higher values result in a more glossy/"wet" look, with reflections becoming more localized and less visible overall. The default value of [code]1.0[/code] disables specular reflections entirely. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
</member>
<member name="specular_texture" type="Texture2D" setter="set_specular_texture" getter="get_specular_texture">
+ The specular map to use for [Light2D] specular reflections. This should be a grayscale or colored texture, with brighter areas resulting in a higher [member specular_shininess] value. Using a colored [member specular_texture] allows controlling specular shininess on a per-channel basis. Only has a visible effect if [Light2D]s are affecting this [CanvasTexture].
</member>
<member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="CanvasItem.TextureFilter" default="0">
+ The texture filtering mode to use when drawing this [CanvasTexture].
</member>
<member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="CanvasItem.TextureRepeat" default="0">
+ The texture repeat mode to use when drawing this [CanvasTexture].
</member>
</members>
</class>
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index 2ffe880971..699e872e99 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -4,7 +4,7 @@
Binary choice user interface widget. See also [CheckButton].
</brief_description>
<description>
- A checkbox allows the user to make a binary choice (choosing only one of two possible options). It's similar to [CheckButton] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckBox when toggling it has [b]no[/b] immediate effect on something. For instance, it should be used when toggling it will only do something once a confirmation button is pressed.
+ A checkbox allows the user to make a binary choice (choosing only one of two possible options). It's similar to [CheckButton] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckBox when toggling it has [b]no[/b] immediate effect on something. For example, it could be used when toggling it will only do something once a confirmation button is pressed.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index 2f584103be..dfbaa7cbee 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -4,7 +4,7 @@
Checkable button. See also [CheckBox].
</brief_description>
<description>
- CheckButton is a toggle button displayed as a check field. It's similar to [CheckBox] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckButton when toggling it has an [b]immediate[/b] effect on something. For instance, it should be used if toggling it enables/disables a setting without requiring the user to press a confirmation button.
+ CheckButton is a toggle button displayed as a check field. It's similar to [CheckBox] in functionality, but it has a different appearance. To follow established UX patterns, it's recommended to use CheckButton when toggling it has an [b]immediate[/b] effect on something. For example, it could be used if toggling it enables/disables a setting without requiring the user to press a confirmation button.
See also [BaseButton] which contains common properties and methods associated with this node.
</description>
<tutorials>
diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml
index 58a536406f..5d3c6210f6 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -13,7 +13,7 @@
<return type="bool" />
<param index="0" name="class" type="StringName" />
<description>
- Returns [code]true[/code] if you can instance objects from the specified [param class], [code]false[/code] in other case.
+ Returns [code]true[/code] if objects can be instantiated from the specified [param class], otherwise returns [code]false[/code].
</description>
</method>
<method name="class_exists" qualifiers="const">
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index ca482a39e0..4c62ab2a7f 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -616,8 +616,8 @@
<theme_item name="font_readonly_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
Sets the font [Color] when [member TextEdit.editable] is disabled.
</theme_item>
- <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
- Sets the [Color] of the selected text. [member TextEdit.override_selected_font_color] has to be enabled.
+ <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)">
+ Sets the [Color] of the selected text. If equal to [code]Color(0, 0, 0, 0)[/code], it will be ignored.
</theme_item>
<theme_item name="line_length_guideline_color" data_type="color" type="Color" default="Color(0.3, 0.5, 0.8, 0.1)">
[Color] of the main line length guideline, secondary guidelines will have 50% alpha applied.
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index fa8fbd0d3e..75530370bc 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -14,6 +14,10 @@
<link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link>
</tutorials>
<members>
+ <member name="debug_color" type="Color" setter="set_debug_color" getter="get_debug_color" default="Color(0, 0, 0, 1)">
+ The collision shape debug color.
+ [b]Note:[/b] The default value is [member ProjectSettings.debug/shapes/collision/shape_color]. The [code]Color(0, 0, 0, 1)[/code] value documented here is a placeholder, and not the actual default debug color.
+ </member>
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false">
A disabled collision shape has no effect in the world. This property should be changed with [method Object.set_deferred].
</member>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 3a3803c1da..a14ca15ef1 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -141,12 +141,6 @@
[/codeblocks]
</description>
</method>
- <method name="find_named_color" qualifiers="static">
- <return type="int" />
- <param index="0" name="name" type="String" />
- <description>
- </description>
- </method>
<method name="from_hsv" qualifiers="static">
<return type="Color" />
<param index="0" name="h" type="float" />
@@ -187,6 +181,7 @@
<return type="Color" />
<param index="0" name="rgbe" type="int" />
<description>
+ Encodes a [Color] from a RGBE9995 format integer. See [constant Image.FORMAT_RGBE9995].
</description>
</method>
<method name="from_string" qualifiers="static">
@@ -194,6 +189,7 @@
<param index="0" name="str" type="String" />
<param index="1" name="default" type="Color" />
<description>
+ Creates a [Color] from string, which can be either a HTML color code or a named color. Fallbacks to [param default] if the string does not denote any valid color.
</description>
</method>
<method name="get_luminance" qualifiers="const">
@@ -204,33 +200,21 @@
[b]Note:[/b] [method get_luminance] relies on the colour being in the linear color space to return an accurate relative luminance value. If the color is in the sRGB color space, use [method srgb_to_linear] to convert it to the linear color space first.
</description>
</method>
- <method name="get_named_color" qualifiers="static">
- <return type="Color" />
- <param index="0" name="idx" type="int" />
- <description>
- </description>
- </method>
- <method name="get_named_color_count" qualifiers="static">
- <return type="int" />
- <description>
- </description>
- </method>
- <method name="get_named_color_name" qualifiers="static">
- <return type="String" />
- <param index="0" name="idx" type="int" />
- <description>
- </description>
- </method>
<method name="hex" qualifiers="static">
<return type="Color" />
<param index="0" name="hex" type="int" />
<description>
+ Returns the [Color] associated with the provided integer number, with 8 bits per channel in ARGB order. The integer should be 32-bit. Best used with hexadecimal notation.
+ [codeblock]
+ modulate = Color.hex(0xffff0000) # red
+ [/codeblock]
</description>
</method>
<method name="hex64" qualifiers="static">
<return type="Color" />
<param index="0" name="hex" type="int" />
<description>
+ Same as [method hex], but takes 64-bit integer and the color uses 16 bits per channel.
</description>
</method>
<method name="html" qualifiers="static">
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index e992d6f9d4..cd1d0b016d 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -19,6 +19,14 @@
[b]Note:[/b] The presets list is only for [i]this[/i] color picker.
</description>
</method>
+ <method name="add_recent_preset">
+ <return type="void" />
+ <param index="0" name="color" type="Color" />
+ <description>
+ Adds the given color to a list of color recent presets so that it can be picked later. Recent presets are the colors that were picked recently, a new preset is automatically created and added to recent presets when you pick a new color.
+ [b]Note:[/b] The recent presets list is only for [i]this[/i] color picker.
+ </description>
+ </method>
<method name="erase_preset">
<return type="void" />
<param index="0" name="color" type="Color" />
@@ -26,12 +34,25 @@
Removes the given color from the list of color presets of this color picker.
</description>
</method>
+ <method name="erase_recent_preset">
+ <return type="void" />
+ <param index="0" name="color" type="Color" />
+ <description>
+ Removes the given color from the list of color recent presets of this color picker.
+ </description>
+ </method>
<method name="get_presets" qualifiers="const">
<return type="PackedColorArray" />
<description>
Returns the list of colors in the presets of the color picker.
</description>
</method>
+ <method name="get_recent_presets" qualifiers="const">
+ <return type="PackedColorArray" />
+ <description>
+ Returns the list of colors in the recent presets of the color picker.
+ </description>
+ </method>
</methods>
<members>
<member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)">
@@ -110,6 +131,7 @@
The width of the hue selection slider.
</theme_item>
<theme_item name="label_width" data_type="constant" type="int" default="10">
+ The minimum width of the color labels next to sliders.
</theme_item>
<theme_item name="margin" data_type="constant" type="int" default="4">
The margin around the [ColorPicker].
@@ -129,15 +151,32 @@
<theme_item name="color_hue" data_type="icon" type="Texture2D">
Custom texture for the hue selection slider on the right.
</theme_item>
+ <theme_item name="expanded_arrow" data_type="icon" type="Texture2D">
+ The icon for color preset drop down menu when expanded.
+ </theme_item>
+ <theme_item name="folded_arrow" data_type="icon" type="Texture2D">
+ The icon for color preset drop down menu when folded.
+ </theme_item>
<theme_item name="overbright_indicator" data_type="icon" type="Texture2D">
The indicator used to signalize that the color value is outside the 0-1 range.
</theme_item>
<theme_item name="picker_cursor" data_type="icon" type="Texture2D">
+ The image displayed over the color box/circle (depending on the [member picker_shape]), marking the currently selected color.
</theme_item>
<theme_item name="sample_bg" data_type="icon" type="Texture2D">
+ Background panel for the color preview box (visible when the color is translucent).
</theme_item>
<theme_item name="screen_picker" data_type="icon" type="Texture2D">
The icon for the screen color picker button.
</theme_item>
+ <theme_item name="shape_circle" data_type="icon" type="Texture2D">
+ The icon for circular picker shapes.
+ </theme_item>
+ <theme_item name="shape_rect" data_type="icon" type="Texture2D">
+ The icon for rectangular picker shapes.
+ </theme_item>
+ <theme_item name="shape_rect_wheel" data_type="icon" type="Texture2D">
+ The icon for rectangular wheel picker shapes.
+ </theme_item>
</theme_items>
</class>
diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml
index d4c503857d..48b4df9126 100644
--- a/doc/classes/ConfirmationDialog.xml
+++ b/doc/classes/ConfirmationDialog.xml
@@ -8,10 +8,10 @@
To get cancel action, you can use:
[codeblocks]
[gdscript]
- get_cancel().connect("pressed", self, "cancelled")
+ get_cancel_button().pressed.connect(self.cancelled)
[/gdscript]
[csharp]
- GetCancel().Connect("pressed", this, nameof(Cancelled));
+ GetCancelButton().Pressed += Cancelled;
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/Container.xml b/doc/classes/Container.xml
index a13e1598b2..0e1ef02573 100644
--- a/doc/classes/Container.xml
+++ b/doc/classes/Container.xml
@@ -14,14 +14,14 @@
<method name="_get_allowed_size_flags_horizontal" qualifiers="virtual const">
<return type="PackedInt32Array" />
<description>
- Implement to return a list of allowed horizontal [enum Control.SizeFlags] for child nodes. This doesn't technically prevent the usages of any other size flags, if your implementation requires that. This only limits the options available to the user in the inspector dock.
+ Implement to return a list of allowed horizontal [enum Control.SizeFlags] for child nodes. This doesn't technically prevent the usages of any other size flags, if your implementation requires that. This only limits the options available to the user in the Inspector dock.
[b]Note:[/b] Having no size flags is equal to having [constant Control.SIZE_SHRINK_BEGIN]. As such, this value is always implicitly allowed.
</description>
</method>
<method name="_get_allowed_size_flags_vertical" qualifiers="virtual const">
<return type="PackedInt32Array" />
<description>
- Implement to return a list of allowed vertical [enum Control.SizeFlags] for child nodes. This doesn't technically prevent the usages of any other size flags, if your implementation requires that. This only limits the options available to the user in the inspector dock.
+ Implement to return a list of allowed vertical [enum Control.SizeFlags] for child nodes. This doesn't technically prevent the usages of any other size flags, if your implementation requires that. This only limits the options available to the user in the Inspector dock.
[b]Note:[/b] Having no size flags is equal to having [constant Control.SIZE_SHRINK_BEGIN]. As such, this value is always implicitly allowed.
</description>
</method>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index bf449ade77..c1fa1a2bf1 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -7,12 +7,12 @@
Base class for all UI-related nodes. [Control] features a bounding rectangle that defines its extents, an anchor position relative to its parent control or the current viewport, and offsets relative to the anchor. The offsets update automatically when the node, any of its parents, or the screen size change.
For more information on Godot's UI system, anchors, offsets, and containers, see the related tutorials in the manual. To build flexible UIs, you'll need a mix of UI elements that inherit from [Control] and [Container] nodes.
[b]User Interface nodes and input[/b]
- Godot sends input events to the scene's root node first, by calling [method Node._input]. [method Node._input] forwards the event down the node tree to the nodes under the mouse cursor, or on keyboard focus. To do so, it calls [code]MainLoop._input_event[/code].
- [b]FIXME:[/b] No longer valid after DisplayServer split and Input refactoring.
+ Godot propagates input events via viewports. Each [Viewport] is responsible for propagating [InputEvent]s to their child nodes. As the [member SceneTree.root] is a [Window], this already happens automatically for all UI elements in your game.
+ Input events are propagated through the [SceneTree] from the root node to all child nodes by calling [method Node._input]. For UI elements specifically, it makes more sense to override the virtual method [method _gui_input], which filters out unrelated input events, such as by checking z-order, [member mouse_filter], focus, or if the event was inside of the control's bounding box.
Call [method accept_event] so no other node receives the event. Once you accept an input, it becomes handled so [method Node._unhandled_input] will not process it.
- Only one [Control] node can be in keyboard focus. Only the node in focus will receive keyboard events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus.
+ Only one [Control] node can be in focus. Only the node in focus will receive events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus.
Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a [Control] node to ignore mouse or touch events. You'll need it if you place an icon on top of a button.
- [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can override the theme with the inspector.
+ [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can override the theme with the Inspector.
[b]Note:[/b] Theme items are [i]not[/i] [Object] properties. This means you can't access their values using [method Object.get] and [method Object.set]. Instead, use the [code]get_theme_*[/code] and [code]add_theme_*_override[/code] methods provided by this class.
</description>
<tutorials>
@@ -383,7 +383,7 @@
<method name="get_global_rect" qualifiers="const">
<return type="Rect2" />
<description>
- Returns the position and size of the control relative to the top-left corner of the screen. See [member position] and [member size].
+ Returns the position and size of the control relative to the [CanvasLayer]. See [member global_position] and [member size].
</description>
</method>
<method name="get_minimum_size" qualifiers="const">
@@ -680,7 +680,7 @@
<method name="release_focus">
<return type="void" />
<description>
- Give up the focus. No other control will be able to receive keyboard input.
+ Give up the focus. No other control will be able to receive input.
</description>
</method>
<method name="remove_theme_color_override">
@@ -972,34 +972,34 @@
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered and won't receive input.
</member>
- <member name="custom_minimum_size" type="Vector2i" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2i(0, 0)">
+ <member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes.
</member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
- The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard signals.
+ The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard, gamepad, and mouse signals.
</member>
<member name="focus_neighbor_bottom" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses the down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [code]ui_down[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
+ Tells Godot which node it should give focus to if the user presses the down arrow on the keyboard or down on a gamepad by default. You can change the key by editing the [code]ui_down[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
</member>
<member name="focus_neighbor_left" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses the left arrow on the keyboard or left on a gamepad by default. You can change the key by editing the [code]ui_left[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the left of this one.
+ Tells Godot which node it should give focus to if the user presses the left arrow on the keyboard or left on a gamepad by default. You can change the key by editing the [code]ui_left[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the left of this one.
</member>
<member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [code]ui_right[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
+ Tells Godot which node it should give focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [code]ui_right[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
</member>
<member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [code]ui_top[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
+ Tells Godot which node it should give focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [code]ui_top[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one.
</member>
<member name="focus_next" type="NodePath" setter="set_focus_next" getter="get_focus_next" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses [kbd]Tab[/kbd] on a keyboard by default. You can change the key by editing the [code]ui_focus_next[/code] input action.
+ Tells Godot which node it should give focus to if the user presses [kbd]Tab[/kbd] on a keyboard by default. You can change the key by editing the [code]ui_focus_next[/code] input action.
If this property is not set, Godot will select a "best guess" based on surrounding nodes in the scene tree.
</member>
<member name="focus_previous" type="NodePath" setter="set_focus_previous" getter="get_focus_previous" default="NodePath(&quot;&quot;)">
- Tells Godot which node it should give keyboard focus to if the user presses [kbd]Shift + Tab[/kbd] on a keyboard by default. You can change the key by editing the [code]ui_focus_prev[/code] input action.
+ Tells Godot which node it should give focus to if the user presses [kbd]Shift + Tab[/kbd] on a keyboard by default. You can change the key by editing the [code]ui_focus_prev[/code] input action.
If this property is not set, Godot will select a "best guess" based on surrounding nodes in the scene tree.
</member>
<member name="global_position" type="Vector2" setter="_set_global_position" getter="get_global_position">
- The node's global position, relative to the world (usually to the top-left corner of the window).
+ The node's global position, relative to the world (usually to the [CanvasLayer]).
</member>
<member name="grow_horizontal" type="int" setter="set_h_grow_direction" getter="get_h_grow_direction" enum="Control.GrowDirection" default="1">
Controls the direction on the horizontal axis in which the control should grow if its horizontal minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size.
@@ -1051,6 +1051,9 @@
[b]Note:[/b] This property is mainly intended to be used for animation purposes. Text inside the Control will look pixelated or blurry when the Control is scaled. To support multiple resolutions in your project, use an appropriate viewport stretch mode as described in the [url=$DOCS_URL/tutorials/viewports/multiple_resolutions.html]documentation[/url] instead of scaling Controls individually.
[b]Note:[/b] If the Control node is a child of a [Container] node, the scale will be reset to [code]Vector2(1, 1)[/code] when the scene is instantiated. To set the Control's scale when it's instantiated, wait for one frame using [code]await get_tree().process_frame[/code] then set its [member scale] property.
</member>
+ <member name="shortcut_context" type="Node" setter="set_shortcut_context" getter="get_shortcut_context">
+ The [Node] which must be a parent of the focused [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
+ </member>
<member name="size" type="Vector2" setter="_set_size" getter="get_size" default="Vector2(0, 0)">
The size of the node's bounding rectangle, in pixels. [Container] nodes update this property automatically.
</member>
@@ -1098,12 +1101,12 @@
<signals>
<signal name="focus_entered">
<description>
- Emitted when the node gains keyboard focus.
+ Emitted when the node gains focus.
</description>
</signal>
<signal name="focus_exited">
<description>
- Emitted when the node loses keyboard focus.
+ Emitted when the node loses focus.
</description>
</signal>
<signal name="gui_input">
@@ -1159,7 +1162,7 @@
The node can only grab focus on mouse clicks. Use with [member focus_mode].
</constant>
<constant name="FOCUS_ALL" value="2" enum="FocusMode">
- The node can grab focus on mouse click or using the arrows and the Tab keys on the keyboard. Use with [member focus_mode].
+ The node can grab focus on mouse click, using the arrows and the Tab keys on the keyboard, or using the D-pad buttons on a gamepad. Use with [member focus_mode].
</constant>
<constant name="NOTIFICATION_RESIZED" value="40">
Sent when the node changes size. Use [member size] to get the new size.
diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml
index cc4124d084..ccdf085319 100644
--- a/doc/classes/Curve2D.xml
+++ b/doc/classes/Curve2D.xml
@@ -102,6 +102,22 @@
Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
+ <method name="sample_baked_with_rotation" qualifiers="const">
+ <return type="Transform2D" />
+ <param index="0" name="offset" type="float" />
+ <param index="1" name="cubic" type="bool" default="false" />
+ <param index="2" name="loop" type="bool" default="true" />
+ <param index="3" name="lookahead" type="float" default="4.0" />
+ <description>
+ Similar to [method sample_baked], but returns [Transform2D] that includes a rotation along the curve. Returns empty transform if length of the curve is [code]0[/code].
+ Use [param loop] to smooth the tangent at the end of the curve. [param lookahead] defines the distance to a nearby point for calculating the tangent vector.
+ [codeblock]
+ var transform = curve.sample_baked_with_rotation(offset)
+ position = transform.get_origin()
+ rotation = transform.get_rotation()
+ [/codeblock]
+ </description>
+ </method>
<method name="samplef" qualifiers="const">
<return type="Vector2" />
<param index="0" name="fofs" type="float" />
diff --git a/doc/classes/CylinderShape3D.xml b/doc/classes/CylinderShape3D.xml
index 6ff142da59..dcb14ec945 100644
--- a/doc/classes/CylinderShape3D.xml
+++ b/doc/classes/CylinderShape3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Cylinder shape for collisions. Like [CapsuleShape3D], but without hemispheres at the cylinder's ends.
+ [b]Note:[/b] There are several known bugs with cylinder collision shapes. Using [CapsuleShape3D] or [BoxShape3D] instead is recommended.
[b]Performance:[/b] Being a primitive collision shape, [CylinderShape3D] is fast to check collisions against (though not as fast as [SphereShape3D]). [CylinderShape3D] is also more demanding compared to [CapsuleShape3D].
</description>
<tutorials>
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index a86aff060d..ac1f63af56 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -325,18 +325,21 @@
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
+ Returns [code]true[/code] if the dictionaries differ, i.e. their key or value lists are different (including the order).
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Dictionary" />
<description>
+ Returns [code]true[/code] if both dictionaries have the same contents, i.e. their keys list and value list are equal.
</description>
</operator>
<operator name="operator []">
<return type="Variant" />
<param index="0" name="key" type="Variant" />
<description>
+ Retunrs a value at the given [param key] or [code]null[/code] and error if the key does not exist. For safe access, use [method get] or [method has].
</description>
</operator>
</operators>
diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml
index 554ef9e2da..7d1612e59c 100644
--- a/doc/classes/DirAccess.xml
+++ b/doc/classes/DirAccess.xml
@@ -80,7 +80,7 @@
<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.
+ 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>
@@ -199,7 +199,7 @@
<method name="get_space_left">
<return type="int" />
<description>
- On UNIX desktop systems, returns the available space on the current directory's disk. On other platforms, this information is not available and the method returns 0 or -1.
+ Returns the available space on the current directory's disk, in bytes. Returns [code]0[/code] if the platform-specific method to query the available space fails.
</description>
</method>
<method name="list_dir_begin">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 6d3f3a7362..4bb3657cf7 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="DisplayServer" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Singleton for window management functions.
</brief_description>
<description>
+ [DisplayServer] handles everything related to window management. This is separated from [OS] as a single operating system may support multiple display servers.
+ [b]Headless mode:[/b] Starting the engine with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] disables all rendering and window management functions. Most functions from [DisplayServer] will return dummy values in this case.
</description>
<tutorials>
</tutorials>
@@ -16,8 +19,8 @@
<method name="clipboard_get_primary" qualifiers="const">
<return type="String" />
<description>
- Returns the user's primary clipboard as a string if possible.
- [b]Note:[/b] This method is only implemented on Linux.
+ Returns the user's [url=https://unix.stackexchange.com/questions/139191/whats-the-difference-between-primary-selection-and-clipboard-buffer]primary[/url] clipboard as a string if possible. This is the clipboard that is set when the user selects text in any application, rather than when pressing [kbd]Ctrl + C[/kbd]. The clipboard data can then be pasted by clicking the middle mouse button in any application that supports the primary clipboard mechanism.
+ [b]Note:[/b] This method is only implemented on Linux (X11).
</description>
</method>
<method name="clipboard_has" qualifiers="const">
@@ -37,22 +40,14 @@
<return type="void" />
<param index="0" name="clipboard_primary" type="String" />
<description>
- Sets the user's primary clipboard content to the given string.
- [b]Note:[/b] This method is only implemented on Linux.
- </description>
- </method>
- <method name="create_sub_window">
- <return type="int" />
- <param index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
- <param index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode" />
- <param index="2" name="flags" type="int" />
- <param index="3" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)" />
- <description>
+ Sets the user's [url=https://unix.stackexchange.com/questions/139191/whats-the-difference-between-primary-selection-and-clipboard-buffer]primary[/url] clipboard content to the given string. This is the clipboard that is set when the user selects text in any application, rather than when pressing [kbd]Ctrl + C[/kbd]. The clipboard data can then be pasted by clicking the middle mouse button in any application that supports the primary clipboard mechanism.
+ [b]Note:[/b] This method is only implemented on Linux (X11).
</description>
</method>
<method name="cursor_get_shape" qualifiers="const">
<return type="int" enum="DisplayServer.CursorShape" />
<description>
+ Returns the default mouse cursor shape set by [method cursor_set_shape].
</description>
</method>
<method name="cursor_set_custom_image">
@@ -61,18 +56,14 @@
<param index="1" name="shape" type="int" enum="DisplayServer.CursorShape" default="0" />
<param index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)" />
<description>
+ Sets a custom mouse cursor image for the defined [param shape]. This means the user's operating system and mouse cursor theme will no longer influence the mouse cursor's appearance. The image must be [code]256x256[/code] or smaller for correct appearance. [param hotspot] can optionally be set to define the area where the cursor will click. By default, [param hotspot] is set to [code]Vector2(0, 0)[/code], which is the top-left corner of the image. See also [method cursor_set_shape].
</description>
</method>
<method name="cursor_set_shape">
<return type="void" />
<param index="0" name="shape" type="int" enum="DisplayServer.CursorShape" />
<description>
- </description>
- </method>
- <method name="delete_sub_window">
- <return type="void" />
- <param index="0" name="window_id" type="int" />
- <description>
+ Sets the default mouse cursor shape. The cursor's appearance will vary depending on the user's operating system and mouse cursor theme. See also [method cursor_get_shape] and [method cursor_set_custom_image].
</description>
</method>
<method name="dialog_input_text">
@@ -82,6 +73,8 @@
<param index="2" name="existing_text" type="String" />
<param index="3" name="callback" type="Callable" />
<description>
+ Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] will be called with a [String] argument equal to the text field's contents when the dialog is closed for any reason.
+ [b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="dialog_show">
@@ -91,17 +84,23 @@
<param index="2" name="buttons" type="PackedStringArray" />
<param index="3" name="callback" type="Callable" />
<description>
+ Shows a text dialog which uses the operating system's native look-and-feel. [param callback] will be called when the dialog is closed for any reason.
+ [b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="enable_for_stealing_focus">
<return type="void" />
<param index="0" name="process_id" type="int" />
<description>
+ Allows the [param process_id] PID to steal focus from this window. In other words, this disables the operating system's focus stealing protection for the specified PID.
+ [b]Note:[/b] This method is implemented on Windows.
</description>
</method>
<method name="force_process_and_drop_events">
<return type="void" />
<description>
+ Forces window manager processing while ignoring all [InputEvent]s. See also [method process_events].
+ [b]Note:[/b] This method is implemented on Windows and macOS.
</description>
</method>
<method name="get_accent_color" qualifiers="const">
@@ -127,27 +126,43 @@
<method name="get_name" qualifiers="const">
<return type="String" />
<description>
+ Returns the name of the [DisplayServer] currently in use. Most operating systems only have a single [DisplayServer], but Linux has access to more than one [DisplayServer] (although only X11 is currently implemented in Godot).
+ The names of built-in display servers are [code]Windows[/code], [code]macOS[/code], [code]X11[/code] (Linux), [code]Android[/code], [code]iOS[/code], [code]web[/code] (HTML5) and [code]headless[/code] (when started with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]).
</description>
</method>
<method name="get_screen_count" qualifiers="const">
<return type="int" />
<description>
+ Returns the number of displays available.
</description>
</method>
<method name="get_swap_cancel_ok">
<return type="bool" />
<description>
+ Returns [code]true[/code] if positions of [b]OK[/b] and [b]Cancel[/b] buttons are swapped in dialogs. This is enabled by default on Windows and UWP to follow interface conventions, and be toggled by changing [member ProjectSettings.gui/common/swap_cancel_ok].
+ [b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
</description>
</method>
<method name="get_window_at_screen_position" qualifiers="const">
<return type="int" />
<param index="0" name="position" type="Vector2i" />
<description>
+ Returns the ID of the window at the specified screen [param position] (in pixels). On multi-monitor setups, the screen position is relative to the virtual desktop area. On multi-monitor setups with different screen resolutions or orientations, the origin may be located outside any display like this:
+ [codeblock]
+ * (0, 0) +-------+
+ | |
+ +-------------+ | |
+ | | | |
+ | | | |
+ +-------------+ +-------+
+ [/codeblock]
</description>
</method>
<method name="get_window_list" qualifiers="const">
<return type="PackedInt32Array" />
<description>
+ Returns the list of Godot window IDs belonging to this process.
+ [b]Note:[/b] Native dialogs are not included in this list.
</description>
</method>
<method name="global_menu_add_check_item">
@@ -362,6 +377,14 @@
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
+ <method name="global_menu_get_item_count" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <description>
+ Returns number of items in the global menu with ID [param menu_root].
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
<method name="global_menu_get_item_icon" qualifiers="const">
<return type="Texture2D" />
<param index="0" name="menu_root" type="String" />
@@ -665,37 +688,42 @@
<return type="bool" />
<param index="0" name="feature" type="int" enum="DisplayServer.Feature" />
<description>
+ Returns [code]true[/code] if the specified [param feature] is supported by the current [DisplayServer], [code]false[/code] otherwise.
</description>
</method>
<method name="ime_get_selection" qualifiers="const">
<return type="Vector2i" />
<description>
+ Returns the text selection in the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] composition string, with the [Vector2i]'s [code]x[/code] component being the caret position and [code]y[/code] being the length of the selection.
+ [b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="ime_get_text" qualifiers="const">
<return type="String" />
<description>
+ Returns the composition string contained within the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] window.
+ [b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="is_dark_mode" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if OS is using dark mode.
- [b]Note:[/b] This method is implemented on macOS, Windows and Linux.
+ [b]Note:[/b] This method is implemented on macOS, Windows and Linux (X11).
</description>
</method>
<method name="is_dark_mode_supported" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if OS supports dark mode.
- [b]Note:[/b] This method is implemented on macOS, Windows and Linux.
+ [b]Note:[/b] This method is implemented on macOS, Windows and Linux (X11).
</description>
</method>
<method name="keyboard_get_current_layout" qualifiers="const">
<return type="int" />
<description>
Returns active keyboard layout index.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="keyboard_get_keycode_from_physical" qualifiers="const">
@@ -703,14 +731,14 @@
<param index="0" name="keycode" type="int" enum="Key" />
<description>
Converts a physical (US QWERTY) [param keycode] to one in the active keyboard layout.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="keyboard_get_layout_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of keyboard layouts.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="keyboard_get_layout_language" qualifiers="const">
@@ -718,7 +746,7 @@
<param index="0" name="index" type="int" />
<description>
Returns the ISO-639/BCP-47 language code of the keyboard layout at position [param index].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="keyboard_get_layout_name" qualifiers="const">
@@ -726,25 +754,27 @@
<param index="0" name="index" type="int" />
<description>
Returns the localized name of the keyboard layout at position [param index].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="keyboard_set_current_layout">
<return type="void" />
<param index="0" name="index" type="int" />
<description>
- Sets active keyboard layout.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ Sets the active keyboard layout.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="mouse_get_button_state" qualifiers="const">
<return type="int" enum="MouseButton" />
<description>
+ Returns the current state of mouse buttons (whether each button is pressed) as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together. Equivalent to [method Input.get_mouse_button_mask].
</description>
</method>
<method name="mouse_get_mode" qualifiers="const">
<return type="int" enum="DisplayServer.MouseMode" />
<description>
+ Returns the current mouse mode. See also [method mouse_set_mode].
</description>
</method>
<method name="mouse_get_position" qualifiers="const">
@@ -757,11 +787,13 @@
<return type="void" />
<param index="0" name="mouse_mode" type="int" enum="DisplayServer.MouseMode" />
<description>
+ Sets the current mouse mode. See also [method mouse_get_mode].
</description>
</method>
<method name="process_events">
<return type="void" />
<description>
+ Perform window manager processing, including input flushing. See also [method force_process_and_drop_events], [method Input.flush_buffered_events] and [member Input.use_accumulated_input].
</description>
</method>
<method name="screen_get_dpi" qualifiers="const">
@@ -779,7 +811,7 @@
xxhdpi - 480 dpi
xxxhdpi - 640 dpi
[/codeblock]
- [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows. Returns [code]72[/code] on unsupported platforms.
+ [b]Note:[/b] This method is implemented on Android, Linux (X11), macOS and Windows. Returns [code]72[/code] on unsupported platforms.
</description>
</method>
<method name="screen_get_max_scale" qualifiers="const">
@@ -794,12 +826,24 @@
<return type="int" enum="DisplayServer.ScreenOrientation" />
<param index="0" name="screen" type="int" default="-1" />
<description>
+ Returns the [param screen]'s current orientation. See also [method screen_set_orientation].
+ [b]Note:[/b] This method is implemented on Android and iOS.
</description>
</method>
<method name="screen_get_position" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="screen" type="int" default="-1" />
<description>
+ Returns the screen's top-left corner position in pixels. On multi-monitor setups, the screen position is relative to the virtual desktop area. On multi-monitor setups with different screen resolutions or orientations, the origin may be located outside any display like this:
+ [codeblock]
+ * (0, 0) +-------+
+ | |
+ +-------------+ | |
+ | | | |
+ | | | |
+ +-------------+ +-------+
+ [/codeblock]
+ See also [method screen_get_size].
</description>
</method>
<method name="screen_get_refresh_rate" qualifiers="const">
@@ -829,29 +873,34 @@
<return type="Vector2i" />
<param index="0" name="screen" type="int" default="-1" />
<description>
+ Returns the screen's size in pixels. See also [method screen_get_position] and [method screen_get_usable_rect].
</description>
</method>
<method name="screen_get_usable_rect" qualifiers="const">
<return type="Rect2i" />
<param index="0" name="screen" type="int" default="-1" />
<description>
+ Returns the portion of the screen that is not obstructed by a status bar in pixels. See also [method screen_get_size].
</description>
</method>
<method name="screen_is_kept_on" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the screen should never be turned off by the operating system's power-saving measures. See also [method screen_set_keep_on].
</description>
</method>
<method name="screen_is_touchscreen" qualifiers="const">
<return type="bool" />
<param index="0" name="screen" type="int" default="-1" />
<description>
+ Returns [code]true[/code] if the screen can send touch events or if [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is [code]true[/code].
</description>
</method>
<method name="screen_set_keep_on">
<return type="void" />
<param index="0" name="enable" type="bool" />
<description>
+ Sets whether the screen should never be turned off by the operating system's power-saving measures. See also [method screen_is_kept_on].
</description>
</method>
<method name="screen_set_orientation">
@@ -859,18 +908,21 @@
<param index="0" name="orientation" type="int" enum="DisplayServer.ScreenOrientation" />
<param index="1" name="screen" type="int" default="-1" />
<description>
+ Sets the [param screen]'s [param orientation]. See also [method screen_get_orientation].
</description>
</method>
<method name="set_icon">
<return type="void" />
<param index="0" name="image" type="Image" />
<description>
+ Sets the window icon (usually displayed in the top-left corner) in the operating system's [i]native[/i] format. To use icons in the operating system's native format, use [method set_native_icon] instead.
</description>
</method>
<method name="set_native_icon">
<return type="void" />
<param index="0" name="filename" type="String" />
<description>
+ Sets the window icon (usually displayed in the top-left corner) in the operating system's [i]native[/i] format. The file at [param filename] must be in [code].ico[/code] format on Windows or [code].icns[/code] on macOS. By using specially crafted [code].ico[/code] or [code].icns[/code] icons, [method set_native_icon] allows specifying different icons depending on the size the icon is displayed at. This size is determined by the operating system and user preferences (including the display scale factor). To use icons in other formats, use [method set_icon] instead.
</description>
</method>
<method name="tablet_get_current_driver" qualifiers="const">
@@ -911,7 +963,7 @@
- [code]name[/code] is voice name.
- [code]id[/code] is voice identifier.
- [code]language[/code] is language code in [code]lang_Variant[/code] format. [code]lang[/code] part is a 2 or 3-letter code based on the ISO-639 standard, in lowercase. And [code]Variant[/code] part is an engine dependent string describing country, region or/and dialect.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_get_voices_for_language" qualifiers="const">
@@ -919,35 +971,35 @@
<param index="0" name="language" type="String" />
<description>
Returns an [PackedStringArray] of voice identifiers for the [param language].
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_is_paused" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the synthesizer is in a paused state.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_is_speaking" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the synthesizer is generating speech, or have utterance waiting in the queue.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_pause">
<return type="void" />
<description>
Puts the synthesizer into a paused state.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_resume">
<return type="void" />
<description>
Resumes the synthesizer if it was paused.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_set_utterance_callback">
@@ -959,7 +1011,7 @@
- [code]TTS_UTTERANCE_STARTED[/code], [code]TTS_UTTERANCE_ENDED[/code], and [code]TTS_UTTERANCE_CANCELED[/code] callable's method should take one [int] parameter, the utterance id.
- [code]TTS_UTTERANCE_BOUNDARY[/code] callable's method should take two [int] parameters, the index of the character and the utterance id.
[b]Note:[/b] The granularity of the boundary callbacks is engine dependent.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_speak">
@@ -978,16 +1030,16 @@
- [param pitch] ranges from [code]0.0[/code] (lowest) to [code]2.0[/code] (highest), [code]1.0[/code] is default pitch for the current voice.
- [param rate] ranges from [code]0.1[/code] (lowest) to [code]10.0[/code] (highest), [code]1.0[/code] is a normal speaking rate. Other values act as a percentage relative.
- [param utterance_id] is passed as a parameter to the callback functions.
- [b]Note:[/b] On Windows and Linux, utterance [param text] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak].
+ [b]Note:[/b] On Windows and Linux (X11), utterance [param text] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak].
[b]Note:[/b] The granularity of pitch, rate, and volume is engine and voice dependent. Values may be truncated.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="tts_stop">
<return type="void" />
<description>
Stops synthesis in progress and removes all utterances from the queue.
- [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux (X11), macOS, and Windows.
</description>
</method>
<method name="virtual_keyboard_get_height" qualifiers="const">
@@ -1028,17 +1080,11 @@
Sets the mouse cursor position to the given [param position] relative to an origin at the upper left corner of the currently focused game Window Manager window.
</description>
</method>
- <method name="window_attach_instance_id">
- <return type="void" />
- <param index="0" name="instance_id" type="int" />
- <param index="1" name="window_id" type="int" default="0" />
- <description>
- </description>
- </method>
<method name="window_can_draw" qualifiers="const">
<return type="bool" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns [code]true[/code] if anything can be drawn in the window specified by [param window_id], [code]false[/code] otherwise. Using the [code]--disable-render-loop[/code] command line argument or a headless build will return [code]false[/code].
</description>
</method>
<method name="window_get_active_popup" qualifiers="const">
@@ -1051,12 +1097,14 @@
<return type="int" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the [method Object.get_instance_id] of the [Window] the [param window_id] is attached to. also [method window_get_attached_instance_id].
</description>
</method>
<method name="window_get_current_screen" qualifiers="const">
<return type="int" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the screen the window specified by [param window_id] is currently positioned on. If the screen overlaps multiple displays, the screen where the window's center is located is returned. See also [method window_set_current_screen].
</description>
</method>
<method name="window_get_flag" qualifiers="const">
@@ -1071,12 +1119,14 @@
<return type="Vector2i" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the window's maximum size (in pixels). See also [method window_set_max_size].
</description>
</method>
<method name="window_get_min_size" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the window's minimum size (in pixels). See also [method window_set_min_size].
</description>
</method>
<method name="window_get_mode" qualifiers="const">
@@ -1092,7 +1142,7 @@
<param index="1" name="window_id" type="int" default="0" />
<description>
Returns internal structure pointers for use in plugins.
- [b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Android, Linux (X11), macOS and Windows.
</description>
</method>
<method name="window_get_popup_safe_rect" qualifiers="const">
@@ -1113,19 +1163,21 @@
<return type="Vector2i" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the size of the window specified by [param window_id] (in pixels), including the borders drawn by the operating system. See also [method window_get_size].
</description>
</method>
<method name="window_get_safe_title_margins" qualifiers="const">
- <return type="Vector2i" />
+ <return type="Vector3i" />
<param index="0" name="window_id" type="int" default="0" />
<description>
- Returns left and right margins of the title that are safe to use (contains no buttons or other elements) when [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set.
+ Returns left margins ([code]x[/code]), right margins ([code]y[/code]) adn height ([code]z[/code]) of the title that are safe to use (contains no buttons or other elements) when [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set.
</description>
</method>
<method name="window_get_size" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Returns the size of the window specified by [param window_id] (in pixels), excluding the borders drawn by the operating system. This is also called the "client area". See also [method window_get_real_size], [method window_set_size] and [method window_get_position].
</description>
</method>
<method name="window_get_vsync_mode" qualifiers="const">
@@ -1135,6 +1187,13 @@
Returns the V-Sync mode of the given window.
</description>
</method>
+ <method name="window_is_maximize_allowed" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="window_id" type="int" default="0" />
+ <description>
+ Returns [code]true[/code] if the given window can be maximized (the maximize button is enabled).
+ </description>
+ </method>
<method name="window_maximize_on_title_dbl_click" qualifiers="const">
<return type="bool" />
<description>
@@ -1153,12 +1212,14 @@
<return type="void" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Moves the window specified by [param window_id] to the foreground, so that it is visible over other windows.
</description>
</method>
<method name="window_request_attention">
<return type="void" />
<param index="0" name="window_id" type="int" default="0" />
<description>
+ Makes the window specified by [param window_id] request attention, which is materialized by the window title and taskbar entry blinking until the window is focused. This usually has no visible effect if the window is currently focused. The exact behavior varies depending on the operating system.
</description>
</method>
<method name="window_set_current_screen">
@@ -1166,6 +1227,7 @@
<param index="0" name="screen" type="int" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Moves the window specified by [param window_id] to the specified [param screen]. See also [method window_get_current_screen].
</description>
</method>
<method name="window_set_drop_files_callback">
@@ -1173,6 +1235,8 @@
<param index="0" name="callback" type="Callable" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the [param callback] that should be called when files are dropped from the operating system's file manager to the window specified by [param window_id].
+ [b]Note:[/b] This method is implemented on Windows, macOS, Linux (X11) and Web.
</description>
</method>
<method name="window_set_exclusive">
@@ -1199,6 +1263,7 @@
<param index="0" name="active" type="bool" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets whether [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] should be enabled for the window specified by [param window_id]. See also [method window_set_ime_position].
</description>
</method>
<method name="window_set_ime_position">
@@ -1206,6 +1271,7 @@
<param index="0" name="position" type="Vector2i" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the position of the [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url] popup for the specified [param window_id]. Only effective if [method window_set_ime_active] was set to [code]true[/code] for the specified [param window_id].
</description>
</method>
<method name="window_set_input_event_callback">
@@ -1213,6 +1279,7 @@
<param index="0" name="callback" type="Callable" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the [param callback] that should be called when any [InputEvent] is sent to the window specified by [param window_id].
</description>
</method>
<method name="window_set_input_text_callback">
@@ -1220,6 +1287,7 @@
<param index="0" name="callback" type="Callable" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the [param callback] that should be called when text is entered using the virtual keyboard to the window specified by [param window_id].
</description>
</method>
<method name="window_set_max_size">
@@ -1227,6 +1295,8 @@
<param index="0" name="max_size" type="Vector2i" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the maximum size of the window specified by [param window_id] in pixels. Normally, the user will not be able to drag the window to make it smaller than the specified size. See also [method window_get_max_size].
+ [b]Note:[/b] Using third-party tools, it is possible for users to disable window geometry restrictions and therefore bypass this limit.
</description>
</method>
<method name="window_set_min_size">
@@ -1234,8 +1304,9 @@
<param index="0" name="min_size" type="Vector2i" />
<param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the minimum size for the given window to [param min_size] (in pixels).
+ Sets the minimum size for the given window to [param min_size] (in pixels). Normally, the user will not be able to drag the window to make it larger than the specified size. See also [method window_get_min_size].
[b]Note:[/b] By default, the main window has a minimum size of [code]Vector2i(64, 64)[/code]. This prevents issues that can arise when the window is resized to a near-zero size.
+ [b]Note:[/b] Using third-party tools, it is possible for users to disable window geometry restrictions and therefore bypass this limit.
</description>
</method>
<method name="window_set_mode">
@@ -1244,7 +1315,7 @@
<param index="1" name="window_id" type="int" default="0" />
<description>
Sets window mode for the given window to [param mode]. See [enum WindowMode] for possible values and how each mode behaves.
- [b]Note:[/b] Setting the window to fullscreen forcibly sets the borderless flag to [code]true[/code], so make sure to set it back to [code]false[/code] when not wanted.
+ [b]Note:[/b] Setting the window to full screen forcibly sets the borderless flag to [code]true[/code], so make sure to set it back to [code]false[/code] when not wanted.
</description>
</method>
<method name="window_set_mouse_passthrough">
@@ -1276,8 +1347,8 @@
DisplayServer.WindowSetMousePassthrough(new Vector2[] {});
[/csharp]
[/codeblocks]
- [b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux and macOS it is.
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is.
+ [b]Note:[/b] This method is implemented on Linux (X11), macOS and Windows.
</description>
</method>
<method name="window_set_popup_safe_rect">
@@ -1293,7 +1364,16 @@
<param index="0" name="position" type="Vector2i" />
<param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the position of the given window to [param position].
+ Sets the position of the given window to [param position]. On multi-monitor setups, the screen position is relative to the virtual desktop area. On multi-monitor setups with different screen resolutions or orientations, the origin may be located outside any display like this:
+ [codeblock]
+ * (0, 0) +-------+
+ | |
+ +-------------+ | |
+ | | | |
+ | | | |
+ +-------------+ +-------+
+ [/codeblock]
+ See also [method window_get_position] and [method window_set_size].
</description>
</method>
<method name="window_set_rect_changed_callback">
@@ -1301,6 +1381,7 @@
<param index="0" name="callback" type="Callable" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the [param callback] that will be called when the window specified by [param window_id] is moved or resized.
</description>
</method>
<method name="window_set_size">
@@ -1308,7 +1389,7 @@
<param index="0" name="size" type="Vector2i" />
<param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the size of the given window to [param size].
+ Sets the size of the given window to [param size] (in pixels). See also [method window_get_size] and [method window_get_position].
</description>
</method>
<method name="window_set_title">
@@ -1317,6 +1398,7 @@
<param index="1" name="window_id" type="int" default="0" />
<description>
Sets the title of the given window to [param title].
+ [b]Note:[/b] Avoid changing the window title every frame, as this can cause performance issues on certain window managers. Try to change the window title only a few times per second at most.
</description>
</method>
<method name="window_set_transient">
@@ -1324,7 +1406,8 @@
<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.
+ Sets window transient parent. Transient window is will be destroyed with its transient parent and will return focus to their parent when closed. The transient window is displayed on top of a non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
+ Note that behavior might be different depending on the platform.
</description>
</method>
<method name="window_set_vsync_mode">
@@ -1351,51 +1434,70 @@
<param index="0" name="callback" type="Callable" />
<param index="1" name="window_id" type="int" default="0" />
<description>
+ Sets the [param callback] that will be called when an event occurs in the window specified by [param window_id].
</description>
</method>
</methods>
<constants>
<constant name="FEATURE_GLOBAL_MENU" value="0" enum="Feature">
+ Display server supports global menu. This allows the application to display its menu items in the operating system's top bar. [b]macOS[/b]
</constant>
<constant name="FEATURE_SUBWINDOWS" value="1" enum="Feature">
+ Display server supports multiple windows that can be moved outside of the main window. [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_TOUCHSCREEN" value="2" enum="Feature">
+ Display server supports touchscreen input. [b]Windows, Linux (X11), Android, iOS, Web[/b]
</constant>
<constant name="FEATURE_MOUSE" value="3" enum="Feature">
+ Display server supports mouse input. [b]Windows, macOS, Linux (X11), Android, Web[/b]
</constant>
<constant name="FEATURE_MOUSE_WARP" value="4" enum="Feature">
+ Display server supports warping mouse coordinates to keep the mouse cursor constrained within an area, but looping when one of the edges is reached. [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_CLIPBOARD" value="5" enum="Feature">
+ Display server supports setting and getting clipboard data. See also [constant FEATURE_CLIPBOARD_PRIMARY]. [b]Windows, macOS, Linux (X11), Android, iOS, Web[/b]
</constant>
<constant name="FEATURE_VIRTUAL_KEYBOARD" value="6" enum="Feature">
+ Display server supports popping up a virtual keyboard when requested to input text without a physical keyboard. [b]Android, iOS, Web[/b]
</constant>
<constant name="FEATURE_CURSOR_SHAPE" value="7" enum="Feature">
+ Display server supports setting the mouse cursor shape to be different from the default. [b]Windows, macOS, Linux (X11), Android, Web[/b]
</constant>
<constant name="FEATURE_CUSTOM_CURSOR_SHAPE" value="8" enum="Feature">
+ Display server supports setting the mouse cursor shape to a custom image. [b]Windows, macOS, Linux (X11), Web[/b]
</constant>
<constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature">
+ Display server supports spawning dialogs using the operating system's native look-and-feel. [b]macOS[/b]
</constant>
<constant name="FEATURE_IME" value="10" enum="Feature">
+ Display server supports [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url], which is commonly used for inputting Chinese/Japanese/Korean text. This is handled by the operating system, rather than by Godot. [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_WINDOW_TRANSPARENCY" value="11" enum="Feature">
+ Display server supports windows can use per-pixel transparency to make windows behind them partially or fully visible. [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_HIDPI" value="12" enum="Feature">
+ Display server supports querying the operating system's display scale factor. This allows for [i]reliable[/i] automatic hiDPI display detection, as opposed to guessing based on the screen resolution and reported display DPI (which can be unreliable due to broken monitor EDID). [b]Windows, macOS[/b]
</constant>
<constant name="FEATURE_ICON" value="13" enum="Feature">
+ Display server supports changing the window icon (usually displayed in the top-left corner). [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_NATIVE_ICON" value="14" enum="Feature">
+ Display server supports changing the window icon (usually displayed in the top-left corner). [b]Windows, macOS[/b]
</constant>
<constant name="FEATURE_ORIENTATION" value="15" enum="Feature">
+ Display server supports changing the screen orientation. [b]Android, iOS[/b]
</constant>
<constant name="FEATURE_SWAP_BUFFERS" value="16" enum="Feature">
+ Display server supports V-Sync status can be changed from the default (which is forced to be enabled platforms not supporting this feature). [b]Windows, macOS, Linux (X11)[/b]
</constant>
<constant name="FEATURE_CLIPBOARD_PRIMARY" value="18" enum="Feature">
+ Display server supports Primary clipboard can be used. This is a different clipboard from [constant FEATURE_CLIPBOARD]. [b]Linux (X11)[/b]
</constant>
<constant name="FEATURE_TEXT_TO_SPEECH" value="19" enum="Feature">
- Display server supports text-to-speech. See [code]tts_*[/code] methods.
+ Display server supports text-to-speech. See [code]tts_*[/code] methods. [b]Windows, macOS, Linux (X11), Android, iOS, Web[/b]
</constant>
<constant name="FEATURE_EXTEND_TO_TITLE" value="20" enum="Feature">
- Display server supports expanding window content to the title. See [constant WINDOW_FLAG_EXTEND_TO_TITLE].
+ Display server supports expanding window content to the title. See [constant WINDOW_FLAG_EXTEND_TO_TITLE]. [b]macOS[/b]
</constant>
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
Makes the mouse cursor visible if it is hidden.
@@ -1414,24 +1516,34 @@
Confines the mouse cursor to the game window, and make it hidden.
</constant>
<constant name="SCREEN_OF_MAIN_WINDOW" value="-1">
+ Represents the screen where the main window is located. This is usually the default value in functions that allow specifying one of several screens.
</constant>
<constant name="MAIN_WINDOW_ID" value="0">
+ The ID of the main window spawned by the engine, which can be passed to methods expecting a [code]window_id[/code].
</constant>
<constant name="INVALID_WINDOW_ID" value="-1">
+ The ID that refers to a nonexisting window. This is be returned by some [DisplayServer] methods if no window matches the requested result.
</constant>
<constant name="SCREEN_LANDSCAPE" value="0" enum="ScreenOrientation">
+ Default landscape orientation.
</constant>
<constant name="SCREEN_PORTRAIT" value="1" enum="ScreenOrientation">
+ Default portrait orienstation.
</constant>
<constant name="SCREEN_REVERSE_LANDSCAPE" value="2" enum="ScreenOrientation">
+ Reverse landscape orientation (upside down).
</constant>
<constant name="SCREEN_REVERSE_PORTRAIT" value="3" enum="ScreenOrientation">
+ Reverse portrait orientation (upside down).
</constant>
<constant name="SCREEN_SENSOR_LANDSCAPE" value="4" enum="ScreenOrientation">
+ Automatic landscape orientation (default or reverse depending on sensor).
</constant>
<constant name="SCREEN_SENSOR_PORTRAIT" value="5" enum="ScreenOrientation">
+ Automatic portrait orientation (default or reverse depending on sensor).
</constant>
<constant name="SCREEN_SENSOR" value="6" enum="ScreenOrientation">
+ Automatic landscape or portrait orientation (default or reverse depending on sensor).
</constant>
<constant name="KEYBOARD_TYPE_DEFAULT" value="0" enum="VirtualKeyboardType">
Default text virtual keyboard.
@@ -1459,118 +1571,154 @@
Virtual keyboard with additional keys to assist with typing URLs.
</constant>
<constant name="CURSOR_ARROW" value="0" enum="CursorShape">
+ Arrow cursor shape. This is the default when not pointing anything that overrides the mouse cursor, such as a [LineEdit] or [TextEdit].
</constant>
<constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
+ I-beam cursor shape. This is used by default when hovering a control that accepts text input, such as [LineEdit] or [TextEdit].
</constant>
<constant name="CURSOR_POINTING_HAND" value="2" enum="CursorShape">
+ Pointing hand cursor shape. This is used by default when hovering a [LinkButton] or an URL tag in a [RichTextLabel].â‹…
</constant>
<constant name="CURSOR_CROSS" value="3" enum="CursorShape">
+ Crosshair cursor. This is intended to be displayed when the user needs precise aim over an element, such as a rectangle selection tool or a color picker.
</constant>
<constant name="CURSOR_WAIT" value="4" enum="CursorShape">
+ Wait cursor. On most cursor themes, this displays a spinning icon [i]besides[/i] the arrow. Intended to be used for non-blocking operations (when the user can do something else at the moment). See also [constant CURSOR_BUSY].
</constant>
<constant name="CURSOR_BUSY" value="5" enum="CursorShape">
+ Wait cursor. On most cursor themes, this [i]replaces[/i] the arrow with a spinning icon. Intended to be used for blocking operations (when the user can't do anything else at the moment). See also [constant CURSOR_WAIT].
</constant>
<constant name="CURSOR_DRAG" value="6" enum="CursorShape">
+ Dragging hand cursor. This is displayed during drag-and-drop operations. See also [constant CURSOR_CAN_DROP].
</constant>
<constant name="CURSOR_CAN_DROP" value="7" enum="CursorShape">
+ "Can drop" cursor. This is displayed during drag-and-drop operations if hovering over a [Control] that can accept the drag-and-drop event. On most cursor themes, this displays a dragging hand with an arrow symbol besides it. See also [constant CURSOR_DRAG].
</constant>
<constant name="CURSOR_FORBIDDEN" value="8" enum="CursorShape">
+ Forbidden cursor. This is displayed during drag-and-drop operations if the hovered [Control] can't accept the drag-and-drop event.
</constant>
<constant name="CURSOR_VSIZE" value="9" enum="CursorShape">
+ Vertical resize cursor. Intended to be displayed when the hovered [Control] can be vertically resized using the mouse. See also [constant CURSOR_VSPLIT].
</constant>
<constant name="CURSOR_HSIZE" value="10" enum="CursorShape">
+ Horizontal resize cursor. Intended to be displayed when the hovered [Control] can be horizontally resized using the mouse. See also [constant CURSOR_HSPLIT].
</constant>
<constant name="CURSOR_BDIAGSIZE" value="11" enum="CursorShape">
+ Secondary diagonal resize cursor (top-right/bottom-left). Intended to be displayed when the hovered [Control] can be resized on both axes at once using the mouse.
</constant>
<constant name="CURSOR_FDIAGSIZE" value="12" enum="CursorShape">
+ Main diagonal resize cursor (top-left/bottom-right). Intended to be displayed when the hovered [Control] can be resized on both axes at once using the mouse.
</constant>
<constant name="CURSOR_MOVE" value="13" enum="CursorShape">
+ Move cursor. Intended to be displayed when the hovered [Control] can be moved using the mouse.
</constant>
<constant name="CURSOR_VSPLIT" value="14" enum="CursorShape">
+ Vertical split cursor. This is displayed when hovering a [Control] with splits that can be vertically resized using the mouse, such as [VSplitContainer]. On some cursor themes, this cursor may have the same appearance as [constant CURSOR_VSIZE].
</constant>
<constant name="CURSOR_HSPLIT" value="15" enum="CursorShape">
+ Horizontal split cursor. This is displayed when hovering a [Control] with splits that can be horizontally resized using the mouse, such as [HSplitContainer]. On some cursor themes, this cursor may have the same appearance as [constant CURSOR_HSIZE].
</constant>
<constant name="CURSOR_HELP" value="16" enum="CursorShape">
+ Help cursor. On most cursor themes, this displays a question mark icon instead of the mouse cursor. Intended to be used when the user has requested help on the next element that will be clicked.
</constant>
<constant name="CURSOR_MAX" value="17" enum="CursorShape">
+ Represents the size of the [enum CursorShape] enum.
</constant>
<constant name="WINDOW_MODE_WINDOWED" value="0" enum="WindowMode">
+ Windowed mode, i.e. [Window] doesn't occupy the whole screen (unless set to the size of the screen).
</constant>
<constant name="WINDOW_MODE_MINIMIZED" value="1" enum="WindowMode">
+ Minimized window mode, i.e. [Window] is not visible and available on window manager's window list. Normally happens when the minimize button is pressed.
</constant>
<constant name="WINDOW_MODE_MAXIMIZED" value="2" enum="WindowMode">
+ Maximized window mode, i.e. [Window] will occupy whole screen area except task bar and still display its borders. Normally happens when the minimize button is pressed.
</constant>
<constant name="WINDOW_MODE_FULLSCREEN" value="3" enum="WindowMode">
- Fullscreen window mode. 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.
+ Full screen window mode. Note that this is not [i]exclusive[/i] full screen. On Windows and Linux (X11), a borderless window is used to emulate full screen. On macOS, a new desktop is used to display the running project.
+ Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="WINDOW_MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="WindowMode">
- Exclusive fullscreen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
- Only one window in exclusive fullscreen mode can be visible on a given screen at a time. If multiple windows are in exclusive fullscreen mode for the same screen, the last one being set to this mode takes precedence.
- 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.
+ Exclusive full screen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant WINDOW_MODE_FULLSCREEN].
+ Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
+ Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="WINDOW_FLAG_RESIZE_DISABLED" value="0" enum="WindowFlags">
- Window can't be resizing by dragging its resize grip. It's still possible to resize the window using [method window_set_size]. This flag is ignored for full screen windows.
+ The window can't be resizing by dragging its resize grip. It's still possible to resize the window using [method window_set_size]. This flag is ignored for full screen windows.
</constant>
<constant name="WINDOW_FLAG_BORDERLESS" value="1" enum="WindowFlags">
- Window do not have native title bar and other decorations. This flag is ignored for full-screen windows.
+ The window do not have native title bar and other decorations. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_ALWAYS_ON_TOP" value="2" enum="WindowFlags">
- Window is floating above other regular windows. This flag is ignored for full-screen windows.
+ The window is floating on top of all other windows. This flag is ignored for full-screen windows.
</constant>
<constant name="WINDOW_FLAG_TRANSPARENT" value="3" enum="WindowFlags">
- Window background can be transparent.
+ The 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].
+ [b]Note:[/b] Transparency support is implemented on Linux (X11), macOS and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities.
</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.
+ The window can't be focused. No-focus window will ignore all input, except mouse clicks.
</constant>
<constant name="WINDOW_FLAG_POPUP" value="5" enum="WindowFlags">
- Window is part of menu or [OptionButton] dropdown. This flag can't be changed when window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [constant WINDOW_FLAG_TRANSPARENT] set.
+ Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [code]transient parent[/code] set (see [method window_set_transient]).
</constant>
<constant name="WINDOW_FLAG_EXTEND_TO_TITLE" value="6" enum="WindowFlags">
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.
+ Use [method window_set_window_buttons_offset] to adjust minimize/maximize/close buttons offset.
+ Use [method window_get_safe_title_margins] to determine area under the title bar that is not covered by decorations.
[b]Note:[/b] This flag is implemented on macOS.
</constant>
<constant name="WINDOW_FLAG_MAX" value="7" enum="WindowFlags">
+ Max value of the [enum WindowFlags].
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
+ Sent when the mouse pointer enters the window, see [method window_set_window_event_callback].
</constant>
<constant name="WINDOW_EVENT_MOUSE_EXIT" value="1" enum="WindowEvent">
+ Sent when the mouse pointer exits the window, see [method window_set_window_event_callback].
</constant>
<constant name="WINDOW_EVENT_FOCUS_IN" value="2" enum="WindowEvent">
+ Sent when the window grabs focus, see [method window_set_window_event_callback].
</constant>
<constant name="WINDOW_EVENT_FOCUS_OUT" value="3" enum="WindowEvent">
+ Sent when the window loses focus, see [method window_set_window_event_callback].
</constant>
<constant name="WINDOW_EVENT_CLOSE_REQUEST" value="4" enum="WindowEvent">
+ Sent when the user has attempted to close the window (e.g. close button is pressed), see [method window_set_window_event_callback].
</constant>
<constant name="WINDOW_EVENT_GO_BACK_REQUEST" value="5" enum="WindowEvent">
+ Sent when the device "Back" button is pressed, see [method window_set_window_event_callback].
+ [b]Note:[/b] This event is implemented on Android.
</constant>
<constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent">
+ Sent when the window is moved to the display with different DPI, or display DPI is changed, see [method window_set_window_event_callback].
+ [b]Note:[/b] This flag is implemented on macOS.
</constant>
<constant name="WINDOW_EVENT_TITLEBAR_CHANGE" value="7" enum="WindowEvent">
+ Sent when the window title bar decoration is changed (e.g. [constant WINDOW_FLAG_EXTEND_TO_TITLE] is set or window entered/exited full screen mode), see [method window_set_window_event_callback].
+ [b]Note:[/b] This flag is implemented on macOS.
</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).
+ No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). Framerate is unlimited (nonwithstanding [member Engine.max_fps]).
</constant>
<constant name="VSYNC_ENABLED" value="1" enum="VSyncMode">
- Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible).
+ Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). Framerate is limited by the monitor refresh rate (nonwithstanding [member Engine.max_fps]).
</constant>
<constant name="VSYNC_ADAPTIVE" value="2" enum="VSyncMode">
- Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible), otherwise vertical synchronization is enabled to avoid tearing.
+ Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible). Otherwise, vertical synchronization is enabled to avoid tearing. Framerate is limited by the monitor refresh rate (nonwithstanding [member Engine.max_fps]).
</constant>
<constant name="VSYNC_MAILBOX" value="3" enum="VSyncMode">
- Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible).
- Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag.
+ Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). Framerate is unlimited (nonwithstanding [member Engine.max_fps]).
+ Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag (also called "Fast" V-Sync mode). [constant VSYNC_MAILBOX] works best when at least twice as many frames as the display refresh rate are rendered.
</constant>
<constant name="DISPLAY_HANDLE" value="0" enum="HandleType">
Display handle:
- - Linux: [code]X11::Display*[/code] for the display.
+ - Linux (X11): [code]X11::Display*[/code] for the display.
</constant>
<constant name="WINDOW_HANDLE" value="1" enum="HandleType">
Window handle:
- Windows: [code]HWND[/code] for the window.
- - Linux: [code]X11::Window*[/code] for the window.
+ - Linux (X11): [code]X11::Window*[/code] for the window.
- macOS: [code]NSWindow*[/code] for the window.
- iOS: [code]UIViewController*[/code] for the view controller.
- Android: [code]jObject[/code] for the activity.
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index e216059364..99e97fc25f 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -28,7 +28,7 @@
<return type="bool" />
<param index="0" name="class_name" type="StringName" />
<description>
- Returns [code]true[/code] if editing for the class specified by [param class_name] is disabled. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
+ Returns [code]true[/code] if editing for the class specified by [param class_name] is disabled. When disabled, the class will still appear in the Create New Node dialog but the Inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="is_class_property_disabled" qualifiers="const">
@@ -36,7 +36,7 @@
<param index="0" name="class_name" type="StringName" />
<param index="1" name="property" type="StringName" />
<description>
- Returns [code]true[/code] if [param property] is disabled in the class specified by [param class_name]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [param class_name].
+ Returns [code]true[/code] if [param property] is disabled in the class specified by [param class_name]. When a property is disabled, it won't appear in the Inspector when selecting a node that extends the class specified by [param class_name].
</description>
</method>
<method name="is_feature_disabled" qualifiers="const">
@@ -73,7 +73,7 @@
<param index="0" name="class_name" type="StringName" />
<param index="1" name="disable" type="bool" />
<description>
- If [param disable] is [code]true[/code], disables editing for the class specified by [param class_name]. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
+ If [param disable] is [code]true[/code], disables editing for the class specified by [param class_name]. When disabled, the class will still appear in the Create New Node dialog but the Inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="set_disable_class_property">
@@ -82,7 +82,7 @@
<param index="1" name="property" type="StringName" />
<param index="2" name="disable" type="bool" />
<description>
- If [param disable] is [code]true[/code], disables editing for [param property] in the class specified by [param class_name]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [param class_name].
+ If [param disable] is [code]true[/code], disables editing for [param property] in the class specified by [param class_name]. When a property is disabled, it won't appear in the Inspector when selecting a node that extends the class specified by [param class_name].
</description>
</method>
<method name="set_disable_feature">
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 891c8d7d92..51e3706981 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -4,6 +4,7 @@
A modified version of [FileDialog] used by the editor.
</brief_description>
<description>
+ [EditorFileDialog] is an enhanced version of [FileDialog] avaiable only to editor plugins. Additional features include list of favorited/recent files and ability to see files as thumbnails grid instead of list.
</description>
<tutorials>
</tutorials>
@@ -62,7 +63,7 @@
The dialog's open or save mode, which affects the selection behavior. See [enum FileMode]
</member>
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
- If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog].
+ If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog]. This property is synchronized with [member EditorSettings.filesystem/file_dialog/show_hidden_files].
</member>
<member name="title" type="String" setter="set_title" getter="get_title" overrides="Window" default="&quot;Save a File&quot;" />
</members>
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index a1a43dd5bf..108c670f59 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -33,7 +33,7 @@
<signal name="object_id_selected">
<param index="0" name="id" type="int" />
<description>
- Emitted when the Edit button of an [Object] has been pressed in the inspector. This is mainly used in the remote scene tree inspector.
+ Emitted when the Edit button of an [Object] has been pressed in the inspector. This is mainly used in the remote scene tree Inspector.
</description>
</signal>
<signal name="property_deleted">
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index c8a499260e..ba2f7b24bf 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorInspectorPlugin" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Plugin for adding custom property editors on inspector.
+ Plugin for adding custom property editors on the inspector.
</brief_description>
<description>
[EditorInspectorPlugin] allows adding custom property editors to [EditorInspector].
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 1e3b1f07ee..594c180894 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -70,6 +70,7 @@
<method name="get_editor_paths">
<return type="EditorPaths" />
<description>
+ Returns the [EditorPaths] singleton.
</description>
</method>
<method name="get_editor_scale" qualifiers="const">
@@ -151,6 +152,12 @@
Shows the given property on the given [param object] in the editor's Inspector dock. If [param inspector_only] is [code]true[/code], plugins will not attempt to edit [param object].
</description>
</method>
+ <method name="is_movie_maker_enabled" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if Movie Maker mode is enabled in the editor. See also [method set_movie_maker_enabled]. See [MovieWriter] for more information.
+ </description>
+ </method>
<method name="is_playing_scene" qualifiers="const">
<return type="bool" />
<description>
@@ -240,6 +247,13 @@
Sets the editor's current main screen to the one specified in [param name]. [param name] must match the text of the tab in question exactly ([code]2D[/code], [code]3D[/code], [code]Script[/code], [code]AssetLib[/code]).
</description>
</method>
+ <method name="set_movie_maker_enabled">
+ <return type="void" />
+ <param index="0" name="enabled" type="bool" />
+ <description>
+ Sets whether Movie Maker mode is enabled in the editor. See also [method is_movie_maker_enabled]. See [MovieWriter] for more information.
+ </description>
+ </method>
<method name="set_plugin_enabled">
<return type="void" />
<param index="0" name="plugin" type="String" />
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
index 9ee21fd63b..561ccdc6e7 100644
--- a/doc/classes/EditorNode3DGizmo.xml
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -168,16 +168,16 @@
Removes everything in the gizmo including meshes, collisions and handles.
</description>
</method>
- <method name="get_plugin" qualifiers="const">
- <return type="EditorNode3DGizmoPlugin" />
+ <method name="get_node_3d" qualifiers="const">
+ <return type="Node3D" />
<description>
- Returns the [EditorNode3DGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorNode3DGizmoPlugin.get_material].
+ Returns the [Node3D] node associated with this gizmo.
</description>
</method>
- <method name="get_spatial_node" qualifiers="const">
- <return type="Node3D" />
+ <method name="get_plugin" qualifiers="const">
+ <return type="EditorNode3DGizmoPlugin" />
<description>
- Returns the Node3D node associated with this gizmo.
+ Returns the [EditorNode3DGizmoPlugin] that owns this gizmo. It's useful to retrieve materials using [method EditorNode3DGizmoPlugin.get_material].
</description>
</method>
<method name="get_subgizmo_selection" qualifiers="const">
@@ -200,7 +200,7 @@
Sets the gizmo's hidden state. If [code]true[/code], the gizmo will be hidden. If [code]false[/code], it will be shown.
</description>
</method>
- <method name="set_spatial_node">
+ <method name="set_node_3d">
<return type="void" />
<param index="0" name="node" type="Node" />
<description>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 8a97dda9ae..24e1a2da7c 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -5,10 +5,10 @@
</brief_description>
<description>
[EditorNode3DGizmoPlugin] allows you to define a new type of Gizmo. There are two main ways to do so: extending [EditorNode3DGizmoPlugin] for the simpler gizmos, or creating a new [EditorNode3DGizmo] type. See the tutorial in the documentation for more info.
- To use [EditorNode3DGizmoPlugin], register it using the [method EditorPlugin.add_spatial_gizmo_plugin] method first.
+ To use [EditorNode3DGizmoPlugin], register it using the [method EditorPlugin.add_node_3d_gizmo_plugin] method first.
</description>
<tutorials>
- <link title="Spatial gizmo plugins">$DOCS_URL/tutorials/plugins/editor/spatial_gizmos.html</link>
+ <link title="Node3D gizmo plugins">$DOCS_URL/tutorials/plugins/editor/spatial_gizmos.html</link>
</tutorials>
<methods>
<method name="_can_be_hidden" qualifiers="virtual const">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 27cf410c15..e413c526f4 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -455,6 +455,14 @@
[/codeblocks]
</description>
</method>
+ <method name="add_node_3d_gizmo_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
+ <description>
+ Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D].
+ See [method add_inspector_plugin] for an example of how to register a plugin.
+ </description>
+ </method>
<method name="add_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
@@ -473,14 +481,6 @@
If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
</description>
</method>
- <method name="add_spatial_gizmo_plugin">
- <return type="void" />
- <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
- <description>
- Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D].
- See [method add_inspector_plugin] for an example of how to register a plugin.
- </description>
- </method>
<method name="add_tool_menu_item">
<return type="void" />
<param index="0" name="name" type="String" />
@@ -621,6 +621,13 @@
Removes an inspector plugin registered by [method add_import_plugin]
</description>
</method>
+ <method name="remove_node_3d_gizmo_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
+ <description>
+ Removes a gizmo plugin registered by [method add_node_3d_gizmo_plugin].
+ </description>
+ </method>
<method name="remove_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
@@ -635,13 +642,6 @@
Remove the [EditorScenePostImportPlugin], added with [method add_scene_post_import_plugin].
</description>
</method>
- <method name="remove_spatial_gizmo_plugin">
- <return type="void" />
- <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
- <description>
- Removes a gizmo plugin registered by [method add_spatial_gizmo_plugin].
- </description>
- </method>
<method name="remove_tool_menu_item">
<return type="void" />
<param index="0" name="name" type="String" />
@@ -691,11 +691,13 @@
</signal>
<signal name="project_settings_changed">
<description>
+ Emitted when any project setting has changed.
</description>
</signal>
<signal name="resource_saved">
<param index="0" name="resource" type="Resource" />
<description>
+ Emitted when the given [param resource] was saved on disc.
</description>
</signal>
<signal name="scene_changed">
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 9170c449bf..2aca19510b 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -61,6 +61,7 @@
<method name="update_property">
<return type="void" />
<description>
+ Forces refresh of the property display.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index dfc04c9cde..a02fd215d8 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -30,6 +30,7 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] The script is run in the Editor context, which means the output is visible in the console window started with the Editor (stdout) instead of the usual Godot [b]Output[/b] dock.
+ [b]Note:[/b] EditorScript is [RefCounted], meaning it is destroyed when nothing references it. This can cause errors during asynchronous operations if there are no references to the script.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 7f3ffce9b7..799bd45cee 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -196,10 +196,10 @@
The thumbnail size to use in the FileSystem dock (in pixels). See also [member filesystem/file_dialog/thumbnail_size].
</member>
<member name="docks/property_editor/auto_refresh_interval" type="float" setter="" getter="">
- The refresh interval to use for the inspector dock's properties. The effect of this setting is mainly noticeable when adjusting gizmos in the 2D/3D editor and looking at the inspector at the same time. Lower values make the inspector more often, but take up more CPU time.
+ The refresh interval to use for the Inspector dock's properties. The effect of this setting is mainly noticeable when adjusting gizmos in the 2D/3D editor and looking at the inspector at the same time. Lower values make the inspector more often, but take up more CPU time.
</member>
<member name="docks/property_editor/subresource_hue_tint" type="float" setter="" getter="">
- The tint intensity to use for the subresources background in the inspector dock. The tint is used to distinguish between different subresources in the inspector. Higher values result in a more noticeable background color difference.
+ The tint intensity to use for the subresources background in the Inspector dock. The tint is used to distinguish between different subresources in the inspector. Higher values result in a more noticeable background color difference.
</member>
<member name="docks/scene_tree/auto_expand_to_selected" type="bool" setter="" getter="">
If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected.
@@ -363,7 +363,7 @@
The color to use for the selection box that surrounds selected nodes in the 3D editor viewport. The color's alpha channel influences the selection box's opacity.
</member>
<member name="editors/3d_gizmos/gizmo_colors/instantiated" type="Color" setter="" getter="">
- The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instanced scene file (from the perspective of the current scene).
+ The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instantiated scene file (from the perspective of the current scene).
</member>
<member name="editors/3d_gizmos/gizmo_colors/joint" type="Color" setter="" getter="">
The 3D editor gizmo color for [Joint3D]s and [PhysicalBone3D]s.
@@ -457,6 +457,12 @@
If [code]true[/code], when saving a file, the editor will rename the old file to a different name, save a new file, then only remove the old file once the new file has been saved. This makes loss of data less likely to happen if the editor or operating system exits unexpectedly while saving (e.g. due to a crash or power outage).
[b]Note:[/b] On Windows, this feature can interact negatively with certain antivirus programs. In this case, you may have to set this to [code]false[/code] to prevent file locking issues.
</member>
+ <member name="interface/editor/accept_dialog_cancel_ok_buttons" type="int" setter="" getter="">
+ How to position the Cancel and OK buttons in the editor's [AcceptDialog]s. Different platforms have different standard behaviors for this, which can be overridden using this setting. This is useful if you use Godot both on Windows and macOS/Linux and your Godot muscle memory is stronger than your OS specific one.
+ - [b]Auto[/b] follows the platform convention: Cancel first on macOS and Linux, OK first on Windows.
+ - [b]Cancel First[/b] forces the ordering Cancel/OK.
+ - [b]OK First[/b] forces the ordering OK/Cancel.
+ </member>
<member name="interface/editor/automatically_open_screenshots" type="bool" setter="" getter="">
If [code]true[/code], automatically opens screenshots with the default program associated to [code].png[/code] files after a screenshot is taken using the [b]Editor &gt; Take Screenshot[/b] action.
</member>
@@ -671,19 +677,19 @@
If [code]true[/code], displays line length guidelines to help you keep line lengths in check. See also [member text_editor/appearance/guidelines/line_length_guideline_soft_column] and [member text_editor/appearance/guidelines/line_length_guideline_hard_column].
</member>
<member name="text_editor/appearance/gutters/highlight_type_safe_lines" type="bool" setter="" getter="">
- If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines will run faster in Godot 4.0 and later thanks to typed instructions.
+ If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines may run faster thanks to typed instructions.
</member>
<member name="text_editor/appearance/gutters/line_numbers_zero_padded" type="bool" setter="" getter="">
If [code]true[/code], displays line numbers with zero padding (e.g. [code]007[/code] instead of [code]7[/code]).
</member>
<member name="text_editor/appearance/gutters/show_bookmark_gutter" type="bool" setter="" getter="">
- If [code]true[/code], displays a gutter at the left containing icons for bookmarks.
+ If [code]true[/code], displays icons for bookmarks in a gutter at the left. Bookmarks remain functional when this setting is disabled.
</member>
<member name="text_editor/appearance/gutters/show_info_gutter" type="bool" setter="" getter="">
If [code]true[/code], displays a gutter at the left containing icons for methods with signal connections.
</member>
<member name="text_editor/appearance/gutters/show_line_numbers" type="bool" setter="" getter="">
- If [code]true[/code], displays line numbers in the gutter at the left.
+ If [code]true[/code], displays line numbers in a gutter at the left.
</member>
<member name="text_editor/appearance/lines/code_folding" type="bool" setter="" getter="">
If [code]true[/code], displays the folding arrows next to indented code sections and allows code folding. If [code]false[/code], hides the folding arrows next to indented code sections and disallows code folding.
@@ -752,7 +758,7 @@
[b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster.
</member>
<member name="text_editor/completion/add_type_hints" type="bool" setter="" getter="">
- If [code]true[/code], adds static typing hints such as [code]-&gt; void[/code] and [code]: int[/code] when performing method definition autocompletion.
+ If [code]true[/code], adds static typing hints such as [code]-&gt; void[/code] and [code]: int[/code] when using code autocompletion or when creating onready variables by drag and dropping nodes into the script editor while pressing the [kbd]Ctrl[/kbd] key.
</member>
<member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter="">
If [code]true[/code], automatically completes braces when making use of code completion.
@@ -803,7 +809,7 @@
The script editor's background color. If set to a translucent color, the editor theme's base color will be visible behind.
</member>
<member name="text_editor/theme/highlighting/base_type_color" type="Color" setter="" getter="">
- The script editor's base type color (used for types like [Vector2], [Vector3], ...).
+ The script editor's base type color (used for types like [Vector2], [Vector3], [Color], ...).
</member>
<member name="text_editor/theme/highlighting/bookmark_color" type="Color" setter="" getter="">
The script editor's bookmark icon color (displayed in the gutter).
@@ -863,10 +869,10 @@
[b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function definition color configured in the syntax theme for function definitions (e.g. [code]func _ready():[/code]).
</member>
<member name="text_editor/theme/highlighting/keyword_color" type="Color" setter="" getter="">
- The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], some built-in methods, ...).
+ The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], [code]extends[/code], ...).
</member>
<member name="text_editor/theme/highlighting/line_length_guideline_color" type="Color" setter="" getter="">
- The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with an opacity twice as low.
+ The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with half of its opacity.
</member>
<member name="text_editor/theme/highlighting/line_number_color" type="Color" setter="" getter="">
The script editor's color for line numbers. See also [member text_editor/theme/highlighting/safe_line_number_color].
@@ -907,7 +913,7 @@
The script editor's background color for text. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color].
</member>
<member name="text_editor/theme/highlighting/user_type_color" type="Color" setter="" getter="">
- The script editor's color for user-defined types (using [code]@class_name[/code]).
+ The script editor's color for user-defined types (using [code]class_name[/code]).
</member>
<member name="text_editor/theme/highlighting/word_highlighted_color" type="Color" setter="" getter="">
The script editor's color for words highlighted by selecting them. Only visible if [member text_editor/appearance/caret/highlight_all_occurrences] is [code]true[/code].
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 2ada211dab..9961e11f7d 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -10,13 +10,16 @@
</tutorials>
<members>
<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
+ If [code]true[/code], the slider will not draw background.
</member>
<member name="hide_slider" type="bool" setter="set_hide_slider" getter="is_hiding_slider" default="false">
If [code]true[/code], the slider is hidden.
</member>
<member name="label" type="String" setter="set_label" getter="get_label" default="&quot;&quot;">
+ The text that displays to the left of the value.
</member>
<member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false">
+ If [code]true[/code], the slider can't be interacted with.
</member>
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
index 1350e4487c..c1e771d653 100644
--- a/doc/classes/EditorUndoRedoManager.xml
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -107,6 +107,18 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="history_changed">
+ <description>
+ Emitted when the list of actions in any history has changed, either when an action is commited or a history is cleared.
+ </description>
+ </signal>
+ <signal name="version_changed">
+ <description>
+ Emitted when the version of any history has changed as a result of undo or redo call.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="GLOBAL_HISTORY" value="0" enum="SpecialHistory">
Global history not associated with any scene, but with external resources etc.
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index ecf3d87a70..821fae37a6 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -146,11 +146,13 @@
<return type="ScriptLanguage" />
<param index="0" name="index" type="int" />
<description>
+ Returns an instance of a [ScriptLanguage] with the given index.
</description>
</method>
<method name="get_script_language_count">
<return type="int" />
<description>
+ Returns the number of available script languages. Use with [method get_script_language].
</description>
</method>
<method name="get_singleton" qualifiers="const">
@@ -163,6 +165,7 @@
<method name="get_singleton_list" qualifiers="const">
<return type="PackedStringArray" />
<description>
+ Returns a list of available global singletons.
</description>
</method>
<method name="get_version_info" qualifiers="const">
@@ -244,6 +247,7 @@
<return type="void" />
<param index="0" name="language" type="ScriptLanguage" />
<description>
+ Registers a [ScriptLanguage] instance to be available with [code]ScriptServer[/code].
</description>
</method>
<method name="register_singleton">
@@ -251,22 +255,32 @@
<param index="0" name="name" type="StringName" />
<param index="1" name="instance" type="Object" />
<description>
+ Registers the given object as a singleton, globally available under [param name].
</description>
</method>
<method name="unregister_singleton">
<return type="void" />
<param index="0" name="name" type="StringName" />
<description>
+ Unregisters the singleton registered under [param name]. The singleton object is not freed. Only works with user-defined singletons created with [method register_singleton].
</description>
</method>
</methods>
<members>
+ <member name="max_fps" type="int" setter="set_max_fps" getter="get_max_fps" default="0">
+ The maximum number of frames per second that can be rendered. A value of [code]0[/code] means "no limit". The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project logic and rendering.
+ Limiting the FPS can be useful to reduce system power consumption, which reduces heat and noise emissions (and improves battery life on mobile devices).
+ If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
+ If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Enabled[/code], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using a FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
+ If [member ProjectSettings.display/window/vsync/vsync_mode] is [code]Disabled[/code], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios.
+ See also [member physics_ticks_per_second] and [member ProjectSettings.application/run/max_fps].
+ </member>
<member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5">
Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of the in-game clock and real clock but smooth out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended.
[b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code].
</member>
<member name="physics_ticks_per_second" type="int" setter="set_physics_ticks_per_second" getter="get_physics_ticks_per_second" default="60">
- The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around collision tunneling issues, but keep in mind doing so will increase CPU usage. See also [member target_fps] and [member ProjectSettings.physics/common/physics_ticks_per_second].
+ The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. This value should generally always be set to [code]60[/code] or above, as Godot doesn't interpolate the physics step. As a result, values lower than [code]60[/code] will look stuttery. This value can be increased to make input more reactive or work around collision tunneling issues, but keep in mind doing so will increase CPU usage. See also [member max_fps] and [member ProjectSettings.physics/common/physics_ticks_per_second].
[b]Note:[/b] Only 8 physics ticks may be simulated per rendered frame at most. If more than 8 physics ticks have to be simulated per rendered frame to keep up with rendering, the game will appear to slow down (even if [code]delta[/code] is used consistently in physics calculations). Therefore, it is recommended not to increase [member physics_ticks_per_second] above 240. Otherwise, the game will slow down when the rendering framerate goes below 30 FPS.
</member>
<member name="print_error_messages" type="bool" setter="set_print_error_messages" getter="is_printing_error_messages" default="true">
@@ -274,9 +288,6 @@
[b]Warning:[/b] If you set this to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. If this is set to [code]false[/code] in a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default).
[b]Note:[/b] This property does not impact the editor's Errors tab when running a project from the editor.
</member>
- <member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0">
- The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit. See also [member physics_ticks_per_second] and [member ProjectSettings.debug/settings/fps/force_fps].
- </member>
<member name="time_scale" type="float" setter="set_time_scale" getter="get_time_scale" default="1.0">
Controls how fast or slow the in-game clock ticks versus the real life one. It defaults to 1.0. A value of 2.0 means the game moves twice as fast as real life, whilst a value of 0.5 means the game moves at half the regular speed.
</member>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 243a28e73d..33b6a786ae 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -301,6 +301,7 @@
<member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.05">
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.
+ To make volumetric fog work as a volumetric [i]lighting[/i] solution, set [member volumetric_fog_density] to the lowest non-zero value ([code]0.0001[/code]) then increase lights' [member Light3D.light_volumetric_fog_energy] to values between [code]10000[/code] and [code]100000[/code] to compensate for the very low density.
</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.
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index 3a397f56a9..4670e0c382 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -12,7 +12,7 @@
var expression = Expression.new()
func _ready():
- $LineEdit.connect("text_submitted", self, "_on_text_submitted")
+ $LineEdit.text_submitted.connect(self._on_text_submitted)
func _on_text_submitted(command):
var error = expression.parse(command)
@@ -28,7 +28,7 @@
public override void _Ready()
{
- GetNode("LineEdit").Connect("text_submitted", this, nameof(OnTextEntered));
+ GetNode("LineEdit").TextSubmitted += OnTextEntered;
}
private void OnTextEntered(string command)
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
index 22048c6761..5578f449b3 100644
--- a/doc/classes/FileSystemDock.xml
+++ b/doc/classes/FileSystemDock.xml
@@ -32,7 +32,7 @@
</signal>
<signal name="folder_moved">
<param index="0" name="old_folder" type="String" />
- <param index="1" name="new_file" type="String" />
+ <param index="1" name="new_folder" type="String" />
<description>
</description>
</signal>
diff --git a/doc/classes/FlowContainer.xml b/doc/classes/FlowContainer.xml
index d449049ef1..7a324160c9 100644
--- a/doc/classes/FlowContainer.xml
+++ b/doc/classes/FlowContainer.xml
@@ -18,11 +18,25 @@
</method>
</methods>
<members>
+ <member name="alignment" type="int" setter="set_alignment" getter="get_alignment" enum="FlowContainer.AlignmentMode" default="0">
+ The alignment of the container's children (must be one of [constant ALIGNMENT_BEGIN], [constant ALIGNMENT_CENTER], or [constant ALIGNMENT_END]).
+ </member>
<member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
If [code]true[/code], the [FlowContainer] will arrange its children vertically, rather than horizontally.
Can't be changed when using [HFlowContainer] and [VFlowContainer].
</member>
</members>
+ <constants>
+ <constant name="ALIGNMENT_BEGIN" value="0" enum="AlignmentMode">
+ The child controls will be arranged at the beginning of the container, i.e. top if orientation is vertical, left if orientation is horizontal (right for RTL layout).
+ </constant>
+ <constant name="ALIGNMENT_CENTER" value="1" enum="AlignmentMode">
+ The child controls will be centered in the container.
+ </constant>
+ <constant name="ALIGNMENT_END" value="2" enum="AlignmentMode">
+ The child controls will be arranged at the end of the container, i.e. bottom if orientation is vertical, right if orientation is horizontal (left for RTL layout).
+ </constant>
+ </constants>
<theme_items>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
The horizontal separation of children nodes.
diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml
index 7428d6169a..aab6be4212 100644
--- a/doc/classes/FogMaterial.xml
+++ b/doc/classes/FogMaterial.xml
@@ -15,6 +15,7 @@
</member>
<member name="density" type="float" setter="set_density" getter="get_density" default="1.0">
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.
+ [b]Note:[/b] Due to limited precision, [member density] values between [code]-0.001[/code] and [code]0.001[/code] (exclusive) act like [code]0.0[/code]. This does not apply to [member Environment.volumetric_fog_density].
</member>
<member name="density_texture" type="Texture3D" setter="set_density_texture" getter="get_density_texture">
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].
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index df378d9d2f..dac822ae2f 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -262,7 +262,7 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="texture_index" type="int" />
<description>
- Returns a copy of the array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
+ Returns a copy of the array containing glyph packing data.
</description>
</method>
<method name="get_transform" qualifiers="const">
@@ -522,7 +522,7 @@
<param index="2" name="texture_index" type="int" />
<param index="3" name="offset" type="PackedInt32Array" />
<description>
- Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty (for the fonts without dynamic glyph generation support).
+ Sets array containing glyph packing data.
</description>
</method>
<method name="set_transform">
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index f41e34c43a..4916171900 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -9,7 +9,8 @@
</description>
<tutorials>
<link title="Particle systems (2D)">$DOCS_URL/tutorials/2d/particle_systems_2d.html</link>
- <link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
+ <link title="2D Particles Demo">https://godotengine.org/asset-library/asset/118</link>
+ <link title="2D Dodge The Creeps Demo (uses GPUParticles2D for the trail behind the player)">https://godotengine.org/asset-library/asset/515</link>
</tutorials>
<methods>
<method name="capture_rect" qualifiers="const">
@@ -52,7 +53,7 @@
How rapidly particles in an emission cycle are emitted. If greater than [code]0[/code], there will be a gap in emissions before the next cycle begins.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index e7b436010e..d0be4d784a 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -84,7 +84,7 @@
Time ratio between each emission. If [code]0[/code], particles are emitted continuously. If [code]1[/code], all particles are emitted simultaneously.
</member>
<member name="fixed_fps" type="int" setter="set_fixed_fps" getter="get_fixed_fps" default="30">
- The particle system's frame rate is fixed to a value. For instance, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
+ The particle system's frame rate is fixed to a value. For example, changing the value to 2 will make the particles render at 2 frames per second. Note this does not slow down the simulation of the particle system itself.
</member>
<member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true">
If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect.
diff --git a/doc/classes/HSlider.xml b/doc/classes/HSlider.xml
index 60208eee0f..cb0a8b34db 100644
--- a/doc/classes/HSlider.xml
+++ b/doc/classes/HSlider.xml
@@ -10,6 +10,9 @@
<tutorials>
</tutorials>
<theme_items>
+ <theme_item name="grabber_offset" data_type="constant" type="int" default="0">
+ Vertical offset of the grabber.
+ </theme_item>
<theme_item name="grabber" data_type="icon" type="Texture2D">
The texture for the grabber (the draggable element).
</theme_item>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index b138a55ea3..88cea6820e 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -26,7 +26,7 @@
<param index="1" name="src_rect" type="Rect2i" />
<param index="2" name="dst" type="Vector2i" />
<description>
- Alpha-blends [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blend_rect_mask">
@@ -36,7 +36,7 @@
<param index="2" name="src_rect" type="Rect2i" />
<param index="3" name="dst" type="Vector2i" />
<description>
- Alpha-blends [param src_rect] from [param src] image to this image using [param mask] image at coordinates [param dst], clipped accordingly to both image bounds. Alpha channels are required for both [param src] and [param mask]. [param dst] pixels and [param src] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image using [param mask] image at coordinates [param dst], clipped accordingly to both image bounds. Alpha channels are required for both [param src] and [param mask]. [param dst] pixels and [param src] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blit_rect">
@@ -45,7 +45,7 @@
<param index="1" name="src_rect" type="Rect2i" />
<param index="2" name="dst" type="Vector2i" />
<description>
- Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
+ Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="blit_rect_mask">
@@ -55,7 +55,7 @@
<param index="2" name="src_rect" type="Rect2i" />
<param index="3" name="dst" type="Vector2i" />
<description>
- Blits [param src_rect] area from [param src] image to this image at the coordinates given by [param dst], clipped accordingly to both image bounds. [param src] pixel is copied onto [param dst] if the corresponding [param mask] pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
+ Blits [param src_rect] area from [param src] image to this image at the coordinates given by [param dst], clipped accordingly to both image bounds. [param src] pixel is copied onto [param dst] if the corresponding [param mask] pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with non-positive size is treated as empty.
</description>
</method>
<method name="bump_map_to_normal_map">
@@ -111,8 +111,8 @@
Copies [param src] image to this image.
</description>
</method>
- <method name="create">
- <return type="void" />
+ <method name="create" qualifiers="static">
+ <return type="Image" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
<param index="2" name="use_mipmaps" type="bool" />
@@ -121,8 +121,8 @@
Creates an empty image of given size and format. See [enum Format] constants. If [param use_mipmaps] is [code]true[/code] then generate mipmaps for this image. See the [method generate_mipmaps].
</description>
</method>
- <method name="create_from_data">
- <return type="void" />
+ <method name="create_from_data" qualifiers="static">
+ <return type="Image" />
<param index="0" name="width" type="int" />
<param index="1" name="height" type="int" />
<param index="2" name="use_mipmaps" type="bool" />
@@ -197,7 +197,6 @@
<param index="0" name="renormalize" type="bool" default="false" />
<description>
Generates mipmaps for the image. Mipmaps are precalculated lower-resolution copies of the image that are automatically used if the image needs to be scaled down when rendered. They help improve image quality and performance when rendering. This method returns an error if the image is compressed, in a custom format, or if the image's width/height is [code]0[/code].
- [b]Note:[/b] Mipmap generation is done on the CPU, is single-threaded and is [i]always[/i] done on the main thread. This means generating mipmaps will result in noticeable stuttering during gameplay, even if [method generate_mipmaps] is called from a [Thread].
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -455,6 +454,17 @@
Saves the image as a WebP (Web Picture) file to a byte array. By default it will save lossless. If [param lossy] is true, the image will be saved lossy, using the [param quality] setting between 0.0 and 1.0 (inclusive).
</description>
</method>
+ <method name="set_data">
+ <return type="void" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="use_mipmaps" type="bool" />
+ <param index="3" name="format" type="int" enum="Image.Format" />
+ <param index="4" name="data" type="PackedByteArray" />
+ <description>
+ Overwrites data of an existing [Image]. Non-static equivalent of [method create_from_data].
+ </description>
+ </method>
<method name="set_pixel">
<return type="void" />
<param index="0" name="x" type="int" />
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 56b95fc755..89d52caa02 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -157,7 +157,7 @@
<method name="get_mouse_button_mask" qualifiers="const">
<return type="int" enum="MouseButton" />
<description>
- Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together.
+ Returns mouse buttons as a bitmask. If multiple mouse buttons are pressed at the same time, the bits are added together. Equivalent to [method DisplayServer.mouse_get_button_state].
</description>
</method>
<method name="get_vector" qualifiers="const">
diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml
index 2af88149b6..04d8cab065 100644
--- a/doc/classes/InputEventMIDI.xml
+++ b/doc/classes/InputEventMIDI.xml
@@ -90,7 +90,7 @@
The pressure of the MIDI signal. This value ranges from 0 to 127. For many devices, this value is always zero.
</member>
<member name="velocity" type="int" setter="set_velocity" getter="get_velocity" default="0">
- The velocity of the MIDI signal. This value ranges from 0 to 127. For a piano, this corresponds to how quickly the key was pressed, and is rarely above about 110 in practice.
+ The velocity of the MIDI signal. This value ranges from 0 to 127. For a piano, this corresponds to how quickly the key was pressed, and is rarely above about 110 in practice. Note that some MIDI devices may send a [constant MIDI_MESSAGE_NOTE_ON] message with zero velocity and expect this to be treated the same as a [constant MIDI_MESSAGE_NOTE_OFF] message, but device implementations vary so Godot reports event data exactly as received.
</member>
</members>
</class>
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index fb50454917..346b6bf732 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -11,6 +11,9 @@
<link title="InputEvent">$DOCS_URL/tutorials/inputs/inputevent.html</link>
</tutorials>
<members>
+ <member name="double_tap" type="bool" setter="set_double_tap" getter="is_double_tap" default="false">
+ If [code]true[/code], the touch's state is a double tap.
+ </member>
<member name="index" type="int" setter="set_index" getter="get_index" default="0">
The touch index in the case of a multi-touch event. One index = one finger.
</member>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index e9ebbc0a41..60e20cd97d 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -55,6 +55,7 @@
</member>
<member name="light_angular_distance" type="float" setter="set_param" getter="get_param" default="0.0">
The light's angular size in degrees. Increasing this will make shadows softer at greater distances. Only available for [DirectionalLight3D]s. For reference, the Sun from the Earth is approximately [code]0.5[/code].
+ [b]Note:[/b] [member light_angular_distance] is not affected by [member Node3D.scale] (the light's scale or its parent's scale).
</member>
<member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="2">
The light's bake mode. This will affect the global illumination techniques that have an effect on the light's rendering. See [enum BakeMode].
@@ -91,6 +92,7 @@
</member>
<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
The size of the light in Godot units. Only available for [OmniLight3D]s and [SpotLight3D]s. Increasing this value will make the light fade out slower and shadows appear blurrier. This can be used to simulate area lights to an extent.
+ [b]Note:[/b] [member light_size] is not affected by [member Node3D.scale] (the light's scale or its parent's scale).
</member>
<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
The intensity of the specular blob in objects affected by the light. At [code]0[/code], the light becomes a pure diffuse light. When not baking emission, this can be used to avoid unrealistic reflections when placing lights above an emissive surface.
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 14fb864ca8..e57cc68b36 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -224,6 +224,9 @@
<member name="secret_character" type="String" setter="set_secret_character" getter="get_secret_character" default="&quot;•&quot;">
The character to use to mask secret input (defaults to "•"). Only a single character can be used as the secret character.
</member>
+ <member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
+ If [code]true[/code], the [LineEdit] will select the whole text when it gains focus.
+ </member>
<member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true">
If [code]false[/code], it's impossible to select the text using mouse nor keyboard.
</member>
diff --git a/doc/classes/Marker3D.xml b/doc/classes/Marker3D.xml
index 5ad1cdf513..0d49b376a8 100644
--- a/doc/classes/Marker3D.xml
+++ b/doc/classes/Marker3D.xml
@@ -8,4 +8,9 @@
</description>
<tutorials>
</tutorials>
+ <members>
+ <member name="gizmo_extents" type="float" setter="set_gizmo_extents" getter="get_gizmo_extents" default="0.25">
+ Size of the gizmo cross that appears in the editor.
+ </member>
+ </members>
</class>
diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml
index 3ef0572e9f..e8505937ff 100644
--- a/doc/classes/MenuBar.xml
+++ b/doc/classes/MenuBar.xml
@@ -106,9 +106,6 @@
<member name="prefer_global_menu" type="bool" setter="set_prefer_global_menu" getter="is_prefer_global_menu" default="true">
If [code]true[/code], [MenuBar] will use system global menu when supported.
</member>
- <member name="shortcut_context" type="Node" setter="set_shortcut_context" getter="get_shortcut_context">
- The [Node] which must be a parent of the focused GUI [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
- </member>
<member name="start_index" type="int" setter="set_start_index" getter="get_start_index" default="-1">
Position in the global menu to insert first [MenuBar] item at.
</member>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index d3d5a7bfaa..facbe5fd0f 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -129,7 +129,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the smallest [AABB] enclosing this mesh in local space. Not affected by [code]custom_aabb[/code]. See also [method VisualInstance3D.get_transformed_aabb].
+ Returns the smallest [AABB] enclosing this mesh in local space. Not affected by [code]custom_aabb[/code].
[b]Note:[/b] This is only implemented for [ArrayMesh] and [PrimitiveMesh].
</description>
</method>
diff --git a/doc/classes/MovieWriter.xml b/doc/classes/MovieWriter.xml
index f2509ad2b2..1652dd52aa 100644
--- a/doc/classes/MovieWriter.xml
+++ b/doc/classes/MovieWriter.xml
@@ -4,7 +4,7 @@
Abstract class for non-real-time video recording encoders.
</brief_description>
<description>
- Godot can record videos with non-real-time simulation. Like the [code]--fixed-fps[/code] command line argument, this forces the reported [code]delta[/code] in [method Node._process] functions to be identical across frames, regardless of how long it actually took to render the frame. This can be used to record high-quality videos with perfect frame pacing regardless of your hardware's capabilities.
+ Godot can record videos with non-real-time simulation. Like the [code]--fixed-fps[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url], this forces the reported [code]delta[/code] in [method Node._process] functions to be identical across frames, regardless of how long it actually took to render the frame. This can be used to record high-quality videos with perfect frame pacing regardless of your hardware's capabilities.
Godot has 2 built-in [MovieWriter]s:
- AVI container with MJPEG for video and uncompressed audio ([code].avi[/code] file extension). Lossy compression, medium file sizes, fast encoding. The lossy compression quality can be adjusted by changing [member ProjectSettings.editor/movie_writer/mjpeg_quality]. The resulting file can be viewed in most video players, but it must be converted to another format for viewing on the web or by Godot with [VideoStreamPlayer]. MJPEG does not support transparency. AVI output is currently limited to a file of 4 GB in size at most.
- PNG image sequence for video and WAV for audio ([code].png[/code] file extension). Lossless compression, large file sizes, slow encoding. Designed to be encoded to a video file with another tool such as [url=https://ffmpeg.org/]FFmpeg[/url] after recording. Transparency is currently not supported, even if the root viewport is set to be transparent.
@@ -46,7 +46,7 @@
<param index="1" name="fps" type="int" />
<param index="2" name="base_path" type="String" />
<description>
- Called once before the engine starts writing video and audio data. [param movie_size] is the width and height of the video to save. [param fps] is the number of frames per second specified in the project settings or using the [code]--fixed-fps &lt;fps&gt;[/code] command line argument.
+ Called once before the engine starts writing video and audio data. [param movie_size] is the width and height of the video to save. [param fps] is the number of frames per second specified in the project settings or using the [code]--fixed-fps &lt;fps&gt;[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
</description>
</method>
<method name="_write_end" qualifiers="virtual">
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index ce2b5f2584..d8a232b3cf 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -19,7 +19,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the visibility axis-aligned bounding box in local space. See also [method VisualInstance3D.get_transformed_aabb].
+ Returns the visibility axis-aligned bounding box in local space.
</description>
</method>
<method name="get_instance_color" qualifiers="const">
diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml
index 0f57ff9e55..6661fbfe0b 100644
--- a/doc/classes/MultiplayerPeer.xml
+++ b/doc/classes/MultiplayerPeer.xml
@@ -13,6 +13,20 @@
<link title="WebRTC Signaling Demo">https://godotengine.org/asset-library/asset/537</link>
</tutorials>
<methods>
+ <method name="close">
+ <return type="void" />
+ <description>
+ Immediately close the multiplayer peer returning to the state [constant CONNECTION_DISCONNECTED]. Connected peers will be dropped without emitting [signal peer_disconnected].
+ </description>
+ </method>
+ <method name="disconnect_peer">
+ <return type="void" />
+ <param index="0" name="peer" type="int" />
+ <param index="1" name="force" type="bool" default="false" />
+ <description>
+ Disconnects the given [param peer] from this host. If [param force] is [code]true[/code] the [signal peer_disconnected] signal will not be emitted for this peer.
+ </description>
+ </method>
<method name="generate_unique_id" qualifiers="const">
<return type="int" />
<description>
@@ -25,10 +39,22 @@
Returns the current state of the connection. See [enum ConnectionStatus].
</description>
</method>
+ <method name="get_packet_channel" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the channel over which the next available packet was received. See [method PacketPeer.get_available_packet_count].
+ </description>
+ </method>
+ <method name="get_packet_mode" qualifiers="const">
+ <return type="int" enum="MultiplayerPeer.TransferMode" />
+ <description>
+ Returns the [enum MultiplayerPeer.TransferMode] the remote peer used to send the next available packet. See [method PacketPeer.get_available_packet_count].
+ </description>
+ </method>
<method name="get_packet_peer" qualifiers="const">
<return type="int" />
<description>
- Returns the ID of the [MultiplayerPeer] who sent the most recent packet.
+ Returns the ID of the [MultiplayerPeer] who sent the next available packet. See [method PacketPeer.get_available_packet_count].
</description>
</method>
<method name="get_unique_id" qualifiers="const">
@@ -37,6 +63,12 @@
Returns the ID of this [MultiplayerPeer].
</description>
</method>
+ <method name="is_server_relay_supported" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns true if the server can act as a relay in the current configuration (i.e. if the higher level [MultiplayerAPI] should notify connected clients of other peers, and implement a relay protocol to allow communication between them).
+ </description>
+ </method>
<method name="poll">
<return type="void" />
<description>
@@ -61,7 +93,7 @@
[b]Note:[/b] The default channel ([code]0[/code]) actually works as 3 separate channels (one for each [enum TransferMode]) so that [constant TRANSFER_MODE_RELIABLE] and [constant TRANSFER_MODE_UNRELIABLE_ORDERED] does not interact with each other by default. Refer to the specific network API documentation (e.g. ENet or WebRTC) to learn how to set up channels correctly.
</member>
<member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="MultiplayerPeer.TransferMode" default="2">
- The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode].
+ The manner in which to send packets to the target peer. See [enum TransferMode], and the [method set_target_peer] method.
</member>
</members>
<signals>
diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml
index 18bc18e6e7..5717135b80 100644
--- a/doc/classes/MultiplayerPeerExtension.xml
+++ b/doc/classes/MultiplayerPeerExtension.xml
@@ -9,6 +9,20 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_close" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the multiplayer peer should be immediately closed (see [method MultiplayerPeer.close]).
+ </description>
+ </method>
+ <method name="_disconnect_peer" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="p_peer" type="int" />
+ <param index="1" name="p_force" type="bool" />
+ <description>
+ Called when the connected [param p_peer] should be forcibly disconnected (see [method MultiplayerPeer.disconnect_peer]).
+ </description>
+ </method>
<method name="_get_available_packet_count" qualifiers="virtual const">
<return type="int" />
<description>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 3437e0eca4..8cf7824ff7 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
2D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. [NavigationAgent2D] is physics safe.
- [b]Note:[/b] After [method set_target_location] is used it is required to use the [method get_next_location] function once every physics frame to update the internal path logic of the NavigationAgent. The returned vector position from this function should be used as the next movement position for the agent's parent Node.
+ [b]Note:[/b] After setting [member target_location] it is required to use the [method get_next_location] function once every physics frame to update the internal path logic of the NavigationAgent. The returned vector position from this function should be used as the next movement position for the agent's parent Node.
</description>
<tutorials>
</tutorials>
@@ -13,7 +13,7 @@
<method name="distance_to_target" qualifiers="const">
<return type="float" />
<description>
- Returns the distance to the target location, using the agent's global position. The user must set the target location with [method set_target_location] in order for this to be accurate.
+ Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate.
</description>
</method>
<method name="get_final_location">
@@ -59,12 +59,6 @@
Returns the [RID] of this agent on the [NavigationServer2D].
</description>
</method>
- <method name="get_target_location" qualifiers="const">
- <return type="Vector2" />
- <description>
- Returns the user defined [Vector2] after setting the target location.
- </description>
- </method>
<method name="is_navigation_finished">
<return type="bool" />
<description>
@@ -74,13 +68,13 @@
<method name="is_target_reachable">
<return type="bool" />
<description>
- Returns true if the target location is reachable. The target location is set using [method set_target_location].
+ Returns true if [member target_location] is reachable.
</description>
</method>
<method name="is_target_reached" qualifiers="const">
<return type="bool" />
<description>
- Returns true if the target location is reached. The target location is set using [method set_target_location]. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
+ Returns true if [member target_location] is reached. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
</description>
</method>
<method name="set_navigation_layer_value">
@@ -98,13 +92,6 @@
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
- <method name="set_target_location">
- <return type="void" />
- <param index="0" name="location" type="Vector2" />
- <description>
- Sets the user desired final location. This will clear the current navigation path.
- </description>
- </method>
<method name="set_velocity">
<return type="void" />
<param index="0" name="velocity" type="Vector2" />
@@ -142,6 +129,9 @@
<member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
The distance threshold before the final target point is considered to be reached. This will allow an agent to not have to hit the point of the final target exactly, but only the area. If this value is set to low the NavigationAgent will be stuck in a repath loop cause it will constantly overshoot or undershoot the distance to the final target point on each physics frame update.
</member>
+ <member name="target_location" type="Vector2" setter="set_target_location" getter="get_target_location" default="Vector2(0, 0)">
+ The user-defined target location. Setting this property will clear the current navigation path.
+ </member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="20.0">
The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
@@ -159,11 +149,11 @@
</signal>
<signal name="target_reached">
<description>
- Notifies when the player defined target, set with [method set_target_location], is reached.
+ Notifies when the player-defined [member target_location] is reached.
</description>
</signal>
<signal name="velocity_computed">
- <param index="0" name="safe_velocity" type="Vector3" />
+ <param index="0" name="safe_velocity" type="Vector2" />
<description>
Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity]. Only emitted when [member avoidance_enabled] is true.
</description>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index 3bb5b361ca..44c17647f7 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
3D Agent that is used in navigation to reach a location while avoiding static and dynamic obstacles. The dynamic obstacles are avoided using RVO collision avoidance. The agent needs navigation data to work correctly. [NavigationAgent3D] is physics safe.
- [b]Note:[/b] After [method set_target_location] is used it is required to use the [method get_next_location] function once every physics frame to update the internal path logic of the NavigationAgent. The returned vector position from this function should be used as the next movement position for the agent's parent Node.
+ [b]Note:[/b] After setting [member target_location] it is required to use the [method get_next_location] function once every physics frame to update the internal path logic of the NavigationAgent. The returned vector position from this function should be used as the next movement position for the agent's parent Node.
</description>
<tutorials>
</tutorials>
@@ -13,7 +13,7 @@
<method name="distance_to_target" qualifiers="const">
<return type="float" />
<description>
- Returns the distance to the target location, using the agent's global position. The user must set the target location with [method set_target_location] in order for this to be accurate.
+ Returns the distance to the target location, using the agent's global position. The user must set [member target_location] in order for this to be accurate.
</description>
</method>
<method name="get_final_location">
@@ -59,12 +59,6 @@
Returns the [RID] of this agent on the [NavigationServer3D].
</description>
</method>
- <method name="get_target_location" qualifiers="const">
- <return type="Vector3" />
- <description>
- Returns the user defined [Vector3] after setting the target location.
- </description>
- </method>
<method name="is_navigation_finished">
<return type="bool" />
<description>
@@ -74,13 +68,13 @@
<method name="is_target_reachable">
<return type="bool" />
<description>
- Returns true if the target location is reachable. The target location is set using [method set_target_location].
+ Returns true if [member target_location] is reachable.
</description>
</method>
<method name="is_target_reached" qualifiers="const">
<return type="bool" />
<description>
- Returns true if the target location is reached. The target location is set using [method set_target_location]. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
+ Returns true if [member target_location] is reached. It may not always be possible to reach the target location. It should always be possible to reach the final location though. See [method get_final_location].
</description>
</method>
<method name="set_navigation_layer_value">
@@ -98,13 +92,6 @@
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
- <method name="set_target_location">
- <return type="void" />
- <param index="0" name="location" type="Vector3" />
- <description>
- Sets the user desired final location. This will clear the current navigation path.
- </description>
- </method>
<method name="set_velocity">
<return type="void" />
<param index="0" name="velocity" type="Vector3" />
@@ -148,6 +135,9 @@
<member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
The distance threshold before the final target point is considered to be reached. This will allow an agent to not have to hit the point of the final target exactly, but only the area. If this value is set to low the NavigationAgent will be stuck in a repath loop cause it will constantly overshoot or undershoot the distance to the final target point on each physics frame update.
</member>
+ <member name="target_location" type="Vector3" setter="set_target_location" getter="get_target_location" default="Vector3(0, 0, 0)">
+ The user-defined target location. Setting this property will clear the current navigation path.
+ </member>
<member name="time_horizon" type="float" setter="set_time_horizon" getter="get_time_horizon" default="5.0">
The minimal amount of time for which this agent's velocities, that are computed with the collision avoidance algorithm, are safe with respect to other agents. The larger the number, the sooner the agent will respond to other agents, but less freedom in choosing its velocities. Must be positive.
</member>
@@ -165,7 +155,7 @@
</signal>
<signal name="target_reached">
<description>
- Notifies when the player defined target, set with [method set_target_location], is reached.
+ Notifies when the player-defined [member target_location] is reached.
</description>
</signal>
<signal name="velocity_computed">
diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml
index 6d05e220e3..68d9691ccf 100644
--- a/doc/classes/NavigationObstacle2D.xml
+++ b/doc/classes/NavigationObstacle2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
2D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle2D] is physics safe.
- [b]Note:[/b] Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
+ Obstacles [b]don't[/b] change the resulting path from the pathfinding, they only affect the navigation agent movement in a radius. Therefore, using obstacles for the static walls in your level won't work because those walls don't exist in the pathfinding. The navigation agent will be pushed in a semi-random direction away while moving inside that radius. Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml
index f5a0bde089..90eb55887f 100644
--- a/doc/classes/NavigationObstacle3D.xml
+++ b/doc/classes/NavigationObstacle3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
3D Obstacle used in navigation for collision avoidance. The obstacle needs navigation data to work correctly. [NavigationObstacle3D] is physics safe.
- [b]Note:[/b] Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
+ Obstacles [b]don't[/b] change the resulting path from the pathfinding, they only affect the navigation agent movement in a radius. Therefore, using obstacles for the static walls in your level won't work because those walls don't exist in the pathfinding. The navigation agent will be pushed in a semi-random direction away while moving inside that radius. Obstacles are intended as a last resort option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index d9732da3a3..bf52c55d67 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -39,7 +39,7 @@
<method name="_get_configuration_warnings" qualifiers="virtual const">
<return type="PackedStringArray" />
<description>
- The elements in the array returned from this method are displayed as warnings in the Scene Dock if the script that overrides it is a [code]tool[/code] script.
+ The elements in the array returned from this method are displayed as warnings in the Scene dock if the script that overrides it is a [code]tool[/code] script.
Returning an empty array produces no warnings.
Call [method update_configuration_warnings] when the warnings need to be updated for this node.
</description>
@@ -110,11 +110,12 @@
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
- Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
+ Called when an [InputEventKey] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled key input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_key_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
This method can be used to handle Unicode character input with [kbd]Alt[/kbd], [kbd]Alt + Ctrl[/kbd], and [kbd]Alt + Shift[/kbd] modifiers, after shortcuts were handled.
For gameplay input, this and [method _unhandled_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
+ This method also performs better than [method _unhandled_input], since unrelated events such as [InputEventMouseMotion] are automatically filtered.
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
</method>
@@ -145,7 +146,7 @@
[/csharp]
[/codeblocks]
If you need the child node to be added below a specific node in the list of children, use [method add_sibling] instead of this method.
- [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/misc/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view.
+ [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view.
</description>
</method>
<method name="add_sibling">
@@ -528,9 +529,9 @@
<method name="move_child">
<return type="void" />
<param index="0" name="child_node" type="Node" />
- <param index="1" name="to_position" type="int" />
+ <param index="1" name="to_index" type="int" />
<description>
- Moves a child node to a different position (order) among the other children. Since calls, signals, etc are performed by tree order, changing the order of children nodes may be useful. If [param to_position] is negative, the index will be counted from the end.
+ Moves a child node to a different index (order) among the other children. Since calls, signals, etc. are performed by tree order, changing the order of children nodes may be useful. If [param to_index] is negative, the index will be counted from the end.
[b]Note:[/b] Internal children can only be moved within their expected "internal range" (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
@@ -559,7 +560,7 @@
<method name="print_tree_pretty">
<return type="void" />
<description>
- Similar to [method print_tree], this prints the tree to stdout. This version displays a more graphical representation similar to what is displayed in the scene inspector. It is useful for inspecting larger trees.
+ Similar to [method print_tree], this prints the tree to stdout. This version displays a more graphical representation similar to what is displayed in the Scene Dock. It is useful for inspecting larger trees.
[b]Example output:[/b]
[codeblock]
â”–â•´TheGame
@@ -767,7 +768,7 @@
</member>
<member name="owner" type="Node" setter="set_owner" getter="get_owner">
The node owner. A node can have any other node as owner (as long as it is a valid parent, grandparent, etc. ascending in the tree). When saving a node (using [PackedScene]), all the nodes it owns will be saved with it. This allows for the creation of complex [SceneTree]s, with instancing and subinstancing.
- [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/misc/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view.
+ [b]Note:[/b] If you want a child to be persisted to a [PackedScene], you must set [member owner] in addition to calling [method add_child]. This is typically relevant for [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]tool scripts[/url] and [url=$DOCS_URL/tutorials/plugins/editor/index.html]editor plugins[/url]. If [method add_child] is called without setting [member owner], the newly added [Node] will not be visible in the scene tree, though it will be visible in the 2D/3D view.
</member>
<member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Node.ProcessMode" default="0">
Can be used to pause or unpause the node, or make the node paused based on the [SceneTree], or make it inherit the process mode from its parent (default).
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index a587811260..054ab532af 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -119,6 +119,8 @@
[b]Note:[/b] Negative X scales in 2D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, negative scales on the X axis will be changed to negative scales on the Y axis and a rotation of 180 degrees when decomposed.
</member>
<member name="skew" type="float" setter="set_skew" getter="get_skew" default="0.0">
+ Slants the node.
+ [b]Note:[/b] Skew is X axis only.
</member>
<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform">
Local [Transform2D].
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index 3df7ec931f..bc2570b183 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -296,6 +296,7 @@
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
Scale part of the local transformation.
[b]Note:[/b] Mixed negative scales in 3D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, the scale values will either be all positive or all negative.
+ [b]Note:[/b] Not all nodes are visually scaled by the [member scale] property. For example, [Light3D]s are not visually affected by [member scale].
</member>
<member name="top_level" type="bool" setter="set_as_top_level" getter="is_set_as_top_level" default="false">
If [code]true[/code], the node will not inherit its transformations from its parent. Node transformations are only in global space.
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index 9db100c9f8..022b4826ea 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -4,7 +4,7 @@
Pre-parsed scene tree path.
</brief_description>
<description>
- A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite2D"[/code] which is a child of the other named nodes in the path.
+ A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For example, [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite2D"[/code] which is a child of the other named nodes in the path.
You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]^"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful.
A [NodePath] is composed of a list of slash-separated node names (like a filesystem path) and an optional colon-separated list of "subnames" which can be resources or properties.
Some examples of NodePaths include the following:
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index bc6ac8012f..0c74690924 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -4,7 +4,8 @@
Operating System functions.
</brief_description>
<description>
- Operating System functions. OS wraps the most common functionality to communicate with the host operating system, such as the clipboard, video driver, date and time, timers, environment variables, execution of binaries, command line, etc.
+ Operating System functions. [OS] wraps the most common functionality to communicate with the host operating system, such as the clipboard, video driver, delays, environment variables, execution of binaries, command line, etc.
+ [b]Note:[/b] In Godot 4, [OS] functions related to window management were moved to the [DisplayServer] singleton.
</description>
<tutorials>
<link title="OS Test Demo">https://godotengine.org/asset-library/asset/677</link>
@@ -445,6 +446,15 @@
[b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
</description>
</method>
+ <method name="get_video_adapter_driver_info" qualifiers="const">
+ <return type="PackedStringArray" />
+ <description>
+ Returns the video adapter driver name and version for the user's currently active graphics card.
+ The first element holds the driver name, such as [code]nvidia[/code], [code]amdgpu[/code], etc.
+ The second element holds the driver version. For e.g. the [code]nvidia[/code] driver on a Linux/BSD platform, the version is in the format [code]510.85.02[/code]. For Windows, the driver's format is [code]31.0.15.1659[/code].
+ [b]Note:[/b] This method is only supported on the platforms Linux/BSD and Windows when not running in headless mode. It returns an empty array on other platforms.
+ </description>
+ </method>
<method name="has_environment" qualifiers="const">
<return type="bool" />
<param index="0" name="variable" type="String" />
@@ -616,11 +626,11 @@
</member>
</members>
<constants>
- <constant name="VIDEO_DRIVER_VULKAN" value="0" enum="VideoDriver">
- The Vulkan rendering backend. It requires Vulkan 1.0 support and automatically uses features from Vulkan 1.1 and 1.2 if available.
+ <constant name="RENDERING_DRIVER_VULKAN" value="0" enum="RenderingDriver">
+ The Vulkan rendering driver. It requires Vulkan 1.0 support and automatically uses features from Vulkan 1.1 and 1.2 if available.
</constant>
- <constant name="VIDEO_DRIVER_OPENGL_3" value="1" enum="VideoDriver">
- The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web.
+ <constant name="RENDERING_DRIVER_OPENGL3" value="1" enum="RenderingDriver">
+ The OpenGL 3 rendering driver. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web.
</constant>
<constant name="DAY_SUNDAY" value="0" enum="Weekday">
Sunday.
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 7ad1908bb5..34cf259f63 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -364,9 +364,9 @@
</method>
<method name="get_indexed" qualifiers="const">
<return type="Variant" />
- <param index="0" name="property" type="NodePath" />
+ <param index="0" name="property_path" type="NodePath" />
<description>
- Gets the object's property indexed by the given [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Examples: [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code].
+ Gets the object's property indexed by the given [param property_path]. The path should be a [NodePath] relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Examples: [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code].
[b]Note:[/b] Even though the method takes [NodePath] argument, it doesn't support actual paths to [Node]s in the scene tree, only colon-separated sub-property paths. For the purpose of nodes, use [method Node.get_node_and_resource] instead.
</description>
</method>
@@ -384,7 +384,7 @@
<description>
Returns the object's metadata entry for the given [param name].
Throws error if the entry does not exist, unless [param default] is not [code]null[/code] (in which case the default value will be returned). See also [method has_meta], [method set_meta] and [method remove_meta].
- [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited.
</description>
</method>
<method name="get_meta_list" qualifiers="const">
@@ -430,7 +430,7 @@
<param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if a metadata entry is found with the given [param name]. See also [method get_meta], [method set_meta] and [method remove_meta].
- [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited.
</description>
</method>
<method name="has_method" qualifiers="const">
@@ -502,7 +502,7 @@
<param index="0" name="name" type="StringName" />
<description>
Removes a given entry from the object's metadata. See also [method has_meta], [method get_meta] and [method set_meta].
- [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited.
</description>
</method>
<method name="set">
@@ -532,10 +532,10 @@
</method>
<method name="set_indexed">
<return type="void" />
- <param index="0" name="property" type="NodePath" />
+ <param index="0" name="property_path" type="NodePath" />
<param index="1" name="value" type="Variant" />
<description>
- Assigns a new value to the property identified by the [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Example:
+ Assigns a new value to the property identified by the [param property_path]. The path should be a [NodePath] relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Example:
[codeblocks]
[gdscript]
var node = Node2D.new()
@@ -566,7 +566,7 @@
<description>
Adds, changes or removes a given entry in the object's metadata. Metadata are serialized and can take any [Variant] value.
To remove a given entry from the object's metadata, use [method remove_meta]. Metadata is also removed if its value is set to [code]null[/code]. This means you can also use [code]set_meta("name", null)[/code] to remove metadata for [code]"name"[/code]. See also [method has_meta] and [method get_meta].
- [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the Inspector and should not be edited.
</description>
</method>
<method name="set_script">
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
index 0bebc7ea43..bc16fba500 100644
--- a/doc/classes/OccluderInstance3D.xml
+++ b/doc/classes/OccluderInstance3D.xml
@@ -42,7 +42,7 @@
</member>
<member name="occluder" type="Occluder3D" setter="set_occluder" getter="get_occluder">
The occluder resource for this [OccluderInstance3D]. You can generate an occluder resource by selecting an [OccluderInstance3D] node then using the [b]Bake Occluders[/b] button at the top of the editor.
- You can also draw your own 2D occluder polygon by adding a new [PolygonOccluder3D] resource to the [member occluder] property in the inspector.
+ You can also draw your own 2D occluder polygon by adding a new [PolygonOccluder3D] resource to the [member occluder] property in the Inspector.
Alternatively, you can select a primitive occluder to use: [QuadOccluder3D], [BoxOccluder3D] or [SphereOccluder3D].
</member>
</members>
diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml
index ce63dbdbc1..193ae8deeb 100644
--- a/doc/classes/OmniLight3D.xml
+++ b/doc/classes/OmniLight3D.xml
@@ -15,6 +15,7 @@
</member>
<member name="omni_range" type="float" setter="set_param" getter="get_param" default="5.0">
The light's radius. Note that the effectively lit area may appear to be smaller depending on the [member omni_attenuation] in use. No matter the [member omni_attenuation] in use, the light will never reach anything outside this radius.
+ [b]Note:[/b] [member omni_range] is not affected by [member Node3D.scale] (the light's scale or its parent's scale).
</member>
<member name="omni_shadow_mode" type="int" setter="set_shadow_mode" getter="get_shadow_mode" enum="OmniLight3D.ShadowMode" default="1">
See [enum ShadowMode].
diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index a41207e9b3..d4050e3bd1 100644
--- a/doc/classes/ParticleProcessMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -217,7 +217,7 @@
Maximum linear acceleration applied to each particle in the direction of motion.
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
- Minimum equivalent of [member linear_accel_min].
+ Minimum equivalent of [member linear_accel_max].
</member>
<member name="orbit_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's orbital velocity will vary along this [CurveTexture].
@@ -259,6 +259,10 @@
<member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0">
Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees.
</member>
+ <member name="sub_emitter_amount_at_collision" type="int" setter="set_sub_emitter_amount_at_collision" getter="get_sub_emitter_amount_at_collision">
+ Sub particle amount on collision.
+ Maximum amount set in the sub particles emitter.
+ </member>
<member name="sub_emitter_amount_at_end" type="int" setter="set_sub_emitter_amount_at_end" getter="get_sub_emitter_amount_at_end">
</member>
<member name="sub_emitter_frequency" type="float" setter="set_sub_emitter_frequency" getter="get_sub_emitter_frequency">
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index efe63e4093..04087cbfb6 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -226,6 +226,9 @@
<member name="inverse_inertia" type="Vector3" setter="" getter="get_inverse_inertia">
The inverse of the inertia of the body.
</member>
+ <member name="inverse_inertia_tensor" type="Basis" setter="" getter="get_inverse_inertia_tensor">
+ The inverse of the inertia tensor of the body.
+ </member>
<member name="inverse_mass" type="float" setter="" getter="get_inverse_mass">
The inverse of the mass of the body.
</member>
diff --git a/doc/classes/PhysicsDirectBodyState3DExtension.xml b/doc/classes/PhysicsDirectBodyState3DExtension.xml
index ade197eadc..4432f89b9d 100644
--- a/doc/classes/PhysicsDirectBodyState3DExtension.xml
+++ b/doc/classes/PhysicsDirectBodyState3DExtension.xml
@@ -159,6 +159,11 @@
<description>
</description>
</method>
+ <method name="_get_inverse_inertia_tensor" qualifiers="virtual const">
+ <return type="Basis" />
+ <description>
+ </description>
+ </method>
<method name="_get_inverse_mass" qualifiers="virtual const">
<return type="float" />
<description>
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index e51e3753fc..fbe8afa8d1 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -119,6 +119,12 @@
Returns [code]true[/code] if this plane and [param to_plane] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this plane is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_point_over" qualifiers="const">
<return type="bool" />
<param index="0" name="point" type="Vector3" />
diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml
index 12f8055180..a3fc326351 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -92,6 +92,7 @@
[b]Note:[/b] This returns a copy of the [PackedVector2Array] rather than a reference.
</member>
<member name="polygons" type="Array" setter="set_polygons" getter="get_polygons" default="[]">
+ The list of polygons, in case more than one is being represented. Every individual polygon is stored as a [PackedInt32Array] where each [int] is an index to a point in [member polygon]. If empty, this property will be ignored, and the resulting single polygon will be composed of all points in [member polygon], using the order they are stored in.
</member>
<member name="skeleton" type="NodePath" setter="set_skeleton" getter="get_skeleton" default="NodePath(&quot;&quot;)">
</member>
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 23287f4de1..c99760996f 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -533,6 +533,8 @@
<param index="0" name="id" type="int" />
<description>
Emitted when an item of some [param id] is pressed or its accelerator is activated.
+
+ [b]Note:[/b] If [param id] is negative (either explicitly or due to overflow), this will return the correponding index instead.
</description>
</signal>
<signal name="index_pressed">
diff --git a/doc/classes/PortableCompressedTexture2D.xml b/doc/classes/PortableCompressedTexture2D.xml
index c7e2f2fbdc..a0492f2c07 100644
--- a/doc/classes/PortableCompressedTexture2D.xml
+++ b/doc/classes/PortableCompressedTexture2D.xml
@@ -22,7 +22,7 @@
<description>
Initializes the compressed texture from a base image. The compression mode must be provided.
If this image will be used as a normal map, the "normal map" flag is recommended, to ensure optimum quality.
- If lossy compression is requested, the quality setting can optionally be provided. This maps to Lossy WEBP compression quality.
+ If lossy compression is requested, the quality setting can optionally be provided. This maps to Lossy WebP compression quality.
</description>
</method>
<method name="get_compression_mode" qualifiers="const">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 6b8e077fad..91d9bdd4a2 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -251,7 +251,7 @@
Changes to this setting will only be applied upon restarting the application.
</member>
<member name="application/run/disable_stdout" type="bool" setter="" getter="" default="false">
- If [code]true[/code], disables printing to standard output. This is equivalent to starting the editor or project with the [code]--quiet[/code] command line argument. See also [member application/run/disable_stderr].
+ If [code]true[/code], disables printing to standard output. This is equivalent to starting the editor or project with the [code]--quiet[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url]. See also [member application/run/disable_stderr].
Changes to this setting will only be applied upon restarting the application.
</member>
<member name="application/run/flush_stdout_on_print" type="bool" setter="" getter="" default="false">
@@ -276,6 +276,15 @@
<member name="application/run/main_scene" type="String" setter="" getter="" default="&quot;&quot;">
Path to the main scene file that will be loaded when the project runs.
</member>
+ <member name="application/run/max_fps" type="int" setter="" getter="" default="0">
+ Maximum number of frames per second allowed. A value of [code]0[/code] means "no limit". The actual number of frames per second may still be below this value if the CPU or GPU cannot keep up with the project logic and rendering.
+ Limiting the FPS can be useful to reduce system power consumption, which reduces heat and noise emissions (and improves battery life on mobile devices).
+ If [member display/window/vsync/vsync_mode] is set to [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate.
+ If [member display/window/vsync/vsync_mode] is [code]Enabled[/code], on monitors with variable refresh rate enabled (G-Sync/FreeSync), using a FPS limit a few frames lower than the monitor's refresh rate will [url=https://blurbusters.com/howto-low-lag-vsync-on/]reduce input lag while avoiding tearing[/url].
+ If [member display/window/vsync/vsync_mode] is [code]Disabled[/code], limiting the FPS to a high value that can be consistently reached on the system can reduce input lag compared to an uncapped framerate. Since this works by ensuring the GPU load is lower than 100%, this latency reduction is only effective in GPU-bottlenecked scenarios, not CPU-bottlenecked scenarios.
+ See also [member physics/common/physics_ticks_per_second].
+ [b]Note:[/b] This property is only read when the project starts. To change the rendering FPS cap at runtime, set [member Engine.max_fps] instead.
+ </member>
<member name="audio/buses/channel_disable_threshold_db" type="float" setter="" getter="" default="-60.0">
Audio buses will disable automatically when sound goes below a given dB threshold for a given time. This saves CPU as effects assigned to that bus will no longer do any processing.
</member>
@@ -288,7 +297,7 @@
<member name="audio/driver/driver" type="String" setter="" getter="">
Specifies the audio driver to use. This setting is platform-dependent as each platform supports different audio drivers. If left empty, the default audio driver will be used.
The [code]Dummy[/code] audio driver disables all audio playback and recording, which is useful for non-game applications as it reduces CPU usage. It also prevents the engine from appearing as an application playing audio in the OS' audio mixer.
- [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--audio-driver[/code] command line argument.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--audio-driver[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
</member>
<member name="audio/driver/enable_input" type="bool" setter="" getter="" default="false">
If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS.
@@ -339,25 +348,25 @@
Desktop override for [member debug/file_logging/enable_file_logging], as log files are not readily accessible on mobile/Web platforms.
</member>
<member name="debug/file_logging/log_path" type="String" setter="" getter="" default="&quot;user://logs/godot.log&quot;">
- Path to logs within the project. Using an [code]user://[/code] path is recommended.
+ Path at which to store log files for the project. Using a path under [code]user://[/code] is recommended.
</member>
<member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5">
Specifies the maximum number of log files allowed (used for rotation).
</member>
<member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when an [code]assert[/code] call always returns false.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to false.
</member>
<member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when an [code]assert[/code] call always returns true.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to true.
</member>
<member name="debug/gdscript/warnings/constant_used_as_function" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a constant is used as a function.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a constant is used as a function.
</member>
<member name="debug/gdscript/warnings/deprecated_keyword" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when deprecated keywords are used.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when deprecated keywords are used.
</member>
<member name="debug/gdscript/warnings/empty_file" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when an empty file is parsed.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an empty file is parsed.
</member>
<member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings.
@@ -366,87 +375,91 @@
If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings.
</member>
<member name="debug/gdscript/warnings/function_used_as_property" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when using a function as if it was a property.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a function as if it is a property.
</member>
<member name="debug/gdscript/warnings/incompatible_ternary" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a ternary operator may emit values with incompatible types.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a ternary operator may emit values with incompatible types.
</member>
<member name="debug/gdscript/warnings/int_assigned_to_enum" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when trying to assign an integer to a variable that expects an enum value.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when trying to assign an integer to a variable that expects an enum value.
</member>
<member name="debug/gdscript/warnings/integer_division" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when dividing an integer by another integer (the decimal part will be discarded).
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when dividing an integer by another integer (the decimal part will be discarded).
</member>
<member name="debug/gdscript/warnings/narrowing_conversion" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when passing a floating-point value to a function that expects an integer (it will be converted and lose precision).
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when passing a floating-point value to a function that expects an integer (it will be converted and lose precision).
</member>
<member name="debug/gdscript/warnings/property_used_as_function" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when using a property as if it was a function.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a property as if it is a function.
</member>
<member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a function that is not a coroutine is called with await.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a function that is not a coroutine is called with await.
</member>
<member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum.
</member>
<member name="debug/gdscript/warnings/shadowed_global_identifier" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when defining a local or subclass member variable, signal, or enum that would have the same name as a built-in function or global class name, which possibly shadow it.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable, signal, or enum that would have the same name as a built-in function or global class name, thus shadowing it.
</member>
<member name="debug/gdscript/warnings/shadowed_variable" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable).
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable that would shadow a member variable that the class defines.
</member>
<member name="debug/gdscript/warnings/shadowed_variable_base_class" type="int" setter="" getter="" default="1">
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or subclass member variable that would shadow a variable that is inherited from a parent class.
</member>
<member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that has no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement.
</member>
<member name="debug/gdscript/warnings/standalone_ternary" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when calling a ternary expression that has no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a ternary expression that has no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement.
+ </member>
+ <member name="debug/gdscript/warnings/static_called_on_instance" type="int" setter="" getter="" default="1">
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a static method from an instance of a class instead of from the class directly.
</member>
<member name="debug/gdscript/warnings/treat_warnings_as_errors" type="bool" setter="" getter="" default="false">
- If [code]true[/code], all warnings will be reported as if they were errors.
+ If [code]true[/code], all warnings will be reported as if they are errors.
</member>
<member name="debug/gdscript/warnings/unassigned_variable" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when using a variable that wasn't previously assigned.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using a variable that wasn't previously assigned.
</member>
<member name="debug/gdscript/warnings/unassigned_variable_op_assign" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned.
</member>
<member name="debug/gdscript/warnings/unreachable_code" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed).
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed).
</member>
<member name="debug/gdscript/warnings/unreachable_pattern" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when an unreachable [code]match[/code] pattern is detected.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an unreachable [code]match[/code] pattern is detected.
</member>
<member name="debug/gdscript/warnings/unsafe_call_argument" type="int" setter="" getter="" default="0">
- If [code]enabled[/code], prints a warning or an error when using an expression whose type may not be compatible with the function parameter expected.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using an expression whose type may not be compatible with the function parameter expected.
</member>
<member name="debug/gdscript/warnings/unsafe_cast" type="int" setter="" getter="" default="0">
- If [code]enabled[/code], prints a warning or an error when performing an unsafe cast.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when performing an unsafe cast.
</member>
<member name="debug/gdscript/warnings/unsafe_method_access" type="int" setter="" getter="" default="0">
- If [code]enabled[/code], prints a warning or an error when calling a method whose presence is not guaranteed at compile-time in the class.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a method whose presence is not guaranteed at compile-time in the class.
</member>
<member name="debug/gdscript/warnings/unsafe_property_access" type="int" setter="" getter="" default="0">
- If [code]enabled[/code], prints a warning or an error when accessing a property whose presence is not guaranteed at compile-time in the class.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when accessing a property whose presence is not guaranteed at compile-time in the class.
</member>
<member name="debug/gdscript/warnings/unused_local_constant" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a local constant is never used.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local constant is never used.
</member>
<member name="debug/gdscript/warnings/unused_parameter" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a function parameter is never used.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a function parameter is never used.
</member>
<member name="debug/gdscript/warnings/unused_private_class_variable" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a class variable is never used.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a private member variable is never used.
</member>
<member name="debug/gdscript/warnings/unused_signal" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a signal is unused.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a signal is declared but never emitted.
</member>
<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when a local variable is unused.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable is unused.
</member>
<member name="debug/gdscript/warnings/void_assignment" type="int" setter="" getter="" default="1">
- If [code]enabled[/code], prints a warning or an error when assigning the result of a function that returns [code]void[/code] to a variable.
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning the result of a function that returns [code]void[/code] to a variable.
</member>
<member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;">
Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting.
@@ -454,12 +467,6 @@
<member name="debug/settings/crash_handler/message.editor" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug on: https://github.com/godotengine/godot/issues&quot;">
Editor-only override for [member debug/settings/crash_handler/message]. Does not affect exported projects in debug or release mode.
</member>
- <member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0">
- Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging.
- If [member display/window/vsync/vsync_mode] is set to [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate. See also [member physics/common/physics_ticks_per_second].
- This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions.
- [b]Note:[/b] This property is only read when the project starts. To change the rendering FPS cap at runtime, set [member Engine.target_fps] instead.
- </member>
<member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024">
Maximum call stack allowed for debugging GDScript.
</member>
@@ -470,9 +477,10 @@
Print frames per second to standard output every second.
</member>
<member name="debug/settings/stdout/print_gpu_profile" type="bool" setter="" getter="" default="false">
+ Print GPU profile information to standard output every second. This includes how long each frame takes the GPU to render on average, broken down into different steps of the render pipeline, such as CanvasItems, shadows, glow, etc.
</member>
<member name="debug/settings/stdout/verbose_stdout" type="bool" setter="" getter="" default="false">
- Print more information to standard output when running. It displays information such as memory leaks, which scenes and resources are being loaded, etc. This can also be enabled using the [code]--verbose[/code] or [code]-v[/code] command line argument, even on an exported project. See also [method OS.is_stdout_verbose] and [method @GlobalScope.print_verbose].
+ Print more information to standard output when running. It displays information such as memory leaks, which scenes and resources are being loaded, etc. This can also be enabled using the [code]--verbose[/code] or [code]-v[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url], even on an exported project. See also [method OS.is_stdout_verbose] and [method @GlobalScope.print_verbose].
</member>
<member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color(1, 0.2, 0.1, 0.8)">
Color of the contact points between collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu.
@@ -557,11 +565,21 @@
The default screen orientation to use on mobile devices. See [enum DisplayServer.ScreenOrientation] for possible values.
[b]Note:[/b] When set to a portrait orientation, this project setting does not flip the project resolution's width and height automatically. Instead, you have to set [member display/window/size/viewport_width] and [member display/window/size/viewport_height] accordingly.
</member>
+ <member name="display/window/ios/allow_high_refresh_rate" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], iOS devices that support high refresh rate/"ProMotion" will be allowed to render at up to 120 frames per second.
+ </member>
<member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true">
If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button.
</member>
+ <member name="display/window/ios/hide_status_bar" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], the status bar is hidden while the app is running.
+ </member>
+ <member name="display/window/ios/suppress_ui_gesture" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], it will require two swipes to access iOS UI that uses gestures.
+ [b]Note:[/b] This setting has no effect on the home indicator if [code]hide_home_indicator[/code] is [code]true[/code].
+ </member>
<member name="display/window/per_pixel_transparency/allowed" type="bool" setter="" getter="" default="false">
- If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it.
+ If [code]true[/code], allows per-pixel transparency for the window background. This affects performance, so leave it on [code]false[/code] unless you need it. See also [member display/window/size/transparent] and [member rendering/transparent_background].
</member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Forces the main window to be always on top.
@@ -572,8 +590,8 @@
[b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
<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.
+ Main window content is expanded to the full size of the window. Unlike a borderless window, the frame is left intact and can be used to resize the window, and the title bar is transparent, but has minimize/maximize/close buttons.
+ [b]Note:[/b] This setting is implemented only on macOS.
</member>
<member name="display/window/size/mode" type="int" setter="" getter="" default="0">
Main window mode. See [enum DisplayServer.WindowMode] for possible values and how each mode behaves.
@@ -586,8 +604,8 @@
[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].
+ If [code]true[/code], enables a window manager hint that the main window background [i]can[/i] be transparent. This does not make the background actually transparent. For the background to be transparent, the root viewport must also be made transparent by enabling [member rendering/transparent_background].
+ [b]Note:[/b] To use a transparent splash screen, set [member application/boot_splash/bg_color] to [code]Color(0, 0, 0, 0)[/code].
[b]Note:[/b] This setting has no effect if [member display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
</member>
<member name="display/window/size/viewport_height" type="int" setter="" getter="" default="648">
@@ -615,7 +633,7 @@
</member>
<member name="editor/movie_writer/fps" type="int" setter="" getter="" default="60">
The number of frames per second to record in the video when writing a movie. Simulation speed will adjust to always match the specified framerate, which means the engine will appear to run slower at higher [member editor/movie_writer/fps] values. Certain FPS values will require you to adjust [member editor/movie_writer/mix_rate] to prevent audio from desynchronizing over time.
- This can be specified manually on the command line using the [code]--fixed-fps &lt;fps&gt;[/code] command line argument.
+ This can be specified manually on the command line using the [code]--fixed-fps &lt;fps&gt;[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
</member>
<member name="editor/movie_writer/mix_rate" type="int" setter="" getter="" default="48000">
The audio mix rate to use in the recorded audio when writing a movie (in Hz). This can be different from [member audio/driver/mix_rate], but this value must be divisible by [member editor/movie_writer/fps] to prevent audio from desynchronizing over time.
@@ -679,12 +697,14 @@
Default value for [member ScrollContainer.scroll_deadzone], which will be used for all [ScrollContainer]s unless overridden.
</member>
<member name="gui/common/swap_cancel_ok" type="bool" setter="" getter="">
- If [code]true[/code], swaps Cancel and OK buttons in dialogs on Windows and UWP to follow interface conventions.
+ If [code]true[/code], swaps [b]Cancel[/b] and [b]OK[/b] buttons in dialogs on Windows and UWP to follow interface conventions. [method DisplayServer.get_swap_cancel_ok] can be used to query whether buttons are swapped at run-time.
+ [b]Note:[/b] This doesn't affect native dialogs such as the ones spawned by [method DisplayServer.dialog_show].
</member>
<member name="gui/common/text_edit_undo_stack_max_size" type="int" setter="" getter="" default="1024">
+ Maximum undo/redo history size for [TextEdit] fields.
</member>
<member name="gui/theme/custom" type="String" setter="" getter="" default="&quot;&quot;">
- Path to a custom [Theme] resource file to use for the project ([code]theme[/code] or generic [code]tres[/code]/[code]res[/code] extension).
+ Path to a custom [Theme] resource file to use for the project ([code].theme[/code] or generic [code].tres[/code]/[code].res[/code] extension).
</member>
<member name="gui/theme/custom_font" type="String" setter="" getter="" default="&quot;&quot;">
Path to a custom [Font] resource to use as default for all GUI elements of the project.
@@ -709,6 +729,8 @@
Default font glyph sub-pixel positioning mode. See [member FontFile.subpixel_positioning].
</member>
<member name="gui/theme/default_theme_scale" type="float" setter="" getter="" default="1.0">
+ The default scale factor for [Control]s, when not overriden by a [Theme].
+ [b]Note:[/b] This property is only read when the project starts. To change the default scale at runtime, set [member ThemeDB.fallback_base_scale] instead.
</member>
<member name="gui/theme/lcd_subpixel_layout" type="int" setter="" getter="" default="1">
LCD sub-pixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout].
@@ -731,8 +753,12 @@
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_copy" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to copy a selection to the clipboard.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_cut" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to cut a selection to the clipboard.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_down" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move down in the UI.
@@ -743,10 +769,16 @@
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_filedialog_refresh" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to refresh the contents of the current directory of a [FileDialog].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_filedialog_show_hidden" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to toggle showing hidden files and directories in a [FileDialog].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_filedialog_up_one_level" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to go up one directory in a [FileDialog].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_focus_next" type="Dictionary" setter="" getter="">
Default [InputEventAction] to focus the next [Control] in the scene. The focus behavior can be configured via [member Control.focus_next].
@@ -757,8 +789,12 @@
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_graph_delete" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete a [GraphNode] in a [GraphEdit].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_graph_duplicate" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to duplicate a [GraphNode] in a [GraphEdit].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_home" type="Dictionary" setter="" getter="">
Default [InputEventAction] to go to the start position of a [Control] (e.g. first item in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_HOME] on typical desktop UI systems.
@@ -769,6 +805,8 @@
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_menu" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to open a context menu in a text field.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_page_down" type="Dictionary" setter="" getter="">
Default [InputEventAction] to go down a page in a [Control] (e.g. in an [ItemList] or a [Tree]), matching the behavior of [constant KEY_PAGEDOWN] on typical desktop UI systems.
@@ -779,8 +817,12 @@
[b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_paste" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to paste from the clipboard.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_redo" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to redo an undone action.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_right" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move right in the UI.
@@ -792,97 +834,196 @@
</member>
<member name="input/ui_swap_input_direction" type="Dictionary" setter="" getter="">
</member>
+ <member name="input/ui_text_add_selection_for_next_occurrence" type="Dictionary" setter="" getter="">
+ If a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret and selects the next occurrence.
+ If no selection is currently active with the last caret in text fields, selects the word currently under the caret.
+ The action can be performed sequentially for all occurrences of the selection of the last caret and for all existing carets.
+ The viewport is adjusted to the latest newly added caret.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
+ </member>
<member name="input/ui_text_backspace" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete the character before the text cursor.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_backspace_all_to_left" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete [b]all[/b] text before the text cursor.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_backspace_all_to_left.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to delete all text before the text cursor.
</member>
<member name="input/ui_text_backspace_word" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete all characters before the cursor up until a whitespace or punctuation character.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_backspace_word.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to delete a word.
+ </member>
+ <member name="input/ui_text_caret_add_above" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to add an additional caret above every caret of a text
+ </member>
+ <member name="input/ui_text_caret_add_above.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to add a caret above every caret
+ </member>
+ <member name="input/ui_text_caret_add_below" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to add an additional caret below every caret of a text
+ </member>
+ <member name="input/ui_text_caret_add_below.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to add a caret below every caret
</member>
<member name="input/ui_text_caret_document_end" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor the the end of the text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_document_end.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor to the end of the text.
</member>
<member name="input/ui_text_caret_document_start" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor to the start of the text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_document_start.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor to the start of the text.
</member>
<member name="input/ui_text_caret_down" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor down.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_left" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor left.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_line_end" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor to the end of the line.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_line_end.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor to the end of the line.
</member>
<member name="input/ui_text_caret_line_start" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor to the start of the line.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_line_start.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor to the start of the line.
</member>
<member name="input/ui_text_caret_page_down" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor down one page.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_page_up" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor up one page.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_right" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor right.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_up" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor up.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_word_left" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor left to the next whitespace or punctuation.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_word_left.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor back one word.
</member>
<member name="input/ui_text_caret_word_right" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to move the text cursor right to the next whitespace or punctuation.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_caret_word_right.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to move the text cursor forward one word.
</member>
<member name="input/ui_text_completion_accept" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to accept an autocompetion hint.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_completion_query" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to request autocompetion.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_completion_replace" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to accept an autocompetion hint, replacing existing text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_dedent" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to unindent text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_delete" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete the character after the text cursor.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_delete_all_to_right" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete [b]all[/b] text after the text cursor.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_delete_all_to_right.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to delete all text after the text cursor.
</member>
<member name="input/ui_text_delete_word" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to delete all characters after the cursor up until a whitespace or punctuation character.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_delete_word.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to delete a word after the text cursor.
</member>
<member name="input/ui_text_indent" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to indent the current line.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_newline" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to insert a new line at the position of the text cursor.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_newline_above" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to insert a new line before the current one.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_newline_blank" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to insert a new line after the current one.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
+ </member>
+ <member name="input/ui_text_remove_secondary_carets" type="Dictionary" setter="" getter="">
+ If multiple carets are currently active, clear additional carets and keep just one caret.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_scroll_down" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to scroll down one line of text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_scroll_down.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to scroll down one line.
</member>
<member name="input/ui_text_scroll_up" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to scroll up one line of text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_scroll_up.macos" type="Dictionary" setter="" getter="">
+ macOS specific override for the shortcut to scroll up one line.
</member>
<member name="input/ui_text_select_all" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to select all text.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_select_word_under_caret" type="Dictionary" setter="" getter="">
If no selection is currently active, selects the word currently under the caret in text fields. If a selection is currently active, deselects the current selection.
- [b]Note:[/b] Currently, this is only implemented in [TextEdit], not [LineEdit].
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_submit" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to submit a text field.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_text_toggle_insert_mode" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to toggle [i]instert mode[/i] in a text field. While in insert mode, inserting new text overrides the character after the cursor, unless the next character is a new line.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_undo" type="Dictionary" setter="" getter="">
+ Default [InputEventAction] to undo the most recent action.
+ [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified.
</member>
<member name="input/ui_up" type="Dictionary" setter="" getter="">
Default [InputEventAction] to move up in the UI.
@@ -896,7 +1037,7 @@
</member>
<member name="input_devices/pen_tablet/driver" type="String" setter="" getter="">
Specifies the tablet driver to use. If left empty, the default driver will be used.
- [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--tablet-driver[/code] command line argument.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--tablet-driver[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
</member>
<member name="input_devices/pen_tablet/driver.windows" type="String" setter="" getter="">
Override for [member input_devices/pen_tablet/driver] on Windows.
@@ -961,8 +1102,8 @@
<member name="internationalization/rendering/text_driver" type="String" setter="" getter="" default="&quot;&quot;">
Specifies the [TextServer] to use. If left empty, the default will be used.
"ICU / HarfBuzz / Graphite" is the most advanced text driver, supporting right-to-left typesetting and complex scripts (for languages like Arabic, Hebrew, etc). The "Fallback" text driver does not support right-to-left typesetting and complex scripts.
- [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--text-driver[/code] command line argument.
- [b]Note:[/b] There is an additional [code]Dummy[/code] text driver available, which disables all text rendering and font-related functionality. This driver is not listed in the project settings, but it can be enabled when running the editor or project using the [code]--text-driver Dummy[/code] command line argument.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--text-driver[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
+ [b]Note:[/b] There is an additional [code]Dummy[/code] text driver available, which disables all text rendering and font-related functionality. This driver is not listed in the project settings, but it can be enabled when running the editor or project using the [code]--text-driver Dummy[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url].
</member>
<member name="layer_names/2d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 1. If left empty, the layer will display as "Layer 1".
@@ -1672,7 +1813,7 @@
[b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_jitter_fix] instead.
</member>
<member name="physics/common/physics_ticks_per_second" type="int" setter="" getter="" default="60">
- The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. See also [member debug/settings/fps/force_fps].
+ The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. See also [member application/run/max_fps].
[b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_ticks_per_second] instead.
[b]Note:[/b] Only 8 physics ticks may be simulated per rendered frame at most. If more than 8 physics ticks have to be simulated per rendered frame to keep up with rendering, the game will appear to slow down (even if [code]delta[/code] is used consistently in physics calculations). Therefore, it is recommended not to increase [member physics/common/physics_ticks_per_second] above 240. Otherwise, the game will slow down when the rendering framerate goes below 30 FPS.
</member>
@@ -1697,6 +1838,9 @@
Another way to combat specular aliasing is to enable [member rendering/anti_aliasing/screen_space_roughness_limiter/enabled].
</member>
<member name="rendering/anti_aliasing/quality/use_debanding" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible in 3D. 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS].
+ In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger.
+ [b]Note:[/b] This property is only read when the project starts. To set debanding at run-time, set [member Viewport.use_debanding] on the root [Viewport] instead.
</member>
<member name="rendering/anti_aliasing/quality/use_taa" type="bool" setter="" getter="" default="false">
Enables Temporal Anti-Aliasing for the default screen [Viewport]. TAA works by jittering the camera and accumulating the images of the last rendered frames, motion vector rendering is used to account for camera and object motion. Enabling TAA can make the image blurrier, which is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]).
@@ -1820,6 +1964,9 @@
<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/gl_compatibility/item_buffer_size" type="int" setter="" getter="" default="16384">
+ Maximum number of canvas items commands that can be drawn in a single viewport update. If more render commands are issued they will be ignored. Decreasing this limit may improve performance on bandwidth limited devices. Increase this limit if you find that not all objects are being drawn in a frame.
+ </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.
@@ -1982,9 +2129,9 @@
</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.
+ [b]Forward Plus[/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 Forward Plus, but does not scale as well to large scenes with many elements.
+ [b]GL 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;mobile&quot;">
Override for [member rendering/renderer/rendering_method] on mobile devices.
@@ -1992,8 +2139,6 @@
<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>
@@ -2018,6 +2163,8 @@
</member>
<member name="rendering/rendering_device/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
</member>
+ <member name="rendering/rendering_device/vulkan/max_descriptors_per_pool" 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>
@@ -2030,6 +2177,7 @@
<member name="rendering/shader_compiler/shader_cache/compress" type="bool" setter="" getter="" default="true">
</member>
<member name="rendering/shader_compiler/shader_cache/enabled" type="bool" setter="" getter="" default="true">
+ Enable the shader cache, which stores compiled shaders to disk to prevent stuttering from shader compilation the next time the shader is needed.
</member>
<member name="rendering/shader_compiler/shader_cache/strip_debug" type="bool" setter="" getter="" default="false">
</member>
@@ -2093,6 +2241,9 @@
If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm. This algorithm is only supported on desktop platforms and consoles.
[b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor (see [member application/config/use_hidden_project_data_directory]).
</member>
+ <member name="rendering/transparent_background" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], enables [member Viewport.transparent_bg] on the root viewport. This allows per-pixel transparency to be effective after also enabling [member display/window/size/transparent] and [member display/window/per_pixel_transparency/allowed].
+ </member>
<member name="rendering/vrs/mode" type="int" setter="" getter="" default="0">
Set the default Variable Rate Shading (VRS) mode for the main viewport. See [member Viewport.vrs_mode] to change this at runtime, and [enum Viewport.VRSMode] for possible values.
</member>
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index 5690ea5e95..602833bca5 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Projection" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ 3D projection (4x4 matrix).
</brief_description>
<description>
+ A 4x4 matrix used for 3D projective transformations. It can represent transformations such as translation, rotation, scaling, shearing, and perspective division. It consists of four [Vector4] columns.
+ For purely linear transformations (translation, rotation, and scale), it is recommended to use [Transform3D], as it is more performant and has a lower memory footprint.
+ Used internally as [Camera3D]'s projection matrix.
</description>
<tutorials>
</tutorials>
@@ -10,18 +14,21 @@
<constructor name="Projection">
<return type="Projection" />
<description>
+ Constructs a default-initialized [Projection] set to [constant IDENTITY].
</description>
</constructor>
<constructor name="Projection">
<return type="Projection" />
<param index="0" name="from" type="Projection" />
<description>
+ Constructs a [Projection] as a copy of the given [Projection].
</description>
</constructor>
<constructor name="Projection">
<return type="Projection" />
<param index="0" name="from" type="Transform3D" />
<description>
+ Constructs a Projection as a copy of the given [Transform3D].
</description>
</constructor>
<constructor name="Projection">
@@ -40,12 +47,14 @@
<return type="Projection" />
<param index="0" name="flip_y" type="bool" />
<description>
+ Creates a new [Projection] that projects positions from a depth range of [code]-1[/code] to [code]1[/code] to one that ranges from [code]0[/code] to [code]1[/code], and flips the projected positions vertically, according to [param flip_y].
</description>
</method>
<method name="create_fit_aabb" qualifiers="static">
<return type="Projection" />
<param index="0" name="aabb" type="AABB" />
<description>
+ Creates a new [Projection] that scales a given projection to fit around a given [AABB] in projection space.
</description>
</method>
<method name="create_for_hmd" qualifiers="static">
@@ -59,6 +68,8 @@
<param index="6" name="z_near" type="float" />
<param index="7" name="z_far" type="float" />
<description>
+ Creates a new [Projection] for projecting positions onto a head-mounted display with the given X:Y aspect ratio, distance between eyes, display width, distance to lens, oversampling factor, and depth clipping planes.
+ [param eye] creates the projection for the left eye when set to 1, or the right eye when set to 2.
</description>
</method>
<method name="create_frustum" qualifiers="static">
@@ -70,6 +81,7 @@
<param index="4" name="z_near" type="float" />
<param index="5" name="z_far" type="float" />
<description>
+ Creates a new [Projection] that projects positions in a frustum with the given clipping planes.
</description>
</method>
<method name="create_frustum_aspect" qualifiers="static">
@@ -81,12 +93,15 @@
<param index="4" name="z_far" type="float" />
<param index="5" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions in a frustum with the given size, X:Y aspect ratio, offset, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_light_atlas_rect" qualifiers="static">
<return type="Projection" />
<param index="0" name="rect" type="Rect2" />
<description>
+ Creates a new [Projection] that projects positions into the given [Rect2].
</description>
</method>
<method name="create_orthogonal" qualifiers="static">
@@ -98,6 +113,7 @@
<param index="4" name="z_near" type="float" />
<param index="5" name="z_far" type="float" />
<description>
+ Creates a new [Projection] that projects positions using an orthogonal projection with the given clipping planes.
</description>
</method>
<method name="create_orthogonal_aspect" qualifiers="static">
@@ -108,6 +124,8 @@
<param index="3" name="z_far" type="float" />
<param index="4" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions using an orthogonal projection with the given size, X:Y aspect ratio, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_perspective" qualifiers="static">
@@ -118,6 +136,8 @@
<param index="3" name="z_far" type="float" />
<param index="4" name="flip_fov" type="bool" default="false" />
<description>
+ Creates a new [Projection] that projects positions using a perspective projection with the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping planes.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="create_perspective_hmd" qualifiers="static">
@@ -131,31 +151,40 @@
<param index="6" name="intraocular_dist" type="float" />
<param index="7" name=" convergence_dist" type="float" />
<description>
+ Creates a new [Projection] that projects positions using a perspective projection with the given Y-axis field of view (in degrees), X:Y aspect ratio, and clipping distances. The projection is adjusted for a head-mounted display with the given distance between eyes and distance to a point that can be focused on.
+ [param eye] creates the projection for the left eye when set to 1, or the right eye when set to 2.
+ [param flip_fov] determines whether the projection's field of view is flipped over its diagonal.
</description>
</method>
<method name="determinant" qualifiers="const">
<return type="float" />
<description>
+ Returns a scalar value that is the signed factor by which areas are scaled by this matrix. If the sign is negative, the matrix flips the orientation of the area.
+ The determinant can be used to calculate the invertibility of a matrix or solve linear systems of equations involving the matrix, among other applications.
</description>
</method>
<method name="flipped_y" qualifiers="const">
<return type="Projection" />
<description>
+ Returns a copy of this [Projection] with the signs of the values of the Y column flipped.
</description>
</method>
<method name="get_aspect" qualifiers="const">
<return type="float" />
<description>
+ Returns the X:Y aspect ratio of this [Projection]'s viewport.
</description>
</method>
<method name="get_far_plane_half_extents" qualifiers="const">
<return type="Vector2" />
<description>
+ Returns the dimensions of the far clipping plane of the projection, divided by two.
</description>
</method>
<method name="get_fov" qualifiers="const">
<return type="float" />
<description>
+ Returns the horizontal field of view of the projection (in degrees).
</description>
</method>
<method name="get_fovy" qualifiers="static">
@@ -163,89 +192,114 @@
<param index="0" name="fovx" type="float" />
<param index="1" name="aspect" type="float" />
<description>
+ Returns the vertical field of view of the projection (in degrees) associated with the given horizontal field of view (in degrees) and aspect ratio.
</description>
</method>
<method name="get_lod_multiplier" qualifiers="const">
<return type="float" />
<description>
+ Returns the factor by which the visible level of detail is scaled by this [Projection].
</description>
</method>
<method name="get_pixels_per_meter" qualifiers="const">
<return type="int" />
<param index="0" name="for_pixel_width" type="int" />
<description>
+ Returns the number of pixels with the given pixel width displayed per meter, after this [Projection] is applied.
</description>
</method>
<method name="get_projection_plane" qualifiers="const">
<return type="Plane" />
<param index="0" name="plane" type="int" />
<description>
+ Returns the clipping plane of this [Projection] whose index is given by [param plane].
+ [param plane] should be equal to one of [constant PLANE_NEAR], [constant PLANE_FAR], [constant PLANE_LEFT], [constant PLANE_TOP], [constant PLANE_RIGHT], or [constant PLANE_BOTTOM].
</description>
</method>
<method name="get_viewport_half_extents" qualifiers="const">
<return type="Vector2" />
<description>
+ Returns the dimensions of the viewport plane that this [Projection] projects positions onto, divided by two.
</description>
</method>
<method name="get_z_far" qualifiers="const">
<return type="float" />
<description>
+ Returns the distance for this [Projection] beyond which positions are clipped.
</description>
</method>
<method name="get_z_near" qualifiers="const">
<return type="float" />
<description>
+ Returns the distance for this [Projection] before which positions are clipped.
</description>
</method>
<method name="inverse" qualifiers="const">
<return type="Projection" />
<description>
+ Returns a [Projection] that performs the inverse of this [Projection]'s projective transformation.
</description>
</method>
<method name="is_orthogonal" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if this [Projection] performs an orthogonal projection.
</description>
</method>
<method name="jitter_offseted" qualifiers="const">
<return type="Projection" />
<param index="0" name="offset" type="Vector2" />
<description>
+ Returns a [Projection] with the X and Y values from the given [Vector2] added to the first and second values of the final column respectively.
</description>
</method>
<method name="perspective_znear_adjusted" qualifiers="const">
<return type="Projection" />
<param index="0" name="new_znear" type="float" />
<description>
+ Returns a [Projection] with the near clipping distance adjusted to be [param new_znear].
+ [b]Note:[/b] The original [Projection] must be a perspective projection.
</description>
</method>
</methods>
<members>
<member name="w" type="Vector4" setter="" getter="" default="Vector4(0, 0, 0, 1)">
+ The projection matrix's W vector (column 3). Equivalent to array index [code]3[/code].
</member>
<member name="x" type="Vector4" setter="" getter="" default="Vector4(1, 0, 0, 0)">
+ The projection matrix's X vector (column 0). Equivalent to array index [code]0[/code].
</member>
<member name="y" type="Vector4" setter="" getter="" default="Vector4(0, 1, 0, 0)">
+ The projection matrix's Y vector (column 1). Equivalent to array index [code]1[/code].
</member>
<member name="z" type="Vector4" setter="" getter="" default="Vector4(0, 0, 1, 0)">
+ The projection matrix's Z vector (column 2). Equivalent to array index [code]2[/code].
</member>
</members>
<constants>
<constant name="PLANE_NEAR" value="0">
+ The index value of the projection's near clipping plane.
</constant>
<constant name="PLANE_FAR" value="1">
+ The index value of the projection's far clipping plane.
</constant>
<constant name="PLANE_LEFT" value="2">
+ The index value of the projection's left clipping plane.
</constant>
<constant name="PLANE_TOP" value="3">
+ The index value of the projection's top clipping plane.
</constant>
<constant name="PLANE_RIGHT" value="4">
+ The index value of the projection's right clipping plane.
</constant>
<constant name="PLANE_BOTTOM" value="5">
+ The index value of the projection bottom clipping plane.
</constant>
<constant name="IDENTITY" value="Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)">
+ A [Projection] with no transformation defined. When applied to other data structures, no transformation is performed.
</constant>
<constant name="ZERO" value="Projection(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)">
+ A [Projection] with all values initialized to 0. When applied to other data structures, they will be zeroed.
</constant>
</constants>
<operators>
@@ -253,30 +307,38 @@
<return type="bool" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns [code]true[/code] if the projections are not equal.
+ [b]Note:[/b] Due to floating-point precision errors, this may return [code]true[/code], even if the projections are virtually equal. An [code]is_equal_approx[/code] method may be added in a future version of Godot.
</description>
</operator>
<operator name="operator *">
<return type="Projection" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns a [Projection] that applies the combined transformations of this [Projection] and [param right].
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
<param index="0" name="right" type="Vector4" />
<description>
+ Projects (multiplies) the given [Vector4] by this [Projection] matrix.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
<param index="0" name="right" type="Projection" />
<description>
+ Returns [code]true[/code] if the projections are equal.
+ [b]Note:[/b] Due to floating-point precision errors, this may return [code]false[/code], even if the projections are virtually equal. An [code]is_equal_approx[/code] method may be added in a future version of Godot.
</description>
</operator>
<operator name="operator []">
<return type="Vector4" />
<param index="0" name="index" type="int" />
<description>
+ Returns the column of the [Projection] with the given index.
+ Indices are in the following order: x, y, z, w.
</description>
</operator>
</operators>
diff --git a/doc/classes/PropertyTweener.xml b/doc/classes/PropertyTweener.xml
index 75d9c919aa..78ead65cdd 100644
--- a/doc/classes/PropertyTweener.xml
+++ b/doc/classes/PropertyTweener.xml
@@ -27,7 +27,7 @@
Sets a custom initial value to the [PropertyTweener]. Example:
[codeblock]
var tween = get_tree().create_tween()
- tween.tween_property(self, "position", Vector2(200, 100), 1).from(Vector2(100, 100) #this will move the node from position (100, 100) to (200, 100)
+ tween.tween_property(self, "position", Vector2(200, 100), 1).from(Vector2(100, 100)) #this will move the node from position (100, 100) to (200, 100)
[/codeblock]
</description>
</method>
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index f21ebf57e2..08a9231751 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -43,12 +43,6 @@
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <param index="0" name="euler_yxz" type="Vector3" />
- <description>
- </description>
- </constructor>
- <constructor name="Quaternion">
- <return type="Quaternion" />
<param index="0" name="from" type="Basis" />
<description>
Constructs a quaternion from the given [Basis].
@@ -86,6 +80,13 @@
<description>
</description>
</method>
+ <method name="from_euler" qualifiers="static">
+ <return type="Quaternion" />
+ <param index="0" name="euler" type="Vector3" />
+ <description>
+ Constructs a Quaternion from Euler angles in YXZ rotation order.
+ </description>
+ </method>
<method name="get_angle" qualifiers="const">
<return type="float" />
<description>
@@ -115,6 +116,12 @@
Returns [code]true[/code] if this quaternion and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this quaternion is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/RDPipelineRasterizationState.xml b/doc/classes/RDPipelineRasterizationState.xml
index 39a64c730a..48599b6262 100644
--- a/doc/classes/RDPipelineRasterizationState.xml
+++ b/doc/classes/RDPipelineRasterizationState.xml
@@ -13,7 +13,7 @@
</member>
<member name="depth_bias_constant_factor" type="float" setter="set_depth_bias_constant_factor" getter="get_depth_bias_constant_factor" default="0.0">
</member>
- <member name="depth_bias_enable" type="bool" setter="set_depth_bias_enable" getter="get_depth_bias_enable" default="false">
+ <member name="depth_bias_enabled" type="bool" setter="set_depth_bias_enabled" getter="get_depth_bias_enabled" default="false">
</member>
<member name="depth_bias_slope_factor" type="float" setter="set_depth_bias_slope_factor" getter="get_depth_bias_slope_factor" default="0.0">
</member>
diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml
index b8a290381f..a6254788ce 100644
--- a/doc/classes/RandomNumberGenerator.xml
+++ b/doc/classes/RandomNumberGenerator.xml
@@ -10,10 +10,9 @@
[codeblock]
var rng = RandomNumberGenerator.new()
func _ready():
- rng.randomize()
var my_random_number = rng.randf_range(-10.0, 10.0)
[/codeblock]
- [b]Note:[/b] The default values of [member seed] and [member state] properties are pseudo-random, and changes when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed.
+ [b]Note:[/b] The default values of [member seed] and [member state] properties are pseudo-random, and change when calling [method randomize]. The [code]0[/code] value documented here is a placeholder, and not the actual default seed.
</description>
<tutorials>
<link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index ac012e9604..28fe42afae 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -165,6 +165,12 @@
Returns [code]true[/code] if this [Rect2] and [param rect] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this [Rect2] is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="merge" qualifiers="const">
<return type="Rect2" />
<param index="0" name="b" type="Rect2" />
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index eb85a4adb4..51c2498ea7 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -1581,6 +1581,10 @@
</constant>
<constant name="LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z" value="34" enum="Limit">
</constant>
+ <constant name="LIMIT_MAX_VIEWPORT_DIMENSIONS_X" value="35" enum="Limit">
+ </constant>
+ <constant name="LIMIT_MAX_VIEWPORT_DIMENSIONS_Y" value="36" enum="Limit">
+ </constant>
<constant name="MEMORY_TEXTURES" value="0" enum="MemoryType">
</constant>
<constant name="MEMORY_BUFFERS" value="1" enum="MemoryType">
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 6aa9237385..1c02d58299 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -13,6 +13,7 @@
Similarly, in 2D, a canvas is needed to draw all canvas items.
In 3D, all visible objects are comprised of a resource and an instance. A resource can be a mesh, a particle system, a light, or any other 3D object. In order to be visible resources must be attached to an instance using [method instance_set_base]. The instance must also be attached to the scenario using [method instance_set_scenario] in order to be visible.
In 2D, all visible objects are some form of canvas item. In order to be visible, a canvas item needs to be the child of a canvas attached to a viewport, or it needs to be the child of another canvas item that is eventually attached to the canvas.
+ [b]Headless mode:[/b] Starting the engine with the [code]--headless[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] disables all rendering and window management functions. Most functions from [RenderingServer] will return dummy values in this case.
</description>
<tutorials>
<link title="Optimization using Servers">$DOCS_URL/tutorials/performance/using_servers.html</link>
@@ -498,6 +499,14 @@
Sets if the [CanvasItem] uses its parent's material.
</description>
</method>
+ <method name="canvas_item_set_visibility_layer">
+ <return type="void" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="visibility_layer" type="int" />
+ <description>
+ Sets the rendering visibility layer associated with this [CanvasItem]. Only [Viewport] nodes with a matching rendering mask will render this [CanvasItem].
+ </description>
+ </method>
<method name="canvas_item_set_visibility_notifier">
<return type="void" />
<param index="0" name="item" type="RID" />
@@ -3142,6 +3151,14 @@
If [code]true[/code], sets the viewport active, else sets it inactive.
</description>
</method>
+ <method name="viewport_set_canvas_cull_mask">
+ <return type="void" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="canvas_cull_mask" type="int" />
+ <description>
+ Sets the rendering mask associated with this [Viewport]. Only [CanvasItem] nodes with a matching rendering visibility layer will be rendered by this [Viewport].
+ </description>
+ </method>
<method name="viewport_set_canvas_stacking">
<return type="void" />
<param index="0" name="viewport" type="RID" />
@@ -4576,9 +4593,11 @@
</constant>
<constant name="CANVAS_GROUP_MODE_DISABLED" value="0" enum="CanvasGroupMode">
</constant>
- <constant name="CANVAS_GROUP_MODE_OPAQUE" value="1" enum="CanvasGroupMode">
+ <constant name="CANVAS_GROUP_MODE_CLIP_ONLY" value="1" enum="CanvasGroupMode">
+ </constant>
+ <constant name="CANVAS_GROUP_MODE_CLIP_AND_DRAW" value="2" enum="CanvasGroupMode">
</constant>
- <constant name="CANVAS_GROUP_MODE_TRANSPARENT" value="2" enum="CanvasGroupMode">
+ <constant name="CANVAS_GROUP_MODE_TRANSPARENT" value="3" enum="CanvasGroupMode">
</constant>
<constant name="CANVAS_LIGHT_MODE_POINT" value="0" enum="CanvasLightMode">
</constant>
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 3adf10da2d..b2b8a37e39 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -4,7 +4,8 @@
Base class for all resources.
</brief_description>
<description>
- Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instantiated from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
+ Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources are reference-counted and freed when no longer in use. They can also be nested within other resources, and saved on disk. Once loaded from disk, further attempts to load a resource by [member resource_path] returns the same reference. [PackedScene], one of the most common [Object]s in a Godot project, is also a resource, uniquely capable of storing and instantiating the [Node]s it contains as many times as desired.
+ In GDScript, resources can loaded from disk by their [member resource_path] using [method @GDScript.load] or [method @GDScript.preload].
[b]Note:[/b] In C#, resources will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free resources that are no longer in use. This means that unused resources will linger on for a while before being removed.
</description>
<tutorials>
@@ -15,77 +16,94 @@
<method name="_get_rid" qualifiers="virtual">
<return type="RID" />
<description>
+ Override this method to return a custom [RID] when [method get_rid] is called.
</description>
</method>
<method name="duplicate" qualifiers="const">
<return type="Resource" />
<param index="0" name="subresources" type="bool" default="false" />
<description>
- Duplicates the resource, returning a new resource with the exported members copied. [b]Note:[/b] To duplicate the resource the constructor is called without arguments. This method will error when the constructor doesn't have default values.
- By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [param subresources] argument which will copy the subresources.
- [b]Note:[/b] If [param subresources] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
- [b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource.
+ Duplicates this resource, returning a new resource with its [code]export[/code]ed or [constant PROPERTY_USAGE_STORAGE] properties copied from the original.
+ If [param subresources] is [code]false[/code], a shallow copy is returned. Nested resources within subresources are not duplicated and are shared from the original resource. This behavior can be overriden by the [constant PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE] flag.
+ [b]Note:[/b] For custom resources, this method will fail if [method Object._init] has been defined with required parameters.
</description>
</method>
<method name="emit_changed">
<return type="void" />
<description>
- Emits the [signal changed] signal.
- If external objects which depend on this resource should be updated, this method must be called manually whenever the state of this resource has changed (such as modification of properties).
- The method is equivalent to:
+ Emits the [signal changed] signal. This method is called automatically for built-in resources.
+ [b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated.
[codeblock]
- emit_signal("changed")
+ var damage:
+ set(new_value):
+ if damage != new_value:
+ damage = new_value
+ emit_changed()
[/codeblock]
- [b]Note:[/b] This method is called automatically for built-in resources.
</description>
</method>
<method name="get_local_scene" qualifiers="const">
<return type="Node" />
<description>
- If [member resource_local_to_scene] is enabled and the resource was loaded from a [PackedScene] instantiation, returns the local scene where this resource's unique copy is in use. Otherwise, returns [code]null[/code].
+ If [member resource_local_to_scene] is set to [code]true[/code] and the resource has been loaded from a [PackedScene] instantiation, returns the root [Node] of the scene where this resource is used. Otherwise, returns [code]null[/code].
</description>
</method>
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
- Returns the RID of the resource (or an empty RID). Many resources (such as [Texture2D], [Mesh], etc) are high-level abstractions of resources stored in a server, so this function will return the original RID.
+ Returns the [RID] of this resource (or an empty RID). Many resources (such as [Texture2D], [Mesh], and so on) are high-level abstractions of resources stored in a specialised server ([DisplayServer], [RenderingServer], etc.), so this function will return the original [RID].
</description>
</method>
<method name="setup_local_to_scene">
<return type="void" />
<description>
- This method is called when a resource with [member resource_local_to_scene] enabled is loaded from a [PackedScene] instantiation. Its behavior can be customized by connecting [signal setup_local_to_scene_requested] from script.
- For most resources, this method performs no base logic. [ViewportTexture] performs custom logic to properly set the proxy texture and flags in the local viewport.
+ Emits the [signal setup_local_to_scene_requested] signal. If [member resource_local_to_scene] is set to [code]true[/code], this method is called from [method PackedScene.instantiate] by the newly duplicated resource within the scene instance.
+ For most resources, this method performs no logic of its own. Custom behavior can be defined by connecting [signal setup_local_to_scene_requested] from a script, [b]not[/b] by overriding this method.
+ [b]Example:[/b] Assign a random value to [code]health[/code] for every duplicated Resource from an instantiated scene, excluding the original.
+ [codeblock]
+ extends Resource
+
+ var health = 0
+
+ func _init():
+ setup_local_to_scene_requested.connect(randomize_health)
+
+ func randomize_health():
+ health = randi_range(10, 40)
+ [/codeblock]
</description>
</method>
<method name="take_over_path">
<return type="void" />
<param index="0" name="path" type="String" />
<description>
- Sets the path of the resource, potentially overriding an existing cache entry for this path. This differs from setting [member resource_path], as the latter would error out if another resource was already cached for the given path.
+ Sets the [member resource_path] to [param path], potentially overriding an existing cache entry for this path. Further attempts to load an overridden resource by path will instead return this resource.
</description>
</method>
</methods>
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" default="false">
- If [code]true[/code], the resource will be made unique in each instance of its local scene. It can thus be modified in a scene instance without impacting other instances of that same scene.
+ If [code]true[/code], the resource is duplicated for each instance of all scenes using it. At run-time, the resource can be modified in one scene without affecting other instances (see [method PackedScene.instantiate]).
+ [b]Note:[/b] Changing this property at run-time has no effect on already created duplicate resources.
</member>
<member name="resource_name" type="String" setter="set_name" getter="get_name" default="&quot;&quot;">
- The name of the resource. This is an optional identifier. If [member resource_name] is not empty, its value will be displayed to represent the current resource in the editor inspector. For built-in scripts, the [member resource_name] will be displayed as the tab name in the script editor.
+ An optional name for this resource. When defined, its value is displayed to represent the resource in the Inspector dock. For built-in scripts, the name is displayed as part of the tab name in the script editor.
</member>
<member name="resource_path" type="String" setter="set_path" getter="get_path" default="&quot;&quot;">
- The path to the resource. In case it has its own file, it will return its filepath. If it's tied to the scene, it will return the scene's path, followed by the resource's index.
+ The unique path to this resource. If it has been saved to disk, the value will be its filepath. If the resource is exclusively contained within a scene, the value will be the [PackedScene]'s filepath, followed by an unique identifier.
+ [b]Note:[/b] Setting this property manually may fail if a resource with the same path has already been previously loaded. If necessary, use [method take_over_path].
</member>
</members>
<signals>
<signal name="changed">
<description>
- Emitted whenever the resource changes.
- [b]Note:[/b] This signal is not emitted automatically for custom resources, which means that you need to create a setter and emit the signal yourself.
+ Emitted when the resource changes, usually when one of its properties is modified. See also [method emit_changed].
+ [b]Note:[/b] This signal is not emitted automatically for properties of custom resources. If necessary, a setter needs to be created to emit the signal.
</description>
</signal>
<signal name="setup_local_to_scene_requested">
<description>
+ Emitted when [method setup_local_to_scene] is called, usually by a newly duplicated resource with [member resource_local_to_scene] set to [code]true[/code]. Custom behavior can be defined by connecting this signal.
</description>
</signal>
</signals>
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index 9b8c8d4d9d..2b6376f2cd 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -71,6 +71,15 @@
The [param cache_mode] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
</description>
</method>
+ <method name="_recognize_path" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="type" type="StringName" />
+ <description>
+ Tells whether or not this loader should load a resource from its resource path for a given type.
+ If it is not implemented, the default behavior returns whether the path's extension is within the ones provided by [method _get_recognized_extensions], and if the type is within the ones provided by [method _get_resource_type].
+ </description>
+ </method>
<method name="_rename_dependencies" qualifiers="virtual const">
<return type="int" />
<param index="0" name="path" type="String" />
diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml
index 05bfcf3446..1f2af6d157 100644
--- a/doc/classes/ResourceFormatSaver.xml
+++ b/doc/classes/ResourceFormatSaver.xml
@@ -24,6 +24,15 @@
Returns whether the given resource object can be saved by this saver.
</description>
</method>
+ <method name="_recognize_path" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="path" type="String" />
+ <description>
+ Returns [code]true[/code] if this saver handles a given save path and [code]false[/code] otherwise.
+ If this method is not implemented, the default behavior returns whether the path's extension is within the ones provided by [method _get_recognized_extensions].
+ </description>
+ </method>
<method name="_save" qualifiers="virtual">
<return type="int" />
<param index="0" name="resource" type="Resource" />
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index f4cbf4c442..cb2481f705 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -23,9 +23,11 @@
<param index="2" name="height" type="int" default="0" />
<param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<param index="4" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="5" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<description>
- Adds an image's opening and closing tags to the tag stack, optionally providing a [param width] and [param height] to resize the image and a [param color] to tint the image.
+ Adds an image's opening and closing tags to the tag stack, optionally providing a [param width] and [param height] to resize the image, a [param color] to tint the image and a [param region] to only use parts of the image.
If [param width] or [param height] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
+ If [param width] and [param height] are not set, but [param region] is, the region's rect will be used.
</description>
</method>
<method name="add_text">
@@ -477,9 +479,6 @@
<member name="meta_underlined" type="bool" setter="set_meta_underline" getter="is_meta_underlined" default="true">
If [code]true[/code], the label underlines meta tags such as [code][url]{text}[/url][/code].
</member>
- <member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color" default="false">
- If [code]true[/code], the label uses the custom font color.
- </member>
<member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000">
The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely.
[b]Note:[/b] Progress bar is displayed only if [member threaded] is enabled.
@@ -627,8 +626,8 @@
<theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The default tint of text outline.
</theme_item>
- <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 1)">
- The color of selected text, used when [member selection_enabled] is [code]true[/code].
+ <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)">
+ The color of selected text, used when [member selection_enabled] is [code]true[/code]. If equal to [code]Color(0, 0, 0, 0)[/code], it will be ignored.
</theme_item>
<theme_item name="font_shadow_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)">
The color of the font's shadow.
@@ -666,6 +665,12 @@
<theme_item name="table_v_separation" data_type="constant" type="int" default="3">
The vertical separation of elements in a table.
</theme_item>
+ <theme_item name="text_highlight_h_padding" data_type="constant" type="int" default="3">
+ The horizontal padding around a highlighting and background color box.
+ </theme_item>
+ <theme_item name="text_highlight_v_padding" data_type="constant" type="int" default="3">
+ The vertical padding around a highlighting and background color box.
+ </theme_item>
<theme_item name="bold_font" data_type="font" type="Font">
The font used for bold text.
</theme_item>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 40ec8ed429..b4b14c01c6 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -4,7 +4,7 @@
A class stored as a resource.
</brief_description>
<description>
- A class stored as a resource. A script extends the functionality of all objects that instance it.
+ A class stored as a resource. A script extends the functionality of all objects that instantiate it.
This is the base class for all scripts and should not be used directly. Trying to create a new script with this class will result in an error.
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 34ca228795..7be0ba64d6 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -66,6 +66,12 @@
Draws a solid shape onto a [CanvasItem] with the [RenderingServer] API filled with the specified [param color]. The exact drawing method is specific for each shape and cannot be configured.
</description>
</method>
+ <method name="get_rect" qualifiers="const">
+ <return type="Rect2" />
+ <description>
+ Returns a [Rect2] representing the shapes boundary.
+ </description>
+ </method>
</methods>
<members>
<member name="custom_solver_bias" type="float" setter="set_custom_solver_bias" getter="get_custom_solver_bias" default="0.0">
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 55d21f3224..57bdd52d9e 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -7,6 +7,7 @@
This resource is used in [EditorScenePostImport]. Some parameters are referring to bones in [Skeleton3D], [Skin], [Animation], and some other nodes are rewritten based on the parameters of [SkeletonProfile].
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<methods>
<method name="find_bone" qualifiers="const">
diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml
index 11f0521718..0dbd66d8d6 100644
--- a/doc/classes/SkeletonProfileHumanoid.xml
+++ b/doc/classes/SkeletonProfileHumanoid.xml
@@ -6,6 +6,7 @@
A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only.
</description>
<tutorials>
+ <link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
</tutorials>
<members>
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" overrides="SkeletonProfile" default="56" />
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index 8df039794a..93799b58f0 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -56,6 +56,9 @@
<member name="prefix" type="String" setter="set_prefix" getter="get_prefix" default="&quot;&quot;">
Adds the specified [code]prefix[/code] string before the numerical value of the [SpinBox].
</member>
+ <member name="select_all_on_focus" type="bool" setter="set_select_all_on_focus" getter="is_select_all_on_focus" default="false">
+ If [code]true[/code], the [SpinBox] will select the whole text when the [LineEdit] gains focus. Clicking the up and down arrows won't trigger this behavior.
+ </member>
<member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default="&quot;&quot;">
Adds the specified [code]suffix[/code] string after the numerical value of the [SpinBox].
</member>
diff --git a/doc/classes/SpotLight3D.xml b/doc/classes/SpotLight3D.xml
index 62cb55daec..28e2ef0d95 100644
--- a/doc/classes/SpotLight3D.xml
+++ b/doc/classes/SpotLight3D.xml
@@ -14,6 +14,7 @@
<member name="shadow_bias" type="float" setter="set_param" getter="get_param" overrides="Light3D" default="0.03" />
<member name="spot_angle" type="float" setter="set_param" getter="get_param" default="45.0">
The spotlight's angle in degrees.
+ [b]Note:[/b] [member spot_angle] is not affected by [member Node3D.scale] (the light's scale or its parent's scale).
</member>
<member name="spot_angle_attenuation" type="float" setter="set_param" getter="get_param" default="1.0">
The spotlight's angular attenuation curve.
@@ -23,6 +24,7 @@
</member>
<member name="spot_range" type="float" setter="set_param" getter="get_param" default="5.0">
The maximal range that can be reached by the spotlight. Note that the effectively lit area may appear to be smaller depending on the [member spot_attenuation] in use. No matter the [member spot_attenuation] in use, the light will never reach anything outside this range.
+ [b]Note:[/b] [member spot_range] is not affected by [member Node3D.scale] (the light's scale or its parent's scale).
</member>
</members>
</class>
diff --git a/doc/classes/StandardMaterial3D.xml b/doc/classes/StandardMaterial3D.xml
index bd6e5cdfa2..0f6a3168eb 100644
--- a/doc/classes/StandardMaterial3D.xml
+++ b/doc/classes/StandardMaterial3D.xml
@@ -4,7 +4,7 @@
Physically based rendering (PBR) material that can be applied to 3D objects.
</brief_description>
<description>
- StandardMaterial3D's properties are inherited from [BaseMaterial3D].
+ [StandardMaterial3D]'s properties are inherited from [BaseMaterial3D]. [StandardMaterial3D] uses separate textures for ambient occlusion, roughness and metallic maps. To use a single ORM map for all 3 textures, use an [ORMMaterial3D] instead.
</description>
<tutorials>
<link title="Standard Material 3D and ORM Material 3D">$DOCS_URL/tutorials/3d/standard_material_3d.html</link>
diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml
index 21c160b780..2393790e12 100644
--- a/doc/classes/StaticBody2D.xml
+++ b/doc/classes/StaticBody2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Static body for 2D physics.
- A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], it doesn't consume any CPU resources as long as they don't move.
+ A static body is a simple body that doesn't move under physics simulation, i.e. it can't be moved by external forces or contacts but its transformation can still be updated manually by the user. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], it doesn't consume any CPU resources as long as they don't move.
They have extra functionalities to move and affect other bodies:
[b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
[b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
index daa71d1168..0beaa6bb52 100644
--- a/doc/classes/StaticBody3D.xml
+++ b/doc/classes/StaticBody3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Static body for 3D physics.
- A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move.
+ A static body is a simple body that doesn't move under physics simulation, i.e. it can't be moved by external forces or contacts but its transformation can still be updated manually by the user. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move.
They have extra functionalities to move and affect other bodies:
[b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
[b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 316bb923b7..089f6f65a4 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -364,7 +364,7 @@
<return type="bool" />
<param index="0" name="with_prefix" type="bool" default="false" />
<description>
- Returns [code]true[/code] if this string contains a valid hexadecimal number. If [param with_prefix] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
+ Returns [code]true[/code] if this string contains a valid hexadecimal number. If [param with_prefix] is [code]true[/code], then a validity of the hexadecimal number is determined by the [code]0x[/code] prefix, for example: [code]0xDEADC0DE[/code].
</description>
</method>
<method name="is_valid_html_color" qualifiers="const">
@@ -940,12 +940,6 @@
<description>
</description>
</operator>
- <operator name="operator +">
- <return type="String" />
- <param index="0" name="right" type="int" />
- <description>
- </description>
- </operator>
<operator name="operator &lt;">
<return type="bool" />
<param index="0" name="right" type="String" />
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index ccec691107..d56cc9a31b 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -133,6 +133,7 @@
<description>
Generates normals from vertices so you do not have to do it manually. If [param flip] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
[b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
+ [b]Note:[/b] [method generate_normals] takes smooth groups into account. If you don't specify any smooth group for each vertex, [method generate_normals] will smooth normals for you.
</description>
</method>
<method name="generate_tangents">
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 0905c0c20b..d4f5233438 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
TextEdit is meant for editing large, multiline text. It also has facilities for editing code, such as syntax highlighting support and multiple levels of undo/redo.
+ [b]Note:[/b] Most viewport, caret and edit methods contain a [code]caret_index[/code] argument for [member caret_multiple] support. The argument should be one of the following: [code]-1[/code] for all carets, [code]0[/code] for the main caret, or greater than [code]0[/code] for secondary carets.
[b]Note:[/b] When holding down [kbd]Alt[/kbd], the vertical scroll wheel will scroll 5 times as fast as it would normally do. This also works in the Godot script editor.
</description>
<tutorials>
@@ -12,18 +13,21 @@
<methods>
<method name="_backspace" qualifiers="virtual">
<return type="void" />
+ <param index="0" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user presses the backspace key.
</description>
</method>
<method name="_copy" qualifiers="virtual">
<return type="void" />
+ <param index="0" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user performs a copy operation.
</description>
</method>
<method name="_cut" qualifiers="virtual">
<return type="void" />
+ <param index="0" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user performs a cut operation.
</description>
@@ -31,23 +35,41 @@
<method name="_handle_unicode_input" qualifiers="virtual">
<return type="void" />
<param index="0" name="unicode_char" type="int" />
+ <param index="1" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user types in the provided key [param unicode_char].
</description>
</method>
<method name="_paste" qualifiers="virtual">
<return type="void" />
+ <param index="0" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user performs a paste operation.
</description>
</method>
<method name="_paste_primary_clipboard" qualifiers="virtual">
<return type="void" />
+ <param index="0" name="caret_index" type="int" />
<description>
Override this method to define what happens when the user performs a paste operation with middle mouse button.
[b]Note:[/b] This method is only implemented on Linux.
</description>
</method>
+ <method name="add_caret">
+ <return type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="col" type="int" />
+ <description>
+ Adds a new caret at the given location. Returns the index of the new caret, or [code]-1[/code] if the location is invalid.
+ </description>
+ </method>
+ <method name="add_caret_at_carets">
+ <return type="void" />
+ <param index="0" name="below" type="bool" />
+ <description>
+ Adds an additional caret above or below every caret. If [param below] is true the new caret will be added below and above otherwise.
+ </description>
+ </method>
<method name="add_gutter">
<return type="void" />
<param index="0" name="at" type="int" default="-1" />
@@ -55,14 +77,33 @@
Register a new gutter to this [TextEdit]. Use [param at] to have a specific gutter order. A value of [code]-1[/code] appends the gutter to the right.
</description>
</method>
+ <method name="add_selection_for_next_occurrence">
+ <return type="void" />
+ <description>
+ Adds a selection and a caret for the next occurrence of the current selection. If there is no active selection, selects word under caret.
+ </description>
+ </method>
+ <method name="adjust_carets_after_edit">
+ <return type="void" />
+ <param index="0" name="caret" type="int" />
+ <param index="1" name="from_line" type="int" />
+ <param index="2" name="from_col" type="int" />
+ <param index="3" name="to_line" type="int" />
+ <param index="4" name="to_col" type="int" />
+ <description>
+ Reposition the carets affected by the edit. This assumes edits are applied in edit order, see [method get_caret_index_edit_order].
+ </description>
+ </method>
<method name="adjust_viewport_to_caret">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Adjust the viewport so the caret is visible.
</description>
</method>
<method name="backspace">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Called when the user presses the backspace key. Can be overridden with [method _backspace].
</description>
@@ -75,6 +116,7 @@
</method>
<method name="center_viewport_to_caret">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Centers the viewport on the line the editing caret is at. This also resets the [member scroll_horizontal] value to [code]0[/code].
</description>
@@ -93,28 +135,38 @@
</method>
<method name="copy">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Copies the current text selection. Can be overridden with [method _copy].
</description>
</method>
<method name="cut">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Cut's the current selection. Can be overridden with [method _cut].
</description>
</method>
<method name="delete_selection">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Deletes the selected text.
</description>
</method>
<method name="deselect">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Deselects the current selection.
</description>
</method>
+ <method name="end_action">
+ <return type="void" />
+ <description>
+ Marks the end of steps in the current action started with [method start_action].
+ </description>
+ </method>
<method name="end_complex_operation">
<return type="void" />
<description>
@@ -123,24 +175,40 @@
</method>
<method name="get_caret_column" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the column the editing caret is at.
</description>
</method>
+ <method name="get_caret_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the number of carets in this [TextEdit].
+ </description>
+ </method>
<method name="get_caret_draw_pos" qualifiers="const">
<return type="Vector2" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the caret pixel draw position.
</description>
</method>
+ <method name="get_caret_index_edit_order">
+ <return type="PackedInt32Array" />
+ <description>
+ Returns a list of caret indexes in their edit order, this done from bottom to top. Edit order refers to the way actions such as [method insert_text_at_caret] are applied.
+ </description>
+ </method>
<method name="get_caret_line" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the line the editing caret is on.
</description>
</method>
<method name="get_caret_wrap_index" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the wrap index the editing caret is on.
</description>
@@ -185,6 +253,12 @@
Returns the width of the gutter at the given index.
</description>
</method>
+ <method name="get_h_scroll_bar" qualifiers="const">
+ <return type="HScrollBar" />
+ <description>
+ Returns the [HScrollBar] used by [TextEdit].
+ </description>
+ </method>
<method name="get_indent_level" qualifiers="const">
<return type="int" />
<param index="0" name="line" type="int" />
@@ -381,32 +455,37 @@
Returns the scroll position for [param wrap_index] of [param line].
</description>
</method>
- <method name="get_selected_text" qualifiers="const">
+ <method name="get_selected_text">
<return type="String" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Returns the text inside the selection.
</description>
</method>
<method name="get_selection_column" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the original start column of the selection.
</description>
</method>
<method name="get_selection_from_column" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the selection begin column.
</description>
</method>
<method name="get_selection_from_line" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the selection begin line.
</description>
</method>
<method name="get_selection_line" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the original start line of the selection.
</description>
@@ -419,12 +498,14 @@
</method>
<method name="get_selection_to_column" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the selection end column.
</description>
</method>
<method name="get_selection_to_line" qualifiers="const">
<return type="int" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns the selection end line.
</description>
@@ -447,6 +528,12 @@
Returns the number of lines that may be drawn.
</description>
</method>
+ <method name="get_v_scroll_bar" qualifiers="const">
+ <return type="VScrollBar" />
+ <description>
+ Returns the [VScrollBar] of the [TextEdit].
+ </description>
+ </method>
<method name="get_version" qualifiers="const">
<return type="int" />
<description>
@@ -476,6 +563,7 @@
</method>
<method name="get_word_under_caret" qualifiers="const">
<return type="String" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Returns a [String] text with the word under the caret's location.
</description>
@@ -494,6 +582,7 @@
</method>
<method name="has_selection" qualifiers="const">
<return type="bool" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Returns [code]true[/code] if the user has selected text.
</description>
@@ -515,12 +604,14 @@
<method name="insert_text_at_caret">
<return type="void" />
<param index="0" name="text" type="String" />
+ <param index="1" name="caret_index" type="int" default="-1" />
<description>
Insert the specified text at the caret position.
</description>
</method>
<method name="is_caret_visible" qualifiers="const">
<return type="bool" />
+ <param index="0" name="caret_index" type="int" default="0" />
<description>
Returns [code]true[/code] if the caret is visible on the screen.
</description>
@@ -576,6 +667,7 @@
<method name="is_mouse_over_selection" qualifiers="const">
<return type="bool" />
<param index="0" name="edges" type="bool" />
+ <param index="1" name="caret_index" type="int" default="-1" />
<description>
Returns whether the mouse is over selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
</description>
@@ -601,18 +693,41 @@
Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied.
</description>
</method>
+ <method name="merge_overlapping_carets">
+ <return type="void" />
+ <description>
+ Merges any overlapping carets. Will favour the newest caret, or the caret with a selection.
+ [b]Note:[/b] This is not called when a caret changes position but after certain actions, so it is possible to get into a state where carets overlap.
+ </description>
+ </method>
<method name="paste">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Paste at the current location. Can be overridden with [method _paste].
</description>
</method>
+ <method name="paste_primary_clipboard">
+ <return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
+ <description>
+ Pastes the primary clipboard.
+ </description>
+ </method>
<method name="redo">
<return type="void" />
<description>
Perform redo operation.
</description>
</method>
+ <method name="remove_caret">
+ <return type="void" />
+ <param index="0" name="caret" type="int" />
+ <description>
+ Removes the given caret index.
+ [b]Note:[/b] This can result in adjustment of all other caret indices.
+ </description>
+ </method>
<method name="remove_gutter">
<return type="void" />
<param index="0" name="gutter" type="int" />
@@ -620,6 +735,12 @@
Removes the gutter from this [TextEdit].
</description>
</method>
+ <method name="remove_secondary_carets">
+ <return type="void" />
+ <description>
+ Removes all additional carets.
+ </description>
+ </method>
<method name="remove_text">
<return type="void" />
<param index="0" name="from_line" type="int" />
@@ -666,6 +787,7 @@
<param index="1" name="from_column" type="int" />
<param index="2" name="to_line" type="int" />
<param index="3" name="to_column" type="int" />
+ <param index="4" name="caret_index" type="int" default="0" />
<description>
Perform selection, from line/column to line/column.
If [member selecting_enabled] is [code]false[/code], no selection will occur.
@@ -680,6 +802,7 @@
</method>
<method name="select_word_under_caret">
<return type="void" />
+ <param index="0" name="caret_index" type="int" default="-1" />
<description>
Selects the word under the caret.
</description>
@@ -688,9 +811,11 @@
<return type="void" />
<param index="0" name="column" type="int" />
<param index="1" name="adjust_viewport" type="bool" default="true" />
+ <param index="2" name="caret_index" type="int" default="0" />
<description>
Moves the caret to the specified [param column] index.
If [param adjust_viewport] is [code]true[/code], the viewport will center at the caret position after the move occurs.
+ [b]Note:[/b] If supporting multiple carets this will not check for any overlap. See [method merge_overlapping_carets].
</description>
</method>
<method name="set_caret_line">
@@ -699,10 +824,12 @@
<param index="1" name="adjust_viewport" type="bool" default="true" />
<param index="2" name="can_be_hidden" type="bool" default="true" />
<param index="3" name="wrap_index" type="int" default="0" />
+ <param index="4" name="caret_index" type="int" default="0" />
<description>
Moves the caret to the specified [param line] index.
If [param adjust_viewport] is [code]true[/code], the viewport will center at the caret position after the move occurs.
If [param can_be_hidden] is [code]true[/code], the specified [code]line[/code] can be hidden.
+ [b]Note:[/b] If supporting multiple carets this will not check for any overlap. See [method merge_overlapping_carets].
</description>
</method>
<method name="set_gutter_clickable">
@@ -872,6 +999,7 @@
<param index="0" name="mode" type="int" enum="TextEdit.SelectionMode" />
<param index="1" name="line" type="int" default="-1" />
<param index="2" name="column" type="int" default="-1" />
+ <param index="3" name="caret_index" type="int" default="0" />
<description>
Sets the current selection mode.
</description>
@@ -890,6 +1018,14 @@
Provide custom tooltip text. The callback method must take the following args: [code]hovered_word: String[/code]
</description>
</method>
+ <method name="start_action">
+ <return type="void" />
+ <param index="0" name="action" type="int" enum="TextEdit.EditAction" />
+ <description>
+ Starts an action, will end the current action if [code]action[/code] is different.
+ An action will also end after a call to [method end_action], after [member ProjectSettings.gui/timers/text_edit_idle_detect_sec] is triggered or a new undoable step outside the [method start_action] and [method end_action] calls.
+ </description>
+ </method>
<method name="swap_lines">
<return type="void" />
<param index="0" name="from_line" type="int" />
@@ -926,6 +1062,9 @@
If [code]true[/code], a right-click moves the caret at the mouse position before displaying the context menu.
If [code]false[/code], the context menu disregards mouse location.
</member>
+ <member name="caret_multiple" type="bool" setter="set_multiple_carets_enabled" getter="is_multiple_carets_enabled" default="true">
+ Sets if multiple carets are allowed.
+ </member>
<member name="caret_type" type="int" setter="set_caret_type" getter="get_caret_type" enum="TextEdit.CaretType" default="0">
Set the type of caret to draw.
</member>
@@ -971,9 +1110,6 @@
The width, in pixels, of the minimap.
</member>
<member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" overrides="Control" enum="Control.CursorShape" default="1" />
- <member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color" default="false">
- If [code]true[/code], custom [code]font_selected_color[/code] will be used for selected text.
- </member>
<member name="placeholder_text" type="String" setter="set_placeholder" getter="get_placeholder" default="&quot;&quot;">
Text shown when the [TextEdit] is empty. It is [b]not[/b] the [TextEdit]'s default value (see [member text]).
</member>
@@ -1154,6 +1290,18 @@
<constant name="MENU_MAX" value="28" enum="MenuItems">
Represents the size of the [enum MenuItems] enum.
</constant>
+ <constant name="ACTION_NONE" value="0" enum="EditAction">
+ No current action.
+ </constant>
+ <constant name="ACTION_TYPING" value="1" enum="EditAction">
+ A typing action.
+ </constant>
+ <constant name="ACTION_BACKSPACE" value="2" enum="EditAction">
+ A backwards delete action.
+ </constant>
+ <constant name="ACTION_DELETE" value="3" enum="EditAction">
+ A forward delete action.
+ </constant>
<constant name="SEARCH_MATCH_CASE" value="1" enum="SearchFlags">
Match case when searching.
</constant>
@@ -1225,8 +1373,8 @@
<theme_item name="font_readonly_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
Sets the font [Color] when [member editable] is disabled.
</theme_item>
- <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
- Sets the [Color] of the selected text. [member override_selected_font_color] has to be enabled.
+ <theme_item name="font_selected_color" data_type="color" type="Color" default="Color(0, 0, 0, 0)">
+ Sets the [Color] of the selected text. If equal to [code]Color(0, 0, 0, 0)[/code], it will be ignored.
</theme_item>
<theme_item name="search_result_border_color" data_type="color" type="Color" default="Color(0.3, 0.3, 0.3, 0.4)">
[Color] of the border around text that matches the search query.
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index 471c1a9040..d1dfdecbd2 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -144,6 +144,7 @@
</methods>
<members>
<member name="alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0">
+ Sets text alignment within the line as if the line was horizontal.
</member>
<member name="direction" type="int" setter="set_direction" getter="get_direction" enum="TextServer.Direction" default="0">
Text writing direction.
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 2512c563c5..0b822a4fe9 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -413,7 +413,7 @@
<param index="1" name="size" type="Vector2i" />
<param index="2" name="texture_index" type="int" />
<description>
- Returns array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
+ Returns array containing glyph packing data.
</description>
</method>
<method name="font_get_transform" qualifiers="const">
@@ -824,7 +824,7 @@
<param index="2" name="texture_index" type="int" />
<param index="3" name="offset" type="PackedInt32Array" />
<description>
- Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
+ Sets array containing glyph packing data.
</description>
</method>
<method name="font_set_transform">
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 14e89a1b74..3dd8c339b2 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -33,7 +33,7 @@
</method>
<method name="_draw_rect_region" qualifiers="virtual const">
<return type="void" />
- <param index="0" name="tp_canvas_item" type="RID" />
+ <param index="0" name="to_canvas_item" type="RID" />
<param index="1" name="rect" type="Rect2" />
<param index="2" name="src_rect" type="Rect2" />
<param index="3" name="modulate" type="Color" />
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index fd9c44091c..01246f0c2e 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -155,6 +155,7 @@
<method name="get_layers_count" qualifiers="const">
<return type="int" />
<description>
+ Returns the number of layers in the TileMap.
</description>
</method>
<method name="get_neighbor_cell" qualifiers="const">
@@ -364,7 +365,7 @@
Show or hide the TileMap's collision shapes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show collision debug settings.
</member>
<member name="navigation_visibility_mode" type="int" setter="set_navigation_visibility_mode" getter="get_navigation_visibility_mode" enum="TileMap.VisibilityMode" default="0">
- Show or hide the TileMap's collision shapes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings.
+ Show or hide the TileMap's navigation meshes. If set to [constant VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings.
</member>
<member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset">
The assigned [TileSet].
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 905b3d77af..23d20a5a75 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -123,6 +123,12 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this transform is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="const">
<return type="Transform2D" />
<param index="0" name="target" type="Vector2" default="Vector2(0, 0)" />
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index 18b4f9e6f9..b3145ea022 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -82,6 +82,12 @@
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this transform is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="looking_at" qualifiers="const">
<return type="Transform3D" />
<param index="0" name="target" type="Vector3" />
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index c109dc57f7..a8ffef427f 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -425,6 +425,15 @@
Sets the given column's button [Texture2D] at index [param button_idx] to [param button].
</description>
</method>
+ <method name="set_button_color">
+ <return type="void" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
+ <param index="2" name="color" type="Color" />
+ <description>
+ Sets the given column's button color at index [param button_idx] to [param color].
+ </description>
+ </method>
<method name="set_button_disabled">
<return type="void" />
<param index="0" name="column" type="int" />
diff --git a/doc/classes/VSlider.xml b/doc/classes/VSlider.xml
index 36954a6912..488154106f 100644
--- a/doc/classes/VSlider.xml
+++ b/doc/classes/VSlider.xml
@@ -14,6 +14,9 @@
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="1" />
</members>
<theme_items>
+ <theme_item name="grabber_offset" data_type="constant" type="int" default="0">
+ Horizontal offset of the grabber.
+ </theme_item>
<theme_item name="grabber" data_type="icon" type="Texture2D">
The texture for the grabber (the draggable element).
</theme_item>
@@ -30,6 +33,7 @@
The background of the area below the grabber.
</theme_item>
<theme_item name="grabber_area_highlight" data_type="style" type="StyleBox">
+ The background of the area below the grabber, to the left of the grabber.
</theme_item>
<theme_item name="slider" data_type="style" type="StyleBox">
The background for the whole slider. Determines the width of the [code]grabber_area[/code].
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index e1852340c0..5590f82336 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -206,6 +206,12 @@
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 1ef84050cd..1a2cdfe10e 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -174,10 +174,16 @@
Returns [code]true[/code] if this vector and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
+ Returns [code]true[/code] if the vector is [method normalized], [code]false[/code] otherwise.
</description>
</method>
<method name="is_zero_approx" qualifiers="const">
@@ -238,18 +244,22 @@
<method name="normalized" qualifiers="const">
<return type="Vector3" />
<description>
- Returns the vector scaled to unit length. Equivalent to [code]v / v.length()[/code].
+ Returns the vector scaled to unit length. Equivalent to [code]v / v.length()[/code]. See also [method is_normalized].
</description>
</method>
<method name="octahedron_decode" qualifiers="static">
<return type="Vector3" />
<param index="0" name="uv" type="Vector2" />
<description>
+ Returns the [Vector3] from an octahedral-compressed form created using [method octahedron_encode] (stored as a [Vector2]).
</description>
</method>
<method name="octahedron_encode" qualifiers="const">
<return type="Vector2" />
<description>
+ Returns the octahedral-encoded (oct32) form of this [Vector3] as a [Vector2]. Since a [Vector2] occupies 1/3 less memory compared to [Vector3], this form of compression can be used to pass greater amounts of [method normalized] [Vector3]s without increasing storage or memory requirements. See also [method octahedron_decode].
+ [b]Note:[/b] [method octahedron_encode] can only be used for [method normalized] vectors. [method octahedron_encode] does [i]not[/i] check whether this [Vector3] is normalized, and will return a value that does not decompress to the original value if the [Vector3] is not normalized.
+ [b]Note:[/b] Octahedral compression is [i]lossy[/i], although visual differences are rarely perceptible in real world scenarios.
</description>
</method>
<method name="outer" qualifiers="const">
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index fdc93f82ec..662d0bce3a 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -135,6 +135,12 @@
Returns [code]true[/code] if this vector and [param with] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
+ <method name="is_finite" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this vector is finite, by calling [method @GlobalScope.is_finite] on each component.
+ </description>
+ </method>
<method name="is_normalized" qualifiers="const">
<return type="bool" />
<description>
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index 3eea93ce1f..e9ac5b9475 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -133,12 +133,20 @@
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Gets the remainder of each component of the [Vector4i] with the components of the given [Vector4i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
+ [codeblock]
+ print(Vector4i(10, -20, 30, -40) % Vector4i(7, 8, 9, 10)) # Prints "(3, -4, 3, 0)"
+ [/codeblock]
</description>
</operator>
<operator name="operator %">
<return type="Vector4i" />
<param index="0" name="right" type="int" />
<description>
+ Gets the remainder of each component of the [Vector4i] with the the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
+ [codeblock]
+ print(Vector4i(10, -20, 30, -40) % 7) # Prints "(3, -6, 2, -5)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 87ee26fa32..78013a8f4b 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -45,6 +45,13 @@
Returns the currently active 3D camera.
</description>
</method>
+ <method name="get_canvas_cull_mask_bit" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="layer" type="int" />
+ <description>
+ Returns an individual bit on the rendering layer mask.
+ </description>
+ </method>
<method name="get_final_transform" qualifiers="const">
<return type="Transform2D" />
<description>
@@ -71,6 +78,12 @@
<description>
</description>
</method>
+ <method name="get_screen_transform" qualifiers="const">
+ <return type="Transform2D" />
+ <description>
+ Returns the transform from the Viewport's coordinates to the screen coordinates of the containing window manager window.
+ </description>
+ </method>
<method name="get_texture" qualifiers="const">
<return type="ViewportTexture" />
<description>
@@ -129,6 +142,9 @@
<method name="is_input_handled" qualifiers="const">
<return type="bool" />
<description>
+ Returns whether the current [InputEvent] has been handled. Input events are not handled until [method set_input_as_handled] has been called during the lifetime of an [InputEvent].
+ This is usually done as part of input handling methods like [method Node._input], [method Control._gui_input] or others, as well as in corresponding signal handlers.
+ If [member handle_input_locally] is set to [code]false[/code], this method will try finding the first parent viewport that is set to handle input locally, and return its value for [method is_input_handled] instead.
</description>
</method>
<method name="push_input">
@@ -136,6 +152,13 @@
<param index="0" name="event" type="InputEvent" />
<param index="1" name="in_local_coords" type="bool" default="false" />
<description>
+ Triggers the given [param event] in this [Viewport]. This can be used to pass an [InputEvent] between viewports, or to locally apply inputs that were sent over the network or saved to a file.
+ If [param in_local_coords] is [code]false[/code], the event's position is in the embedder's coordinates and will be converted to viewport coordinates. If [param in_local_coords] is [code]true[/code], the event's position is in viewport coordinates.
+ While this method serves a similar purpose as [method Input.parse_input_event], it does not remap the specified [param event] based on project settings like [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse].
+ Calling this method will propagate calls to child nodes for following methods in the given order:
+ - [method Node._input]
+ - [method Control._gui_input] for [Control] nodes
+ If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
</description>
</method>
<method name="push_text_input">
@@ -149,6 +172,23 @@
<param index="0" name="event" type="InputEvent" />
<param index="1" name="in_local_coords" type="bool" default="false" />
<description>
+ Triggers the given [InputEvent] in this [Viewport]. This can be used to pass input events between viewports, or to locally apply inputs that were sent over the network or saved to a file.
+ If [param in_local_coords] is [code]false[/code], the event's position is in the embedder's coordinates and will be converted to viewport coordinates. If [param in_local_coords] is [code]true[/code], the event's position is in viewport coordinates.
+ While this method serves a similar purpose as [method Input.parse_input_event], it does not remap the specified [param event] based on project settings like [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse].
+ Calling this method will propagate calls to child nodes for following methods in the given order:
+ - [method Node._shortcut_input]
+ - [method Node._unhandled_input]
+ - [method Node._unhandled_key_input]
+ If an earlier method marks the input as handled via [method set_input_as_handled], any later method in this list will not be called.
+ If none of the methods handle the event and [member physics_object_picking] is [code]true[/code], the event is used for physics object picking.
+ </description>
+ </method>
+ <method name="set_canvas_cull_mask_bit">
+ <return type="void" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="enable" type="bool" />
+ <description>
+ Set/clear individual bits on the rendering layer mask. This simplifies editing this [Viewport]'s layers.
</description>
</method>
<method name="set_input_as_handled">
@@ -180,6 +220,9 @@
<member name="audio_listener_enable_3d" type="bool" setter="set_as_audio_listener_3d" getter="is_audio_listener_3d" default="false">
If [code]true[/code], the viewport will process 3D audio streams.
</member>
+ <member name="canvas_cull_mask" type="int" setter="set_canvas_cull_mask" getter="get_canvas_cull_mask" default="4294967295">
+ The rendering layers in which this [Viewport] renders [CanvasItem] nodes.
+ </member>
<member name="canvas_item_default_texture_filter" type="int" setter="set_default_canvas_item_texture_filter" getter="get_default_canvas_item_texture_filter" enum="Viewport.DefaultCanvasItemTextureFilter" default="1">
Sets the default filter mode used by [CanvasItem]s in this Viewport. See [enum DefaultCanvasItemTextureFilter] for options.
</member>
@@ -212,6 +255,9 @@
If [code]true[/code], the GUI controls on the viewport will lay pixel perfectly.
</member>
<member name="handle_input_locally" type="bool" setter="set_handle_input_locally" getter="is_handling_input_locally" default="true">
+ If [code]true[/code], this viewport will mark incoming input events as handled by itself. If [code]false[/code], this is instead done by the the first parent viewport that is set to handle input locally.
+ A [SubViewportContainer] will automatically set this property to [code]false[/code] for the [Viewport] contained inside of it.
+ See also [method set_input_as_handled] and [method is_input_handled].
</member>
<member name="mesh_lod_threshold" type="float" setter="set_mesh_lod_threshold" getter="get_mesh_lod_threshold" default="1.0">
The automatic LOD bias to use for meshes rendered within the [Viewport] (this is analogous to [member ReflectionProbe.mesh_lod_threshold]). Higher values will use less detailed versions of meshes that have LOD variations generated. If set to [code]0.0[/code], automatic LOD is disabled. Increase [member mesh_lod_threshold] to improve performance at the cost of geometry detail.
@@ -278,6 +324,8 @@
If [code]true[/code], the viewport should render its background as transparent.
</member>
<member name="use_debanding" type="bool" setter="set_use_debanding" getter="is_using_debanding" default="false">
+ If [code]true[/code], uses a fast post-processing filter to make banding significantly less visible in 3D. 2D rendering is [i]not[/i] affected by debanding unless the [member Environment.background_mode] is [constant Environment.BG_CANVAS]. See also [member ProjectSettings.rendering/anti_aliasing/quality/use_debanding].
+ In some cases, debanding may introduce a slightly noticeable dithering pattern. It's recommended to enable debanding only when actually needed since the dithering pattern will make lossless-compressed screenshots larger.
</member>
<member name="use_occlusion_culling" type="bool" setter="set_use_occlusion_culling" getter="is_using_occlusion_culling" default="false">
If [code]true[/code], [OccluderInstance3D] nodes will be usable for occlusion culling in 3D for this viewport. For the root viewport, [member ProjectSettings.rendering/occlusion_culling/use_occlusion_culling] must be set to [code]true[/code] instead.
diff --git a/doc/classes/ViewportTexture.xml b/doc/classes/ViewportTexture.xml
index 87de664aad..6bd64a50bb 100644
--- a/doc/classes/ViewportTexture.xml
+++ b/doc/classes/ViewportTexture.xml
@@ -6,6 +6,7 @@
<description>
Displays the content of a [Viewport] node as a dynamic [Texture2D]. This can be used to mix controls, 2D, and 3D elements in the same scene.
To create a ViewportTexture in code, use the [method Viewport.get_texture] method on the target viewport.
+ [b]Note:[/b] When local to scene, this texture uses [method Resource.setup_local_to_scene] to set the proxy texture and flags in the local viewport.
</description>
<tutorials>
<link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
diff --git a/doc/classes/VisibleOnScreenEnabler2D.xml b/doc/classes/VisibleOnScreenEnabler2D.xml
index 50d0c00017..8590e9cc9f 100644
--- a/doc/classes/VisibleOnScreenEnabler2D.xml
+++ b/doc/classes/VisibleOnScreenEnabler2D.xml
@@ -1,23 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisibleOnScreenEnabler2D" inherits="VisibleOnScreenNotifier2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Automatically disables another node if not visible on screen.
</brief_description>
<description>
+ VisibleOnScreenEnabler2D detects when it is visible on screen (just like [VisibleOnScreenNotifier2D]) and automatically enables or disables the target node. The target node is disabled when [VisibleOnScreenEnabler2D] is not visible on screen (including when [member CanvasItem.visible] is [code]false[/code]), and enabled when the enabler is visible. The disabling is achieved by changing [member Node.process_mode].
</description>
<tutorials>
</tutorials>
<members>
<member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibleOnScreenEnabler2D.EnableMode" default="0">
+ Determines how the node is enabled. Corresponds to [enum Node.ProcessMode]. Disabled node uses [constant Node.PROCESS_MODE_DISABLED].
</member>
<member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath(&quot;..&quot;)">
+ The path to the target node, relative to the [VisibleOnScreenEnabler2D]. The target node is cached; it's only assigned when setting this property (if the [VisibleOnScreenEnabler2D] is inside scene tree) and every time the [VisibleOnScreenEnabler2D] enters the scene tree. If the path is invalid, nothing will happen.
</member>
</members>
<constants>
<constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_INHERIT].
</constant>
<constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_ALWAYS].
</constant>
<constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode">
+ Corresponds to [constant Node.PROCESS_MODE_WHEN_PAUSED.
</constant>
</constants>
</class>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 9574686506..94e8c25660 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -17,7 +17,7 @@
<method name="get_aabb" qualifiers="const">
<return type="AABB" />
<description>
- Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D]. See also [method get_transformed_aabb].
+ Returns the [AABB] (also known as the bounding box) for this [VisualInstance3D].
</description>
</method>
<method name="get_base" qualifiers="const">
@@ -39,13 +39,6 @@
Returns whether or not the specified layer of the [member layers] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
</method>
- <method name="get_transformed_aabb" qualifiers="const">
- <return type="AABB" />
- <description>
- Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance3D].
- Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform3D]. See also [method get_aabb].
- </description>
- </method>
<method name="set_base">
<return type="void" />
<param index="0" name="base" type="RID" />
diff --git a/doc/classes/VisualShaderNodeFloatParameter.xml b/doc/classes/VisualShaderNodeFloatParameter.xml
index c0fd88294a..3b5bf57b4d 100644
--- a/doc/classes/VisualShaderNodeFloatParameter.xml
+++ b/doc/classes/VisualShaderNodeFloatParameter.xml
@@ -16,7 +16,7 @@
Enables usage of the [member default_value].
</member>
<member name="hint" type="int" setter="set_hint" getter="get_hint" enum="VisualShaderNodeFloatParameter.Hint" default="0">
- A hint applied to the uniform, which controls the values it can take when set through the inspector.
+ A hint applied to the uniform, which controls the values it can take when set through the Inspector.
</member>
<member name="max" type="float" setter="set_max" getter="get_max" default="1.0">
Minimum value for range hints. Used if [member hint] is set to [constant HINT_RANGE] or [constant HINT_RANGE_STEP].
diff --git a/doc/classes/VisualShaderNodeParameter.xml b/doc/classes/VisualShaderNodeParameter.xml
index c66022f77d..55b10ac810 100644
--- a/doc/classes/VisualShaderNodeParameter.xml
+++ b/doc/classes/VisualShaderNodeParameter.xml
@@ -4,7 +4,7 @@
A base type for the parameters within the visual shader graph.
</brief_description>
<description>
- A parameter represents a variable in the shader which is set externally, i.e. from the [ShaderMaterial]. Parameters are exposed as properties in the [ShaderMaterial] and can be assigned from the inspector or from a script.
+ A parameter represents a variable in the shader which is set externally, i.e. from the [ShaderMaterial]. Parameters are exposed as properties in the [ShaderMaterial] and can be assigned from the Inspector or from a script.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/VoxelGIData.xml b/doc/classes/VoxelGIData.xml
index 92b2e66e5a..bd9df18394 100644
--- a/doc/classes/VoxelGIData.xml
+++ b/doc/classes/VoxelGIData.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
[VoxelGIData] contains baked voxel global illumination for use in a [VoxelGI] node. [VoxelGIData] also offers several properties to adjust the final appearance of the global illumination. These properties can be adjusted at run-time without having to bake the [VoxelGI] node again.
- [b]Note:[/b] To prevent text-based scene files ([code].tscn[/code]) from growing too much and becoming slow to load and save, always save [VoxelGIData] to an external binary resource file ([code].res[/code]) instead of embedding it within the scene. This can be done by clicking the dropdown arrow next to the [VoxelGIData] resource, choosing [b]Edit[/b], clicking the floppy disk icon at the top of the inspector then choosing [b]Save As...[/b].
+ [b]Note:[/b] To prevent text-based scene files ([code].tscn[/code]) from growing too much and becoming slow to load and save, always save [VoxelGIData] to an external binary resource file ([code].res[/code]) instead of embedding it within the scene. This can be done by clicking the dropdown arrow next to the [VoxelGIData] resource, choosing [b]Edit[/b], clicking the floppy disk icon at the top of the Inspector then choosing [b]Save As...[/b].
</description>
<tutorials>
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index c585b54ee1..8707ef003a 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -355,7 +355,7 @@
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Window.Mode" default="0">
Set's the window's current mode.
- [b]Note:[/b] Fullscreen mode is not exclusive fullscreen on Windows and Linux.
+ [b]Note:[/b] Fullscreen mode is not exclusive full screen on Windows and Linux.
</member>
<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
@@ -377,12 +377,13 @@
The window's title. If the [Window] is non-embedded, title styles set in [Theme] will have no effect.
</member>
<member name="transient" type="bool" setter="set_transient" getter="is_transient" default="false">
- If [code]true[/code], the [Window] is transient, i.e. it's considered a child of another [Window]. Transient windows can't be in fullscreen mode and will return focus to their parent when closed.
+ If [code]true[/code], the [Window] is transient, i.e. it's considered a child of another [Window]. Transient window is will be destroyed with its transient parent and will return focus to their parent when closed. The transient window is displayed on top of a non-exclusive full-screen parent window. Transient windows can't enter full-screen mode.
Note that behavior might be different depending on the platform.
</member>
<member name="transparent" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window]'s background can be transparent. This is best used with embedded windows.
- [b]Note:[/b] This flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
+ [b]Note:[/b] For native windows, this flag has no effect if [member ProjectSettings.display/window/per_pixel_transparency/allowed] is set to [code]false[/code].
+ [b]Note:[/b] Transparency support is implemented on Linux, macOS and Windows, but availability might vary depending on GPU driver, display manager, and compositor capabilities.
</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.
@@ -457,7 +458,7 @@
</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.
+ 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">
@@ -468,7 +469,7 @@
<signal name="window_input">
<param index="0" name="event" type="InputEvent" />
<description>
- Emitted when the [Window] is currently focused and receives any input, passing the received event as an argument.
+ Emitted when the [Window] is currently focused and receives any input, passing the received event as an argument. The event's position, if present, is in the embedder's coordinate system.
</description>
</signal>
</signals>
@@ -484,43 +485,45 @@
[b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree.
</constant>
<constant name="MODE_WINDOWED" value="0" enum="Mode">
- Windowed mode, i.e. [Window] doesn't occupy whole screen (unless set to the size of the screen).
+ Windowed mode, i.e. [Window] doesn't occupy the whole screen (unless set to the size of the screen).
</constant>
<constant name="MODE_MINIMIZED" value="1" enum="Mode">
- Minimized window mode, i.e. [Window] is not visible and available on window manager's window list. Normally happens when the minimize button is presesd.
+ Minimized window mode, i.e. [Window] is not visible and available on window manager's window list. Normally happens when the minimize button is pressed.
</constant>
<constant name="MODE_MAXIMIZED" value="2" enum="Mode">
- Maximized window mode, i.e. [Window] will occupy whole screen area except task bar and still display its borders. Normally happens when the minimize button is presesd.
+ Maximized window mode, i.e. [Window] will occupy whole screen area except task bar and still display its borders. Normally happens when the maximize button is pressed.
</constant>
<constant name="MODE_FULLSCREEN" value="3" enum="Mode">
- Fullscreen window mode. 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.
+ Full screen window mode. Note that this is not [i]exclusive[/i] full screen. On Windows and Linux, a borderless window is used to emulate full screen. On macOS, a new desktop is used to display the running project.
+ Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="MODE_EXCLUSIVE_FULLSCREEN" value="4" enum="Mode">
- Exclusive fullscreen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant MODE_FULLSCREEN].
- Only one window in exclusive fullscreen mode can be visible on a given screen at a time. If multiple windows are in exclusive fullscreen mode for the same screen, the last one being set to this mode takes precedence.
- 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.
+ Exclusive full screen window mode. This mode is implemented on Windows only. On other platforms, it is equivalent to [constant MODE_FULLSCREEN].
+ Only one window in exclusive full screen mode can be visible on a given screen at a time. If multiple windows are in exclusive full screen mode for the same screen, the last one being set to this mode takes precedence.
+ Regardless of the platform, enabling full screen 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 full screen mode.
</constant>
<constant name="FLAG_RESIZE_DISABLED" value="0" enum="Flags">
- The window's ability to be resized. Set with [member unresizable].
+ The window can't be resizing by dragging its resize grip. It's still possible to resize the window using [member size]. This flag is ignored for full screen windows. Set with [member unresizable].
</constant>
<constant name="FLAG_BORDERLESS" value="1" enum="Flags">
- Borderless window. Set with [member borderless].
+ The window do not have native title bar and other decorations. This flag is ignored for full-screen windows. Set with [member borderless].
</constant>
<constant name="FLAG_ALWAYS_ON_TOP" value="2" enum="Flags">
- Flag for making the window always on top of all other windows. Set with [member always_on_top].
+ The window is floating on top of all other windows. This flag is ignored for full-screen windows. Set with [member always_on_top].
</constant>
<constant name="FLAG_TRANSPARENT" value="3" enum="Flags">
- Flag for per-pixel transparency. Set with [member transparent].
+ The 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]. Set with [member transparent].
</constant>
<constant name="FLAG_NO_FOCUS" value="4" enum="Flags">
- The window's ability to gain focus. Set with [member unfocusable].
+ The window can't be focused. No-focus window will ignore all input, except mouse clicks. Set with [member unfocusable].
</constant>
<constant name="FLAG_POPUP" value="5" enum="Flags">
- Whether the window is popup or a regular window. Set with [member popup_window].
+ Window is part of menu or [OptionButton] dropdown. This flag can't be changed when the window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [code]transient parent[/code] set (see [member transient]).
</constant>
<constant name="FLAG_EXTEND_TO_TITLE" value="6" enum="Flags">
- Window contents is expanded to the full size of the window, window title bar is transparent.
+ 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. Set with [member extend_to_title].
+ [b]Note:[/b] This flag is implemented on macOS.
</constant>
<constant name="FLAG_MAX" value="7" enum="Flags">
Max value of the [enum Flags].
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index b0cf126d7b..4a13389708 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -14,7 +14,7 @@
The [RID] of this world's canvas resource. Used by the [RenderingServer] for 2D drawing.
</member>
<member name="direct_space_state" type="PhysicsDirectSpaceState2D" setter="" getter="get_direct_space_state">
- Direct access to the world's physics 2D space state. Used for querying current and potential collisions. When using multi-threaded physics, access is limited to [code]_physics_process(delta)[/code] in the main thread.
+ Direct access to the world's physics 2D space state. Used for querying current and potential collisions. When using multi-threaded physics, access is limited to [method Node._physics_process] in the main thread.
</member>
<member name="navigation_map" type="RID" setter="" getter="get_navigation_map">
The [RID] of this world's navigation map. Used by the [NavigationServer2D].
diff --git a/doc/classes/World3D.xml b/doc/classes/World3D.xml
index f3c7136075..5e58bb0360 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -14,7 +14,7 @@
The default [CameraAttributes] resource to use if none set on the [Camera3D].
</member>
<member name="direct_space_state" type="PhysicsDirectSpaceState3D" setter="" getter="get_direct_space_state">
- Direct access to the world's physics 3D space state. Used for querying current and potential collisions.
+ Direct access to the world's physics 3D space state. Used for querying current and potential collisions. When using multi-threaded physics, access is limited to [method Node._physics_process] in the main thread.
</member>
<member name="environment" type="Environment" setter="set_environment" getter="get_environment">
The World3D's [Environment].
diff --git a/doc/classes/XRInterfaceExtension.xml b/doc/classes/XRInterfaceExtension.xml
index 06ef18b534..5958999037 100644
--- a/doc/classes/XRInterfaceExtension.xml
+++ b/doc/classes/XRInterfaceExtension.xml
@@ -39,6 +39,18 @@
Returns the capabilities of this interface.
</description>
</method>
+ <method name="_get_color_texture" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ Return color texture into which to render (if applicable).
+ </description>
+ </method>
+ <method name="_get_depth_texture" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ Return depth texture into which to render (if applicable).
+ </description>
+ </method>
<method name="_get_name" qualifiers="virtual const">
<return type="StringName" />
<description>
@@ -100,6 +112,12 @@
Returns a [Transform3D] for a given view.
</description>
</method>
+ <method name="_get_velocity_texture" qualifiers="virtual">
+ <return type="RID" />
+ <description>
+ Return velocity texture into which to render (if applicable).
+ </description>
+ </method>
<method name="_get_view_count" qualifiers="virtual">
<return type="int" />
<description>
@@ -213,6 +231,16 @@
Blits our render results to screen optionally applying lens distortion. This can only be called while processing [code]_commit_views[/code].
</description>
</method>
+ <method name="get_color_texture">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="get_depth_texture">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
<method name="get_render_target_texture">
<return type="RID" />
<param index="0" name="render_target" type="RID" />
@@ -220,5 +248,10 @@
Returns a valid [RID] for a texture to which we should render the current frame if supported by the interface.
</description>
</method>
+ <method name="get_velocity_texture">
+ <return type="RID" />
+ <description>
+ </description>
+ </method>
</methods>
</class>
diff --git a/doc/classes/XROrigin3D.xml b/doc/classes/XROrigin3D.xml
index 7acee097e7..506d0fce41 100644
--- a/doc/classes/XROrigin3D.xml
+++ b/doc/classes/XROrigin3D.xml
@@ -13,6 +13,9 @@
<link title="XR documentation index">$DOCS_URL/tutorials/xr/index.html</link>
</tutorials>
<members>
+ <member name="current" type="bool" setter="set_current" getter="is_current" default="false">
+ Is this XROrigin3D node the current origin used by the [XRServer]?
+ </member>
<member name="world_scale" type="float" setter="set_world_scale" getter="get_world_scale" default="1.0">
Allows you to adjust the scale to your game's units. Most AR/VR platforms assume a scale of 1 game world unit = 1 real world meter.
[b]Note:[/b] This method is a passthrough to the [XRServer] itself.
diff --git a/doc/classes/XRPose.xml b/doc/classes/XRPose.xml
index 0e58fab9b3..31a484ea40 100644
--- a/doc/classes/XRPose.xml
+++ b/doc/classes/XRPose.xml
@@ -30,7 +30,7 @@
<member name="name" type="StringName" setter="set_name" getter="get_name" default="&amp;&quot;&quot;">
The name of this pose. Pose names are often driven by an action map setup by the user. Godot does suggest a number of pose names that it expects [XRInterface]s to implement:
- [code]root[/code] defines a root location, often used for tracked objects that do not have further nodes.
- - [code]aim[/code] defines the tip of a controller with the orientation pointing outwards, for instance: add your raycasts to this.
+ - [code]aim[/code] defines the tip of a controller with the orientation pointing outwards, for example: add your raycasts to this.
- [code]grip[/code] defines the location where the user grips the controller
- [code]skeleton[/code] defines the root location a hand mesh should be placed when using hand tracking and the animated skeleton supplied by the XR runtime.
</member>
@@ -46,7 +46,7 @@
No tracking information is available for this pose.
</constant>
<constant name="XR_TRACKING_CONFIDENCE_LOW" value="1" enum="TrackingConfidence">
- Tracking information may be inaccurate or estimated. For instance with inside out tracking this would indicate a controller may be (partially) obscured.
+ Tracking information may be inaccurate or estimated. For example, with inside out tracking this would indicate a controller may be (partially) obscured.
</constant>
<constant name="XR_TRACKING_CONFIDENCE_HIGH" value="2" enum="TrackingConfidence">
Tracking information is deemed accurate and up to date.
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 48b00323d3..d940ea41ac 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -30,18 +30,18 @@
<param index="1" name="keep_height" type="bool" />
<description>
This is an important function to understand correctly. AR and VR platforms all handle positioning slightly differently.
- For platforms that do not offer spatial tracking, our origin point (0,0,0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
+ For platforms that do not offer spatial tracking, our origin point (0, 0, 0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
For platforms that do offer spatial tracking, our origin point depends very much on the system. For OpenVR, our origin point is usually the center of the tracking space, on the ground. For other platforms, it's often the location of the tracking camera.
This method allows you to center your tracker on the location of the HMD. It will take the current location of the HMD and use that to adjust all your tracking data; in essence, realigning the real world to your player's current position in the game world.
For this method to produce usable results, tracking information must be available. This often takes a few frames after starting your game.
- You should call this method after a few seconds have passed. For instance, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
+ You should call this method after a few seconds have passed. For example, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
</description>
</method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface" />
<param index="0" name="name" type="String" />
<description>
- Finds an interface by its [param name]. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
+ Finds an interface by its [param name]. For example, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
</description>
</method>
<method name="get_hmd_transform">
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index 9d685b9cd0..e3938fb5d5 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -114,12 +114,17 @@
<return type="Vector4" />
<param index="0" name="right" type="Vector4" />
<description>
+ Multiplies each component of the [Vector4] by the given [float].
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Multiplies each component of the [Vector4i] by the given [float]. Returns a [Vector4].
+ [codeblock]
+ print(0.9 * Vector4i(10, 15, 20, -10)) # Prints "(9, 13.5, 18, -9)"
+ [/codeblock]
</description>
</operator>
<operator name="operator *">
@@ -140,12 +145,20 @@
<return type="float" />
<param index="0" name="right" type="float" />
<description>
+ Raises a [float] to a power of a [float].
+ [codeblock]
+ print(39.0625**0.25) # 2.5
+ [/codeblock]
</description>
</operator>
<operator name="operator **">
<return type="float" />
<param index="0" name="right" type="int" />
<description>
+ Raises a [float] to a power of an [int]. The result is a [float].
+ [codeblock]
+ print(0.9**3) # 0.729
+ [/codeblock]
</description>
</operator>
<operator name="operator +">
@@ -194,7 +207,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is less than the right one.
+ Returns [code]true[/code] if the left float is less than the right one.
</description>
</operator>
<operator name="operator &lt;">
@@ -208,7 +221,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left integer is less than or equal to the right one.
+ Returns [code]true[/code] if the left float is less than or equal to the right one.
</description>
</operator>
<operator name="operator &lt;=">
@@ -237,7 +250,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is greater than the right one.
+ Returns [code]true[/code] if the left float is greater than the right one.
</description>
</operator>
<operator name="operator &gt;">
@@ -251,7 +264,7 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] the left float is greater than or equal to the right one.
+ Returns [code]true[/code] if the left float is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;=">
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 78e2e7d18f..65ab5d4656 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -72,14 +72,14 @@
<return type="bool" />
<param index="0" name="right" type="float" />
<description>
- Returns [code]true[/code] if operands are different from each other.
+ Returns [code]true[/code] if this [int] is not equivalent to the given [float].
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] if operands are different from each other.
+ Returns [code]true[/code] if the integers are not equal.
</description>
</operator>
<operator name="operator %">
@@ -161,12 +161,14 @@
<return type="Vector4" />
<param index="0" name="right" type="Vector4" />
<description>
+ Multiplies each component of the [Vector4] by the given [int].
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
<param index="0" name="right" type="Vector4i" />
<description>
+ Multiplies each component of the [Vector4i] by the given [int].
</description>
</operator>
<operator name="operator *">
@@ -187,19 +189,20 @@
<return type="float" />
<param index="0" name="right" type="float" />
<description>
+ Raises an [int] to a power of a [float]. The result is a [float].
+ [codeblock]
+ print(8**0.25) # 1.68179283050743
+ [/codeblock]
</description>
</operator>
<operator name="operator **">
<return type="int" />
<param index="0" name="right" type="int" />
<description>
- </description>
- </operator>
- <operator name="operator +">
- <return type="String" />
- <param index="0" name="right" type="String" />
- <description>
- Adds Unicode character with code [int] to the [String].
+ Raises an [int] to a power of a [int].
+ [codeblock]
+ print(5**5) # 3125
+ [/codeblock]
</description>
</operator>
<operator name="operator +">
@@ -262,7 +265,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is less than the right one.
+ Returns [code]true[/code] if the left integer is less than the right one.
</description>
</operator>
<operator name="operator &lt;&lt;">
@@ -287,7 +290,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is less than or equal to the right one.
+ Returns [code]true[/code] if the left integer is less than or equal to the right one.
</description>
</operator>
<operator name="operator ==">
@@ -315,7 +318,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is greater than the right one.
+ Returns [code]true[/code] if the left integer is greater than the right one.
</description>
</operator>
<operator name="operator &gt;=">
@@ -329,7 +332,7 @@
<return type="bool" />
<param index="0" name="right" type="int" />
<description>
- Returns [code]true[/code] the left integer is greater than or equal to the right one.
+ Returns [code]true[/code] if the left integer is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;&gt;">
diff --git a/drivers/SCsub b/drivers/SCsub
index dd81fc645c..6cfcb1d18c 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -24,6 +24,7 @@ SConscript("winmidi/SCsub")
# Graphics drivers
if env["vulkan"]:
+ SConscript("spirv-reflect/SCsub")
SConscript("vulkan/SCsub")
if env["opengl3"]:
SConscript("gl_context/SCsub")
@@ -31,7 +32,6 @@ if env["opengl3"]:
# Core dependencies
SConscript("png/SCsub")
-SConscript("spirv-reflect/SCsub")
env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index d2a0076023..011758e5f7 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -37,85 +37,135 @@
#include <errno.h>
-static int get_message_size(uint8_t message) {
- switch (message & 0xF0) {
- case 0x80: // note off
- case 0x90: // note on
- case 0xA0: // aftertouch
- case 0xB0: // continuous controller
- case 0xE0: // pitch bend
- case 0xF2: // song position pointer
- return 3;
-
- case 0xC0: // patch change
- case 0xD0: // channel pressure
- case 0xF1: // time code quarter frame
- case 0xF3: // song select
+MIDIDriverALSAMidi::MessageCategory MIDIDriverALSAMidi::msg_category(uint8_t msg_part) {
+ if (msg_part >= 0xf8) {
+ return MessageCategory::RealTime;
+ } else if (msg_part >= 0xf0) {
+ // System Exclusive begin/end are specified as System Common Category messages,
+ // but we separate them here and give them their own categories as their
+ // behaviour is significantly different.
+ if (msg_part == 0xf0) {
+ return MessageCategory::SysExBegin;
+ } else if (msg_part == 0xf7) {
+ return MessageCategory::SysExEnd;
+ }
+ return MessageCategory::SystemCommon;
+ } else if (msg_part >= 0x80) {
+ return MessageCategory::Voice;
+ }
+ return MessageCategory::Data;
+}
+
+size_t MIDIDriverALSAMidi::msg_expected_data(uint8_t status_byte) {
+ if (msg_category(status_byte) == MessageCategory::Voice) {
+ // Voice messages have a channel number in the status byte, mask it out.
+ status_byte &= 0xf0;
+ }
+
+ switch (status_byte) {
+ case 0x80: // Note Off
+ case 0x90: // Note On
+ case 0xA0: // Polyphonic Key Pressure (Aftertouch)
+ case 0xB0: // Control Change (CC)
+ case 0xE0: // Pitch Bend Change
+ case 0xF2: // Song Position Pointer
return 2;
- case 0xF0: // SysEx start
- case 0xF4: // reserved
- case 0xF5: // reserved
- case 0xF6: // tune request
- case 0xF7: // SysEx end
- case 0xF8: // timing clock
- case 0xF9: // reserved
- case 0xFA: // start
- case 0xFB: // continue
- case 0xFC: // stop
- case 0xFD: // reserved
- case 0xFE: // active sensing
- case 0xFF: // reset
+ case 0xC0: // Program Change
+ case 0xD0: // Channel Pressure (Aftertouch)
+ case 0xF1: // MIDI Time Code Quarter Frame
+ case 0xF3: // Song Select
return 1;
}
- return 256;
+ return 0;
+}
+
+void MIDIDriverALSAMidi::InputConnection::parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver,
+ uint64_t timestamp) {
+ switch (msg_category(byte)) {
+ case MessageCategory::RealTime:
+ // Real-Time messages are single byte messages that can
+ // occur at any point.
+ // We pass them straight through.
+ driver.receive_input_packet(timestamp, &byte, 1);
+ break;
+
+ case MessageCategory::Data:
+ // We don't currently forward System Exclusive messages so skip their data.
+ // Collect any expected data for other message types.
+ if (!skipping_sys_ex && expected_data > received_data) {
+ buffer[received_data + 1] = byte;
+ received_data++;
+
+ // Forward a complete message and reset relevant state.
+ if (received_data == expected_data) {
+ driver.receive_input_packet(timestamp, buffer, received_data + 1);
+ received_data = 0;
+
+ if (msg_category(buffer[0]) != MessageCategory::Voice) {
+ // Voice Category messages can be sent with "running status".
+ // This means they don't resend the status byte until it changes.
+ // For other categories, we reset expected data, to require a new status byte.
+ expected_data = 0;
+ }
+ }
+ }
+ break;
+
+ case MessageCategory::SysExBegin:
+ buffer[0] = byte;
+ skipping_sys_ex = true;
+ break;
+
+ case MessageCategory::SysExEnd:
+ expected_data = 0;
+ skipping_sys_ex = false;
+ break;
+
+ case MessageCategory::Voice:
+ case MessageCategory::SystemCommon:
+ buffer[0] = byte;
+ received_data = 0;
+ expected_data = msg_expected_data(byte);
+ skipping_sys_ex = false;
+ if (expected_data == 0) {
+ driver.receive_input_packet(timestamp, &byte, 1);
+ }
+ break;
+ }
+}
+
+int MIDIDriverALSAMidi::InputConnection::read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp) {
+ int ret;
+ do {
+ uint8_t byte = 0;
+ ret = snd_rawmidi_read(rawmidi_ptr, &byte, 1);
+
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
+ }
+ } else {
+ parse_byte(byte, driver, timestamp);
+ }
+ } while (ret > 0);
+
+ return ret;
}
void MIDIDriverALSAMidi::thread_func(void *p_udata) {
MIDIDriverALSAMidi *md = static_cast<MIDIDriverALSAMidi *>(p_udata);
uint64_t timestamp = 0;
- uint8_t buffer[256];
- int expected_size = 255;
- int bytes = 0;
while (!md->exit_thread.is_set()) {
- int ret;
-
md->lock();
- for (int i = 0; i < md->connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = md->connected_inputs[i];
- do {
- uint8_t byte = 0;
- ret = snd_rawmidi_read(midi_in, &byte, 1);
- if (ret < 0) {
- if (ret != -EAGAIN) {
- ERR_PRINT("snd_rawmidi_read error: " + String(snd_strerror(ret)));
- }
- } else {
- if (byte & 0x80) {
- // Flush previous packet if there is any
- if (bytes) {
- md->receive_input_packet(timestamp, buffer, bytes);
- bytes = 0;
- }
- expected_size = get_message_size(byte);
- // After a SysEx start, all bytes are data until a SysEx end, so
- // we're going to end the command at the SES, and let the common
- // driver ignore the following data bytes.
- }
+ InputConnection *connections = md->connected_inputs.ptrw();
+ size_t connection_count = md->connected_inputs.size();
- if (bytes < 256) {
- buffer[bytes++] = byte;
- // If we know the size of the current packet receive it if it reached the expected size
- if (bytes >= expected_size) {
- md->receive_input_packet(timestamp, buffer, bytes);
- bytes = 0;
- }
- }
- }
- } while (ret > 0);
+ for (size_t i = 0; i < connection_count; i++) {
+ connections[i].read_in(*md, timestamp);
}
md->unlock();
@@ -139,7 +189,7 @@ Error MIDIDriverALSAMidi::open() {
snd_rawmidi_t *midi_in;
int ret = snd_rawmidi_open(&midi_in, nullptr, name, SND_RAWMIDI_NONBLOCK);
if (ret >= 0) {
- connected_inputs.insert(i++, midi_in);
+ connected_inputs.insert(i++, InputConnection(midi_in));
}
}
@@ -160,7 +210,7 @@ void MIDIDriverALSAMidi::close() {
thread.wait_to_finish();
for (int i = 0; i < connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_close(midi_in);
}
connected_inputs.clear();
@@ -179,7 +229,7 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() {
lock();
for (int i = 0; i < connected_inputs.size(); i++) {
- snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_t *midi_in = connected_inputs[i].rawmidi_ptr;
snd_rawmidi_info_t *info;
snd_rawmidi_info_malloc(&info);
diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h
index ac3530b1b2..9265dede3d 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/midi_driver_alsamidi.h
@@ -46,12 +46,48 @@ class MIDIDriverALSAMidi : public MIDIDriver {
Thread thread;
Mutex mutex;
- Vector<snd_rawmidi_t *> connected_inputs;
+ class InputConnection {
+ public:
+ InputConnection() = default;
+ InputConnection(snd_rawmidi_t *midi_in) :
+ rawmidi_ptr{ midi_in } {}
+
+ // Read in and parse available data, forwarding any complete messages through the driver.
+ int read_in(MIDIDriverALSAMidi &driver, uint64_t timestamp);
+
+ snd_rawmidi_t *rawmidi_ptr = nullptr;
+
+ private:
+ static const size_t MSG_BUFFER_SIZE = 3;
+ uint8_t buffer[MSG_BUFFER_SIZE] = { 0 };
+ size_t expected_data = 0;
+ size_t received_data = 0;
+ bool skipping_sys_ex = false;
+ void parse_byte(uint8_t byte, MIDIDriverALSAMidi &driver, uint64_t timestamp);
+ };
+
+ Vector<InputConnection> connected_inputs;
SafeFlag exit_thread;
static void thread_func(void *p_udata);
+ enum class MessageCategory {
+ Data,
+ Voice,
+ SysExBegin,
+ SystemCommon, // excluding System Exclusive Begin/End
+ SysExEnd,
+ RealTime,
+ };
+
+ // If the passed byte is a status byte, return the associated message category,
+ // else return MessageCategory::Data.
+ static MessageCategory msg_category(uint8_t msg_part);
+
+ // Return the number of data bytes expected for the provided status byte.
+ static size_t msg_expected_data(uint8_t status_byte);
+
void lock() const;
void unlock() const;
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index de0181f887..3acbcf6b53 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -114,19 +114,15 @@ CopyEffects::~CopyEffects() {
copy.shader.version_free(copy.shader_version);
}
-void CopyEffects::copy_to_rect(const Rect2i &p_rect) {
+void CopyEffects::copy_to_rect(const Rect2 &p_rect) {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y, copy.shader_version, CopyShaderGLES3::MODE_COPY_SECTION);
- glBindVertexArray(quad_array);
- glDrawArrays(GL_TRIANGLES, 0, 6);
- glBindVertexArray(0);
+ draw_screen_quad();
}
void CopyEffects::copy_screen() {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_DEFAULT);
- glBindVertexArray(screen_triangle_array);
- glDrawArrays(GL_TRIANGLES, 0, 3);
- glBindVertexArray(0);
+ draw_screen_triangle();
}
void CopyEffects::bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region) {
@@ -158,8 +154,19 @@ void CopyEffects::set_color(const Color &p_color, const Rect2i &p_region) {
copy.shader.version_bind_shader(copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
copy.shader.version_set_uniform(CopyShaderGLES3::COPY_SECTION, p_region.position.x, p_region.position.y, p_region.size.x, p_region.size.y, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
copy.shader.version_set_uniform(CopyShaderGLES3::COLOR_IN, p_color, copy.shader_version, CopyShaderGLES3::MODE_SIMPLE_COLOR);
+ draw_screen_quad();
+}
+
+void CopyEffects::draw_screen_triangle() {
+ glBindVertexArray(screen_triangle_array);
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+ glBindVertexArray(0);
+}
+
+void CopyEffects::draw_screen_quad() {
glBindVertexArray(quad_array);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
+
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/effects/copy_effects.h b/drivers/gles3/effects/copy_effects.h
index b863e76579..a817c3f0dc 100644
--- a/drivers/gles3/effects/copy_effects.h
+++ b/drivers/gles3/effects/copy_effects.h
@@ -61,10 +61,12 @@ public:
~CopyEffects();
// These functions assume that a framebuffer and texture are bound already. They only manage the shader, uniforms, and vertex array.
- void copy_to_rect(const Rect2i &p_rect);
+ void copy_to_rect(const Rect2 &p_rect);
void copy_screen();
void bilinear_blur(GLuint p_source_texture, int p_mipmap_count, const Rect2i &p_region);
void set_color(const Color &p_color, const Rect2i &p_region);
+ void draw_screen_triangle();
+ void draw_screen_quad();
};
} //namespace GLES3
diff --git a/drivers/gles3/environment/fog.cpp b/drivers/gles3/environment/fog.cpp
index 02d88f6871..8587c5f9f7 100644
--- a/drivers/gles3/environment/fog.cpp
+++ b/drivers/gles3/environment/fog.cpp
@@ -43,7 +43,7 @@ RID Fog::fog_volume_allocate() {
void Fog::fog_volume_initialize(RID p_rid) {
}
-void Fog::fog_free(RID p_rid) {
+void Fog::fog_volume_free(RID p_rid) {
}
void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
diff --git a/drivers/gles3/environment/fog.h b/drivers/gles3/environment/fog.h
index 350eb459cf..fcde7399dd 100644
--- a/drivers/gles3/environment/fog.h
+++ b/drivers/gles3/environment/fog.h
@@ -46,7 +46,7 @@ public:
virtual RID fog_volume_allocate() override;
virtual void fog_volume_initialize(RID p_rid) override;
- virtual void fog_free(RID p_rid) override;
+ virtual void fog_volume_free(RID p_rid) override;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 0ffede0992..29252c8677 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -36,26 +36,13 @@
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
+#include "core/math/geometry_2d.h"
#include "servers/rendering/rendering_server_default.h"
#include "storage/config.h"
#include "storage/material_storage.h"
#include "storage/mesh_storage.h"
#include "storage/texture_storage.h"
-#ifndef GLES_OVER_GL
-#define glClearDepth glClearDepthf
-#endif
-
-//static const GLenum gl_primitive[] = {
-// GL_POINTS,
-// GL_LINES,
-// GL_LINE_STRIP,
-// GL_LINE_LOOP,
-// GL_TRIANGLES,
-// GL_TRIANGLE_STRIP,
-// GL_TRIANGLE_FAN
-//};
-
void RasterizerCanvasGLES3::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.columns[0][0];
p_mat4[1] = p_transform.columns[0][1];
@@ -115,7 +102,7 @@ void RasterizerCanvasGLES3::_update_transform_to_mat4(const Transform3D &p_trans
p_mat4[15] = 1;
}
-void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
+void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
@@ -124,9 +111,198 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
// Clear out any state that may have been left from the 3D pass.
reset_canvas();
- // TODO: Setup Directional Lights
+ if (state.canvas_instance_data_buffers[state.current_buffer].fence != GLsync()) {
+ GLint syncStatus;
+ glGetSynciv(state.canvas_instance_data_buffers[state.current_buffer].fence, GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
+ if (syncStatus == GL_UNSIGNALED) {
+ // If older than 2 frames, wait for sync OpenGL can have up to 3 frames in flight, any more and we need to sync anyway.
+ if (state.canvas_instance_data_buffers[state.current_buffer].last_frame_used < RSG::rasterizer->get_frame_number() - 2) {
+#ifndef WEB_ENABLED
+ // On web, we do nothing as the glSubBufferData will force a sync anyway and WebGL does not like waiting.
+ glClientWaitSync(state.canvas_instance_data_buffers[state.current_buffer].fence, 0, 100000000); // wait for up to 100ms
+#endif
+ } else {
+ // Used in last frame or frame before that. OpenGL can get up to two frames behind, so these buffers may still be in use
+ // Allocate a new buffer and use that.
+ _allocate_instance_data_buffer();
+ }
+ } else {
+ // Already finished all rendering commands, we can use it.
+ state.canvas_instance_data_buffers[state.current_buffer].last_frame_used = RSG::rasterizer->get_frame_number();
+ glDeleteSync(state.canvas_instance_data_buffers[state.current_buffer].fence);
+ state.canvas_instance_data_buffers[state.current_buffer].fence = GLsync();
+ }
+ }
+
+ //setup directional lights if exist
+
+ uint32_t light_count = 0;
+ uint32_t directional_light_count = 0;
+ {
+ Light *l = p_directional_light_list;
+ uint32_t index = 0;
+
+ while (l) {
+ if (index == data.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
+
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
+
+ Vector2 canvas_light_dir = l->xform_cache.columns[1].normalized();
+
+ state.light_uniforms[index].position[0] = -canvas_light_dir.x;
+ state.light_uniforms[index].position[1] = -canvas_light_dir.y;
+
+ _update_transform_2d_to_mat2x4(clight->shadow.directional_xform, state.light_uniforms[index].shadow_matrix);
+
+ state.light_uniforms[index].height = l->height; //0..1 here
+
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (state.shadow_fb != 0) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth);
+ state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far;
+ state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ state.light_uniforms[index].shadow_z_far_inv = 1.0;
+ state.light_uniforms[index].shadow_y_ofs = 0;
+ }
+
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+
+ if (clight->shadow.enabled) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ light_count = index;
+ directional_light_count = light_count;
+ state.using_directional_lights = directional_light_count > 0;
+ }
+
+ //setup lights if exist
+
+ {
+ Light *l = p_light_list;
+ uint32_t index = light_count;
+
+ while (l) {
+ if (index == data.max_lights_per_render) {
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ continue;
+ }
+
+ CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal);
+ if (!clight) { //unused or invalid texture
+ l->render_index_cache = -1;
+ l = l->next_ptr;
+ ERR_CONTINUE(!clight);
+ }
+ Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
+
+ Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
+ state.light_uniforms[index].position[0] = canvas_light_pos.x;
+ state.light_uniforms[index].position[1] = canvas_light_pos.y;
- // TODO: Setup lights
+ _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
+ _update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
+
+ state.light_uniforms[index].height = l->height * (p_canvas_transform.columns[0].length() + p_canvas_transform.columns[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
+ for (int i = 0; i < 4; i++) {
+ state.light_uniforms[index].shadow_color[i] = uint8_t(CLAMP(int32_t(l->shadow_color[i] * 255.0), 0, 255));
+ state.light_uniforms[index].color[i] = l->color[i];
+ }
+
+ state.light_uniforms[index].color[3] = l->energy; //use alpha for energy, so base color can go separate
+
+ if (state.shadow_fb != 0) {
+ state.light_uniforms[index].shadow_pixel_size = (1.0 / state.shadow_texture_size) * (1.0 + l->shadow_smooth);
+ state.light_uniforms[index].shadow_z_far_inv = 1.0 / clight->shadow.z_far;
+ state.light_uniforms[index].shadow_y_ofs = clight->shadow.y_offset;
+ } else {
+ state.light_uniforms[index].shadow_pixel_size = 1.0;
+ state.light_uniforms[index].shadow_z_far_inv = 1.0;
+ state.light_uniforms[index].shadow_y_ofs = 0;
+ }
+
+ state.light_uniforms[index].flags = l->blend_mode << LIGHT_FLAGS_BLEND_SHIFT;
+ state.light_uniforms[index].flags |= l->shadow_filter << LIGHT_FLAGS_FILTER_SHIFT;
+
+ if (clight->shadow.enabled) {
+ state.light_uniforms[index].flags |= LIGHT_FLAGS_HAS_SHADOW;
+ }
+
+ if (clight->texture.is_valid()) {
+ Rect2 atlas_rect = GLES3::TextureStorage::get_singleton()->texture_atlas_get_texture_rect(clight->texture);
+ state.light_uniforms[index].atlas_rect[0] = atlas_rect.position.x;
+ state.light_uniforms[index].atlas_rect[1] = atlas_rect.position.y;
+ state.light_uniforms[index].atlas_rect[2] = atlas_rect.size.width;
+ state.light_uniforms[index].atlas_rect[3] = atlas_rect.size.height;
+
+ } else {
+ state.light_uniforms[index].atlas_rect[0] = 0;
+ state.light_uniforms[index].atlas_rect[1] = 0;
+ state.light_uniforms[index].atlas_rect[2] = 0;
+ state.light_uniforms[index].atlas_rect[3] = 0;
+ }
+
+ l->render_index_cache = index;
+
+ index++;
+ l = l->next_ptr;
+ }
+
+ light_count = index;
+ }
+
+ if (light_count > 0) {
+ glBindBufferBase(GL_UNIFORM_BUFFER, LIGHT_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].light_ubo);
+
+#ifdef WEB_ENABLED
+ glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightUniform) * light_count, state.light_uniforms);
+#else
+ // On Desktop and mobile we map the memory without synchronizing for maximum speed.
+ void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(LightUniform) * light_count, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(ubo, state.light_uniforms, sizeof(LightUniform) * light_count);
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+#endif
+
+ GLuint texture_atlas = texture_storage->texture_atlas_get_texture();
+ if (texture_atlas == 0) {
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ texture_atlas = tex->tex_id;
+ }
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas);
+ GLuint shadow_tex = state.shadow_texture;
+ if (shadow_tex == 0) {
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
+ shadow_tex = tex->tex_id;
+ }
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
+ glBindTexture(GL_TEXTURE_2D, shadow_tex);
+ }
{
//update canvas state uniform buffer
@@ -155,13 +331,10 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.screen_pixel_size[0] = 1.0 / render_target_size.x;
state_buffer.screen_pixel_size[1] = 1.0 / render_target_size.y;
- // TODO: temporary, this should be set at the top of this function
- glViewport(0, 0, render_target_size.x, render_target_size.y);
-
state_buffer.time = state.time;
state_buffer.use_pixel_snap = p_snap_2d_vertices_to_pixel;
- state_buffer.directional_light_count = 0; //directional_light_count;
+ state_buffer.directional_light_count = directional_light_count;
Vector2 canvas_scale = p_canvas_transform.get_scale();
@@ -180,7 +353,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
state_buffer.sdf_to_tex[3] = -sdf_tex_rect.position.y / sdf_tex_rect.size.height;
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
- glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].state_ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
GLuint global_buffer = material_storage->global_shader_parameters_get_uniform_buffer();
@@ -189,11 +363,17 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 5);
+ glBindTexture(GL_TEXTURE_2D, texture_storage->render_target_get_sdf_texture(p_to_render_target));
+
{
state.default_filter = p_default_filter;
state.default_repeat = p_default_repeat;
}
+ Size2 render_target_size = texture_storage->render_target_get_size(p_to_render_target);
+ glViewport(0, 0, render_target_size.x, render_target_size.y);
+
r_sdf_used = false;
int item_count = 0;
bool backbuffer_cleared = false;
@@ -207,6 +387,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
Item *ci = p_item_list;
Item *canvas_group_owner = nullptr;
+ uint32_t starting_index = 0;
+
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
backbuffer_copy = true;
@@ -245,14 +427,15 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
if (ci->canvas_group_owner != nullptr) {
if (canvas_group_owner == nullptr) {
// Canvas group begins here, render until before this item
-
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
item_count = 0;
- Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
-
- if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
+ if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
+ Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
+ if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ items[item_count++] = ci->canvas_group_owner;
+ }
} else if (!backbuffer_cleared) {
texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
backbuffer_cleared = true;
@@ -271,7 +454,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
if (ci == canvas_group_owner) {
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, true);
item_count = 0;
if (ci->canvas_group->blur_mipmaps) {
@@ -279,12 +462,14 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
}
canvas_group_owner = nullptr;
+ // Backbuffer is dirty now and needs to be re-cleared if another CanvasGroup needs it.
+ backbuffer_cleared = false;
}
if (backbuffer_copy) {
//render anything pending, including clearing if no items
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
item_count = 0;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
@@ -306,7 +491,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
items[item_count++] = ci;
if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
- _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
+ _render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, starting_index, false);
//then reset
item_count = 0;
}
@@ -318,153 +503,132 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
RenderingServerDefault::redraw_request();
}
+ state.canvas_instance_data_buffers[state.current_buffer].fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
// Clear out state used in 2D pass
reset_canvas();
+ state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
}
-void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer) {
- GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer) {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
- Item *current_clip = nullptr;
-
- Transform2D canvas_transform_inverse = p_canvas_transform_inverse;
canvas_begin(p_to_render_target, p_to_backbuffer);
- RID prev_material;
+ if (p_item_count <= 0) {
+ // Nothing to draw, just call canvas_begin() to clear the render target and return.
+ return;
+ }
+
uint32_t index = 0;
- GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
- Color last_blend_color;
- GLES3::CanvasShaderData *shader_data_cache = nullptr;
+ Item *current_clip = nullptr;
+
+ // Record Batches.
+ // First item always forms its own batch.
+ bool batch_broken = false;
+ _new_batch(batch_broken, index);
- state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
- state.current_tex_ptr = nullptr;
- state.current_normal = RID();
- state.current_specular = RID();
- state.canvas_texscreen_used = false;
- state.current_shader_version = state.canvas_shader_default_version;
+ // Override the start position and index as we want to start from where we finished off last time.
+ state.canvas_instance_batches[state.current_batch_index].start = r_last_index * sizeof(InstanceData);
+ index = 0;
+ _align_instance_data_buffer(index);
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
- if (current_clip != ci->final_clip_owner) {
- _render_batch(index);
-
+ if (ci->final_clip_owner != state.canvas_instance_batches[state.current_batch_index].clip) {
+ _new_batch(batch_broken, index);
+ state.canvas_instance_batches[state.current_batch_index].clip = ci->final_clip_owner;
current_clip = ci->final_clip_owner;
- //setup clip
- if (current_clip) {
- glEnable(GL_SCISSOR_TEST);
- glScissor(current_clip->final_clip_rect.position.x, current_clip->final_clip_rect.position.y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
- } else {
- glDisable(GL_SCISSOR_TEST);
- }
}
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
-
- if (material.is_null() && ci->canvas_group != nullptr) {
- material = default_canvas_group_material;
+ if (ci->canvas_group != nullptr) {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ if (!p_to_backbuffer) {
+ material = default_clip_children_material;
+ }
+ } else {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_ONLY) {
+ material = default_clip_children_material;
+ } else {
+ material = default_canvas_group_material;
+ }
+ }
}
- if (material != prev_material) {
- _render_batch(index);
+ GLES3::CanvasShaderData *shader_data_cache = nullptr;
+ if (material != state.canvas_instance_batches[state.current_batch_index].material) {
+ _new_batch(batch_broken, index);
+
GLES3::CanvasMaterialData *material_data = nullptr;
if (material.is_valid()) {
material_data = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
}
+ shader_data_cache = nullptr;
if (material_data) {
if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) {
- // Bind uniform buffer and textures
- material_data->bind_uniforms();
- state.current_shader_version = material_data->shader_data->version;
shader_data_cache = material_data->shader_data;
- } else {
- state.current_shader_version = state.canvas_shader_default_version;
- shader_data_cache = nullptr;
}
- } else {
- state.current_shader_version = state.canvas_shader_default_version;
- shader_data_cache = nullptr;
}
- prev_material = material;
+
+ state.canvas_instance_batches[state.current_batch_index].material = material;
+ state.canvas_instance_batches[state.current_batch_index].material_data = material_data;
}
GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
- _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index, blend_mode, last_blend_mode, last_blend_color);
- }
- // Render last command
- _render_batch(index);
-}
-
-void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color) {
- // Used by Polygon and Mesh.
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
-
- RS::CanvasItemTextureFilter current_filter = state.default_filter;
- RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
-
- if (p_item->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
- current_filter = p_item->texture_filter;
+ _record_item_commands(ci, p_canvas_transform_inverse, current_clip, blend_mode, p_lights, index, batch_broken);
}
- if (p_item->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
- current_repeat = p_item->texture_repeat;
+ if (r_last_index >= index) {
+ // Nothing to render, just return.
+ state.current_batch_index = 0;
+ state.canvas_instance_batches.clear();
+ return;
}
- Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
- Transform2D draw_transform; // Used by transform command
-
- Color base_color = p_item->final_modulate;
-
- uint32_t base_flags = 0;
-
- bool reclip = false;
-
- bool skipping = false;
-
- const Item::Command *c = p_item->commands;
- while (c) {
- if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
- c = c->next;
- continue;
- }
-
- if (c->type != Item::Command::TYPE_MESH) {
- // For Meshes, this gets updated below.
- _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
- }
-
- for (int i = 0; i < 4; i++) {
- state.instance_data_array[r_index].modulation[i] = 0.0;
- state.instance_data_array[r_index].ninepatch_margins[i] = 0.0;
- state.instance_data_array[r_index].src_rect[i] = 0.0;
- state.instance_data_array[r_index].dst_rect[i] = 0.0;
- state.instance_data_array[r_index].lights[i] = uint32_t(0);
- }
- state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
+ // Copy over all data needed for rendering.
+ glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[state.current_buffer].ubo);
+#ifdef WEB_ENABLED
+ glBufferSubData(GL_UNIFORM_BUFFER, r_last_index * sizeof(InstanceData), sizeof(InstanceData) * index, state.instance_data_array);
+#else
+ // On Desktop and mobile we map the memory without synchronizing for maximum speed.
+ void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, r_last_index * sizeof(InstanceData), index * sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(ubo, state.instance_data_array, index * sizeof(InstanceData));
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+#endif
- state.instance_data_array[r_index].pad[0] = 0.0;
- state.instance_data_array[r_index].pad[1] = 0.0;
+ glDisable(GL_SCISSOR_TEST);
+ current_clip = nullptr;
- state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+ GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
- GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
- Color blend_color;
+ state.current_tex = RID();
- if (c->type == Item::Command::TYPE_RECT) {
- const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
- if (rect->flags & CANVAS_RECT_LCD) {
- blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD;
- blend_color = rect->modulate;
+ for (uint32_t i = 0; i <= state.current_batch_index; i++) {
+ //setup clip
+ if (current_clip != state.canvas_instance_batches[i].clip) {
+ current_clip = state.canvas_instance_batches[i].clip;
+ if (current_clip) {
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(current_clip->final_clip_rect.position.x, current_clip->final_clip_rect.position.y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
+ } else {
+ glDisable(GL_SCISSOR_TEST);
}
}
- if (r_last_blend_mode != blend_mode || r_last_blend_color != blend_color) {
- _render_batch(r_index);
+ GLES3::CanvasMaterialData *material_data = state.canvas_instance_batches[i].material_data;
+ CanvasShaderGLES3::ShaderVariant variant = state.canvas_instance_batches[i].shader_variant;
+ uint64_t specialization = 0;
+ specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
+ specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
+ _bind_material(material_data, variant, specialization);
- if (r_last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+ GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
+
+ if (last_blend_mode != blend_mode) {
+ if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
// re-enable it
glEnable(GL_BLEND);
} else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
@@ -475,7 +639,6 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
switch (blend_mode) {
case GLES3::CanvasShaderData::BLEND_MODE_DISABLED: {
// Nothing to do here.
-
} break;
case GLES3::CanvasShaderData::BLEND_MODE_LCD: {
glBlendEquation(GL_FUNC_ADD);
@@ -484,6 +647,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} else {
glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
}
+ Color blend_color = state.canvas_instance_batches[state.current_batch_index].blend_color;
glBlendColor(blend_color.r, blend_color.g, blend_color.b, blend_color.a);
} break;
@@ -532,32 +696,149 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} break;
}
- r_last_blend_mode = blend_mode;
- r_last_blend_color = blend_color;
+ last_blend_mode = blend_mode;
+ }
+
+ _render_batch(p_lights, i);
+ }
+
+ state.current_batch_index = 0;
+ state.canvas_instance_batches.clear();
+ r_last_index += index;
+}
+
+void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken) {
+ RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
+
+ if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
+ _new_batch(r_batch_broken, r_index);
+
+ state.canvas_instance_batches[state.current_batch_index].filter = texture_filter;
+ }
+
+ RenderingServer::CanvasItemTextureRepeat texture_repeat = p_item->texture_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT ? state.default_repeat : p_item->texture_repeat;
+
+ if (texture_repeat != state.canvas_instance_batches[state.current_batch_index].repeat) {
+ _new_batch(r_batch_broken, r_index);
+
+ state.canvas_instance_batches[state.current_batch_index].repeat = texture_repeat;
+ }
+
+ Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
+ Transform2D draw_transform; // Used by transform command
+
+ Color base_color = p_item->final_modulate;
+ uint32_t base_flags = 0;
+ Size2 texpixel_size;
+
+ bool reclip = false;
+
+ bool skipping = false;
+
+ // TODO: consider making lights a per-batch property and then baking light operations in the shader for better performance.
+ uint32_t lights[4] = { 0, 0, 0, 0 };
+
+ uint16_t light_count = 0;
+
+ {
+ Light *light = p_lights;
+
+ while (light) {
+ if (light->render_index_cache >= 0 && p_item->light_mask & light->item_mask && p_item->z_final >= light->z_min && p_item->z_final <= light->z_max && p_item->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) {
+ uint32_t light_index = light->render_index_cache;
+ lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+
+ light_count++;
+
+ if (light_count == data.max_lights_per_item) {
+ break;
+ }
+ }
+ light = light->next_ptr;
+ }
+
+ base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ }
+
+ bool lights_disabled = light_count == 0 && !state.using_directional_lights;
+
+ if (lights_disabled != state.canvas_instance_batches[state.current_batch_index].lights_disabled) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].lights_disabled = lights_disabled;
+ }
+
+ const Item::Command *c = p_item->commands;
+ while (c) {
+ if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
+ c = c->next;
+ continue;
+ }
+
+ if (c->type != Item::Command::TYPE_MESH) {
+ // For Meshes, this gets updated below.
+ _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ }
+
+ // Zero out most fields.
+ for (int i = 0; i < 4; i++) {
+ state.instance_data_array[r_index].modulation[i] = 0.0;
+ state.instance_data_array[r_index].ninepatch_margins[i] = 0.0;
+ state.instance_data_array[r_index].src_rect[i] = 0.0;
+ state.instance_data_array[r_index].dst_rect[i] = 0.0;
+ state.instance_data_array[r_index].lights[i] = uint32_t(0);
+ }
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
+
+ state.instance_data_array[r_index].pad[0] = 0.0;
+ state.instance_data_array[r_index].pad[1] = 0.0;
+
+ state.instance_data_array[r_index].lights[0] = lights[0];
+ state.instance_data_array[r_index].lights[1] = lights[1];
+ state.instance_data_array[r_index].lights[2] = lights[2];
+ state.instance_data_array[r_index].lights[3] = lights[3];
+
+ state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+
+ Color blend_color;
+ if (c->type == Item::Command::TYPE_RECT) {
+ const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+ if (rect->flags & CANVAS_RECT_LCD) {
+ p_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD;
+ blend_color = rect->modulate * base_color;
+ }
+ }
+
+ if (p_blend_mode != state.canvas_instance_batches[state.current_batch_index].blend_mode || blend_color != state.canvas_instance_batches[state.current_batch_index].blend_color) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].blend_mode = p_blend_mode;
+ state.canvas_instance_batches[state.current_batch_index].blend_color = blend_color;
}
switch (c->type) {
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
- if (rect->flags & CANVAS_RECT_TILE) {
- current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
+ if (rect->flags & CANVAS_RECT_TILE && state.canvas_instance_batches[state.current_batch_index].repeat != RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED;
}
- if (rect->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_RECT) {
- _render_batch(r_index);
-
- state.current_primitive_points = 0;
- state.current_command = Item::Command::TYPE_RECT;
+ if (rect->texture != state.canvas_instance_batches[state.current_batch_index].tex || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_RECT) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = rect->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_RECT;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_QUAD;
}
- _bind_canvas_texture(rect->texture, current_filter, current_repeat, r_index);
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_QUAD);
+
+ _prepare_canvas_texture(rect->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
Rect2 src_rect;
Rect2 dst_rect;
if (rect->texture != RID()) {
- src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * state.current_pixel_size, rect->source.size * state.current_pixel_size) : Rect2(0, 0, 1, 1);
+ src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
@@ -625,36 +906,32 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[2] = dst_rect.size.width;
state.instance_data_array[r_index].dst_rect[3] = dst_rect.size.height;
- r_index++;
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
case Item::Command::TYPE_NINEPATCH: {
const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
- if (np->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_NINEPATCH) {
- _render_batch(r_index);
-
- state.current_primitive_points = 0;
- state.current_command = Item::Command::TYPE_NINEPATCH;
+ if (np->texture != state.canvas_instance_batches[state.current_batch_index].tex || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_NINEPATCH) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = np->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_NINEPATCH;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_NINEPATCH;
}
- //bind textures
- _bind_canvas_texture(np->texture, current_filter, current_repeat, r_index);
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_NINEPATCH);
+ _prepare_canvas_texture(np->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
Rect2 src_rect;
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
if (np->texture == RID()) {
- state.current_pixel_size = Size2(1, 1);
+ texpixel_size = Size2(1, 1);
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
- src_rect = Rect2(np->source.position.x * state.current_pixel_size.width, np->source.position.y * state.current_pixel_size.height, np->source.size.x * state.current_pixel_size.width, np->source.size.y * state.current_pixel_size.height);
+ src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
state.instance_data_array[r_index].color_texture_pixel_size[0] = 1.0 / np->source.size.width;
state.instance_data_array[r_index].color_texture_pixel_size[1] = 1.0 / np->source.size.height;
@@ -690,32 +967,26 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[2] = np->margin[SIDE_RIGHT];
state.instance_data_array[r_index].ninepatch_margins[3] = np->margin[SIDE_BOTTOM];
- r_index++;
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
- }
+ _add_to_batch(r_index, r_batch_broken);
// Restore if overridden.
- state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = texpixel_size.x;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = texpixel_size.y;
} break;
case Item::Command::TYPE_POLYGON: {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
- PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
- ERR_CONTINUE(!pb);
+ // Polygon's can't be batched, so always create a new batch
+ _new_batch(r_batch_broken, r_index);
- if (polygon->texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_POLYGON) {
- _render_batch(r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = polygon->texture;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_POLYGON;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
- state.current_primitive_points = 0;
- state.current_command = Item::Command::TYPE_POLYGON;
- }
- _bind_canvas_texture(polygon->texture, current_filter, current_repeat, r_index);
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
+ _prepare_canvas_texture(polygon->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
- state.current_primitive = polygon->primitive;
state.instance_data_array[r_index].modulation[0] = base_color.r;
state.instance_data_array[r_index].modulation[1] = base_color.g;
state.instance_data_array[r_index].modulation[2] = base_color.b;
@@ -727,39 +998,20 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
- _bind_instance_data_buffer(1);
- glBindVertexArray(pb->vertex_array);
-
- if (pb->color_disabled) {
- glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a);
- }
-
- if (pb->index_buffer != 0) {
- glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
- } else {
- glDrawArrays(prim[polygon->primitive], 0, pb->count);
- }
- glBindVertexArray(0);
- state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
- state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
-
- if (pb->color_disabled) {
- // Reset so this doesn't pollute other draw calls.
- glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
case Item::Command::TYPE_PRIMITIVE: {
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
- if (state.current_primitive_points != primitive->point_count || state.current_command != Item::Command::TYPE_PRIMITIVE) {
- _render_batch(r_index);
- state.current_primitive_points = primitive->point_count;
- state.current_command = Item::Command::TYPE_PRIMITIVE;
+ if (primitive->point_count != state.canvas_instance_batches[state.current_batch_index].primitive_points || state.canvas_instance_batches[state.current_batch_index].command_type != Item::Command::TYPE_PRIMITIVE) {
+ _new_batch(r_batch_broken, r_index);
+ state.canvas_instance_batches[state.current_batch_index].tex = RID();
+ state.canvas_instance_batches[state.current_batch_index].primitive_points = primitive->point_count;
+ state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_PRIMITIVE;
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_PRIMITIVE;
}
- _bind_canvas_texture(RID(), current_filter, current_repeat, r_index);
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_PRIMITIVE);
for (uint32_t j = 0; j < MIN(3u, primitive->point_count); j++) {
state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j].x;
@@ -770,97 +1022,61 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
state.instance_data_array[r_index].colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- r_index++;
+
+ _add_to_batch(r_index, r_batch_broken);
+
if (primitive->point_count == 4) {
- // Reset base data
+ // Reset base data.
_update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
- state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+ state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
for (uint32_t j = 0; j < 3; j++) {
- //second half of triangle
- state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j + 1].x;
- state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j + 1].y;
- state.instance_data_array[r_index].uvs[j * 2 + 0] = primitive->uvs[j + 1].x;
- state.instance_data_array[r_index].uvs[j * 2 + 1] = primitive->uvs[j + 1].y;
- Color col = primitive->colors[j + 1] * base_color;
+ int offset = j == 0 ? 0 : 1;
+ // Second triangle in the quad. Uses vertices 0, 2, 3.
+ state.instance_data_array[r_index].points[j * 2 + 0] = primitive->points[j + offset].x;
+ state.instance_data_array[r_index].points[j * 2 + 1] = primitive->points[j + offset].y;
+ state.instance_data_array[r_index].uvs[j * 2 + 0] = primitive->uvs[j + offset].x;
+ state.instance_data_array[r_index].uvs[j * 2 + 1] = primitive->uvs[j + offset].y;
+ Color col = primitive->colors[j + offset] * base_color;
state.instance_data_array[r_index].colors[j * 2 + 0] = (uint32_t(Math::make_half_float(col.g)) << 16) | Math::make_half_float(col.r);
state.instance_data_array[r_index].colors[j * 2 + 1] = (uint32_t(Math::make_half_float(col.a)) << 16) | Math::make_half_float(col.b);
}
- r_index++;
- }
- if (r_index >= state.max_instances_per_batch - 1) {
- _render_batch(r_index);
+
+ _add_to_batch(r_index, r_batch_broken);
}
} break;
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
- GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
- RID mesh;
- RID mesh_instance;
- RID texture;
- Color modulate(1, 1, 1, 1);
- uint32_t instance_count = 1;
- GLuint multimesh_buffer = 0;
- uint32_t multimesh_stride = 0;
- uint32_t multimesh_color_offset = 0;
- bool multimesh_uses_color = false;
- bool multimesh_uses_custom_data = false;
+ // Mesh's can't be batched, so always create a new batch
+ _new_batch(r_batch_broken, r_index);
+ Color modulate(1, 1, 1, 1);
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
- mesh = m->mesh;
- mesh_instance = m->mesh_instance;
- texture = m->texture;
- modulate = m->modulate;
+ state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
_update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, state.instance_data_array[r_index].world);
+ modulate = m->modulate;
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
- RID multimesh = mm->multimesh;
- mesh = mesh_storage->multimesh_get_mesh(multimesh);
- texture = mm->texture;
-
- if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
- break;
- }
-
- instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
-
- if (instance_count == 0) {
- break;
+ state.canvas_instance_batches[state.current_batch_index].tex = mm->texture;
+ uint32_t instance_count = GLES3::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(mm->multimesh);
+ if (instance_count > 1) {
+ state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
}
-
- multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
- multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
- multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
- multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
- multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
- }
-
- // TODO: implement particles here
-
- if (mesh.is_null()) {
- break;
+ } else if (c->type == Item::Command::TYPE_PARTICLES) {
+ WARN_PRINT_ONCE("Particles not supported yet, sorry :(");
}
- if (texture != state.current_tex || state.current_primitive_points != 0 || state.current_command != Item::Command::TYPE_PRIMITIVE) {
- _render_batch(r_index);
- state.current_primitive_points = 0;
- state.current_command = c->type;
- }
-
- _bind_canvas_texture(texture, current_filter, current_repeat, r_index);
- if (instance_count == 1) {
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
- } else {
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_INSTANCED);
- }
+ state.canvas_instance_batches[state.current_batch_index].command = c;
+ state.canvas_instance_batches[state.current_batch_index].command_type = c->type;
- uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
+ _prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
state.instance_data_array[r_index].modulation[0] = base_color.r * modulate.r;
state.instance_data_array[r_index].modulation[1] = base_color.g * modulate.g;
@@ -872,75 +1088,9 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[j] = 0;
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
- _bind_instance_data_buffer(1);
- for (uint32_t j = 0; j < surf_count; j++) {
- void *surface = mesh_storage->mesh_get_surface(mesh, j);
-
- RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
- ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
-
- GLuint vertex_array_gl = 0;
- GLuint index_array_gl = 0;
-
- uint32_t input_mask = 0; // 2D meshes always use the same vertex format
- if (mesh_instance.is_valid()) {
- mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl);
- } else {
- mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array_gl);
- }
-
- index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
- bool use_index_buffer = false;
- glBindVertexArray(vertex_array_gl);
- if (index_array_gl != 0) {
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
- use_index_buffer = true;
- }
-
- if (instance_count > 1) {
- // Bind instance buffers.
- glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
- glEnableVertexAttribArray(1);
- glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
- glVertexAttribDivisor(1, 1);
- glEnableVertexAttribArray(2);
- glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
- glVertexAttribDivisor(2, 1);
-
- if (multimesh_uses_color || multimesh_uses_custom_data) {
- glEnableVertexAttribArray(5);
- glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float)));
- glVertexAttribDivisor(5, 1);
- }
- }
-
- GLenum primitive_gl = prim[int(primitive)];
- if (instance_count == 1) {
- if (use_index_buffer) {
- glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0);
- } else {
- glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface));
- }
- } else {
- if (use_index_buffer) {
- glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
- } else {
- glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
- }
- }
-
- state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
- state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- if (instance_count > 1) {
- glDisableVertexAttribArray(5);
- glDisableVertexAttribArray(6);
- glDisableVertexAttribArray(7);
- glDisableVertexAttribArray(8);
- }
- }
+ _add_to_batch(r_index, r_batch_broken);
} break;
+
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
draw_transform = transform->xform;
@@ -950,30 +1100,30 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
const Item::CommandClipIgnore *ci = static_cast<const Item::CommandClipIgnore *>(c);
if (current_clip) {
if (ci->ignore != reclip) {
+ _new_batch(r_batch_broken, r_index);
if (ci->ignore) {
- glDisable(GL_SCISSOR_TEST);
+ state.canvas_instance_batches[state.current_batch_index].clip = nullptr;
reclip = true;
} else {
- // Scissor area is already set
- glEnable(GL_SCISSOR_TEST);
+ state.canvas_instance_batches[state.current_batch_index].clip = current_clip;
reclip = false;
}
}
}
} break;
+
case Item::Command::TYPE_ANIMATION_SLICE: {
- /*
const Item::CommandAnimationSlice *as = static_cast<const Item::CommandAnimationSlice *>(c);
- double current_time = RendererCompositorRD::singleton->get_total_time();
+ double current_time = RSG::rasterizer->get_total_time();
double local_time = Math::fposmod(current_time - as->offset, as->animation_length);
skipping = !(local_time >= as->slice_begin && local_time < as->slice_end);
RenderingServerDefault::redraw_request(); // animation visible means redraw request
- */
} break;
}
c = c->next;
+ r_batch_broken = false;
}
if (current_clip && reclip) {
@@ -982,101 +1132,795 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
}
}
-void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
- if (r_index > 0) {
- _bind_instance_data_buffer(r_index);
- glBindVertexArray(data.canvas_quad_array);
- if (state.current_primitive_points == 0) {
- glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, r_index);
- } else {
- static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLES };
- glDrawArraysInstanced(prim[state.current_primitive_points], 0, state.current_primitive_points, r_index);
- }
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
+ ERR_FAIL_COND(!state.canvas_instance_batches[state.current_batch_index].command);
- state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
- //copy the new data into the base of the batch
- for (int i = 0; i < 4; i++) {
- state.instance_data_array[0].modulation[i] = state.instance_data_array[r_index].modulation[i];
- state.instance_data_array[0].ninepatch_margins[i] = state.instance_data_array[r_index].ninepatch_margins[i];
- state.instance_data_array[0].src_rect[i] = state.instance_data_array[r_index].src_rect[i];
- state.instance_data_array[0].dst_rect[i] = state.instance_data_array[r_index].dst_rect[i];
- state.instance_data_array[0].lights[i] = state.instance_data_array[r_index].lights[i];
- }
- state.instance_data_array[0].flags = state.instance_data_array[r_index].flags;
- state.instance_data_array[0].color_texture_pixel_size[0] = state.instance_data_array[r_index].color_texture_pixel_size[0];
- state.instance_data_array[0].color_texture_pixel_size[1] = state.instance_data_array[r_index].color_texture_pixel_size[1];
-
- state.instance_data_array[0].pad[0] = state.instance_data_array[r_index].pad[0];
- state.instance_data_array[0].pad[1] = state.instance_data_array[r_index].pad[1];
- for (int i = 0; i < 6; i++) {
- state.instance_data_array[0].world[i] = state.instance_data_array[r_index].world[i];
- }
+ // Used by Polygon and Mesh.
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+
+ _bind_canvas_texture(state.canvas_instance_batches[p_index].tex, state.canvas_instance_batches[p_index].filter, state.canvas_instance_batches[p_index].repeat);
- r_index = 0;
+ // Bind the region of the UBO used by this batch.
+ // If region exceeds the boundary of the UBO, just ignore.
+ uint32_t range_bytes = data.max_instances_per_batch * sizeof(InstanceData);
+ if (state.canvas_instance_batches[p_index].start >= (data.max_instances_per_ubo - 1) * sizeof(InstanceData)) {
+ return;
+ } else if (state.canvas_instance_batches[p_index].start >= (data.max_instances_per_ubo - data.max_instances_per_batch) * sizeof(InstanceData)) {
+ // If we have less than a full batch at the end, we can just draw it anyway.
+ // OpenGL will complain about the UBO being smaller than expected, but it should render fine.
+ range_bytes = (data.max_instances_per_ubo - 1) * sizeof(InstanceData) - state.canvas_instance_batches[p_index].start;
+ }
+
+ uint32_t range_start = state.canvas_instance_batches[p_index].start;
+ glBindBufferRange(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer].ubo, range_start, range_bytes);
+
+ switch (state.canvas_instance_batches[p_index].command_type) {
+ case Item::Command::TYPE_RECT:
+ case Item::Command::TYPE_NINEPATCH: {
+ glBindVertexArray(data.indexed_quad_array);
+ glDrawElements(GL_TRIANGLES, state.canvas_instance_batches[p_index].instance_count * 6, GL_UNSIGNED_INT, 0);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ glBindVertexArray(0);
+
+ } break;
+
+ case Item::Command::TYPE_POLYGON: {
+ const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(state.canvas_instance_batches[p_index].command);
+
+ PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
+ ERR_FAIL_COND(!pb);
+
+ glBindVertexArray(pb->vertex_array);
+
+ if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
+ glVertexAttrib4f(RS::ARRAY_COLOR, pb->color.r, pb->color.g, pb->color.b, pb->color.a);
+ }
+
+ if (pb->index_buffer != 0) {
+ glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
+ } else {
+ glDrawArrays(prim[polygon->primitive], 0, pb->count);
+ }
+ glBindVertexArray(0);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ if (pb->color_disabled && pb->color != Color(1.0, 1.0, 1.0, 1.0)) {
+ // Reset so this doesn't pollute other draw calls.
+ glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
+ }
+ } break;
+
+ case Item::Command::TYPE_PRIMITIVE: {
+ glBindVertexArray(data.canvas_quad_array);
+ const GLenum primitive[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLES };
+ int instance_count = state.canvas_instance_batches[p_index].instance_count;
+ if (instance_count > 1) {
+ glDrawArraysInstanced(primitive[state.canvas_instance_batches[p_index].primitive_points], 0, state.canvas_instance_batches[p_index].primitive_points, instance_count);
+ } else {
+ glDrawArrays(primitive[state.canvas_instance_batches[p_index].primitive_points], 0, state.canvas_instance_batches[p_index].primitive_points);
+ }
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ } break;
+
+ case Item::Command::TYPE_MESH:
+ case Item::Command::TYPE_MULTIMESH:
+ case Item::Command::TYPE_PARTICLES: {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ RID mesh;
+ RID mesh_instance;
+ RID texture;
+ uint32_t instance_count = 1;
+ GLuint multimesh_buffer = 0;
+ uint32_t multimesh_stride = 0;
+ uint32_t multimesh_color_offset = 0;
+ bool multimesh_uses_color = false;
+ bool multimesh_uses_custom_data = false;
+
+ if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MESH) {
+ const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(state.canvas_instance_batches[p_index].command);
+ mesh = m->mesh;
+ mesh_instance = m->mesh_instance;
+ } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_MULTIMESH) {
+ const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(state.canvas_instance_batches[p_index].command);
+ RID multimesh = mm->multimesh;
+ mesh = mesh_storage->multimesh_get_mesh(multimesh);
+
+ if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+ break;
+ }
+
+ instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
+
+ if (instance_count == 0) {
+ break;
+ }
+
+ multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
+ multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
+ multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
+ multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
+ multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
+ } else if (state.canvas_instance_batches[p_index].command_type == Item::Command::TYPE_PARTICLES) {
+ // Do nothing for now.
+ }
+
+ ERR_FAIL_COND(mesh.is_null());
+
+ uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
+
+ for (uint32_t j = 0; j < surf_count; j++) {
+ void *surface = mesh_storage->mesh_get_surface(mesh, j);
+
+ RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
+ ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
+
+ GLuint vertex_array_gl = 0;
+ GLuint index_array_gl = 0;
+
+ uint32_t input_mask = 0; // 2D meshes always use the same vertex format
+ if (mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl);
+ } else {
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array_gl);
+ }
+
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
+ bool use_index_buffer = false;
+ glBindVertexArray(vertex_array_gl);
+ if (index_array_gl != 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ use_index_buffer = true;
+ }
+
+ if (instance_count > 1) {
+ // Bind instance buffers.
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(1, 1);
+ glEnableVertexAttribArray(2);
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(2, 1);
+
+ if (multimesh_uses_color || multimesh_uses_custom_data) {
+ glEnableVertexAttribArray(5);
+ glVertexAttribIPointer(5, 4, GL_UNSIGNED_INT, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float)));
+ glVertexAttribDivisor(5, 1);
+ }
+ }
+
+ GLenum primitive_gl = prim[int(primitive)];
+ if (instance_count == 1) {
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface));
+ }
+ } else if (instance_count > 1) {
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
+ }
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ if (instance_count > 1) {
+ glDisableVertexAttribArray(5);
+ glDisableVertexAttribArray(6);
+ glDisableVertexAttribArray(7);
+ glDisableVertexAttribArray(8);
+ }
+ }
+
+ } break;
+ case Item::Command::TYPE_TRANSFORM:
+ case Item::Command::TYPE_CLIP_IGNORE:
+ case Item::Command::TYPE_ANIMATION_SLICE: {
+ // Can ignore these as they only impact batch creation.
+ } break;
}
}
-void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) {
- if (p_max_index == 0) {
+void RasterizerCanvasGLES3::_add_to_batch(uint32_t &r_index, bool &r_batch_broken) {
+ if (r_index >= data.max_instances_per_ubo - 1) {
+ WARN_PRINT_ONCE("Trying to draw too many items. Please increase maximum number of items in the project settings 'rendering/gl_compatibility/item_buffer_size'");
return;
}
- // If the previous operation is not done yet, allocate a new buffer
- if (state.fences[state.current_buffer] != GLsync()) {
- GLint syncStatus;
- glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
- if (syncStatus == GL_UNSIGNALED) {
- _allocate_instance_data_buffer();
+
+ if (state.canvas_instance_batches[state.current_batch_index].instance_count >= data.max_instances_per_batch) {
+ _new_batch(r_batch_broken, r_index);
+ }
+
+ state.canvas_instance_batches[state.current_batch_index].instance_count++;
+ r_index++;
+}
+
+void RasterizerCanvasGLES3::_new_batch(bool &r_batch_broken, uint32_t &r_index) {
+ if (state.canvas_instance_batches.size() == 0) {
+ state.canvas_instance_batches.push_back(Batch());
+ return;
+ }
+
+ if (r_batch_broken || state.canvas_instance_batches[state.current_batch_index].instance_count == 0) {
+ return;
+ }
+
+ r_batch_broken = true;
+
+ // Copy the properties of the current batch, we will manually update the things that changed.
+ Batch new_batch = state.canvas_instance_batches[state.current_batch_index];
+ new_batch.instance_count = 0;
+ new_batch.start = state.canvas_instance_batches[state.current_batch_index].start + state.canvas_instance_batches[state.current_batch_index].instance_count * sizeof(InstanceData);
+
+ state.current_batch_index++;
+ state.canvas_instance_batches.push_back(new_batch);
+ _align_instance_data_buffer(r_index);
+}
+
+void RasterizerCanvasGLES3::_bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization) {
+ if (p_material_data) {
+ if (p_material_data->shader_data->version.is_valid() && p_material_data->shader_data->valid) {
+ // Bind uniform buffer and textures
+ p_material_data->bind_uniforms();
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(p_material_data->shader_data->version, p_variant, p_specialization);
} else {
- glDeleteSync(state.fences[state.current_buffer]);
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
}
+ } else {
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, p_variant, p_specialization);
}
-
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef WEB_ENABLED
- //WebGL 2.0 does not support mapping buffers, so use slow glBufferSubData instead
- glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, state.instance_data_array);
-#else
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * p_max_index);
- glUnmapBuffer(GL_UNIFORM_BUFFER);
-#endif
}
RID RasterizerCanvasGLES3::light_create() {
- return RID();
+ CanvasLight canvas_light;
+ return canvas_light_owner.make_rid(canvas_light);
}
void RasterizerCanvasGLES3::light_set_texture(RID p_rid, RID p_texture) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl);
+ if (cl->texture == p_texture) {
+ return;
+ }
+ if (cl->texture.is_valid()) {
+ texture_storage->texture_remove_from_texture_atlas(cl->texture);
+ }
+ cl->texture = p_texture;
+
+ if (cl->texture.is_valid()) {
+ texture_storage->texture_add_to_texture_atlas(cl->texture);
+ }
}
void RasterizerCanvasGLES3::light_set_use_shadow(RID p_rid, bool p_enable) {
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl);
+
+ cl->shadow.enabled = p_enable;
}
void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
+
+ cl->shadow.z_far = p_far;
+ cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(data.max_lights_per_render * 2);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+ glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDisable(GL_BLEND);
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+ glClearColor(p_far, p_far, p_far, 1.0);
+ glClearDepth(1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glCullFace(GL_BACK);
+ glDisable(GL_CULL_FACE);
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
+ shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+
+ for (int i = 0; i < 4; i++) {
+ glViewport((state.shadow_texture_size / 4) * i, p_shadow_index * 2, (state.shadow_texture_size / 4), 2);
+
+ Projection projection;
+ {
+ real_t fov = 90;
+ real_t nearp = p_near;
+ real_t farp = p_far;
+ real_t aspect = 1.0;
+
+ real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5));
+ real_t ymin = -ymax;
+ real_t xmin = ymin * aspect;
+ real_t xmax = ymax * aspect;
+
+ projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
+ }
+
+ Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
+
+ projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
+
+ static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, directions[i].x, directions[i].y, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, p_far, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = p_light_xform * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ if (co->cull_mode != cull_mode) {
+ if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
+ }
+ cull_mode = co->cull_mode;
+ }
+
+ glBindVertexArray(co->vertex_array);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+
+ instance = instance->next;
+ }
+ }
+
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
}
void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND(!cl->shadow.enabled);
+
+ _update_shadow_atlas();
+
+ Vector2 light_dir = p_light_xform.columns[1].normalized();
+
+ Vector2 center = p_clip_rect.get_center();
+
+ float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center));
+
+ Vector2 from_pos = center - light_dir * (to_edge_distance + p_cull_distance);
+ float distance = to_edge_distance * 2.0 + p_cull_distance;
+ float half_size = p_clip_rect.size.length() * 0.5; //shadow length, must keep this no matter the angle
+
+ cl->shadow.z_far = distance;
+ cl->shadow.y_offset = float(p_shadow_index * 2 + 1) / float(data.max_lights_per_render * 2);
+
+ Transform2D to_light_xform;
+
+ to_light_xform[2] = from_pos;
+ to_light_xform[1] = light_dir;
+ to_light_xform[0] = -light_dir.orthogonal();
+
+ to_light_xform.invert();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+ glViewport(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDisable(GL_BLEND);
+
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
+ glClearColor(1.0, 1.0, 1.0, 1.0);
+ glClearDepth(1.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glCullFace(GL_BACK);
+ glDisable(GL_CULL_FACE);
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = config->float_texture_supported ? CanvasOcclusionShaderGLES3::MODE_SHADOW : CanvasOcclusionShaderGLES3::MODE_SHADOW_RGBA;
+ shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+
+ Projection projection;
+ projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance);
+ projection = projection * Projection(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse());
+
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, projection, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 1.0, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, distance, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!co || co->vertex_array == 0 || !(p_light_mask & instance->light_mask)) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = to_light_xform * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ if (co->cull_mode != cull_mode) {
+ if (co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(co->cull_mode == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? GL_FRONT : GL_BACK);
+ }
+ cull_mode = co->cull_mode;
+ }
+
+ glBindVertexArray(co->vertex_array);
+ glDrawElements(GL_TRIANGLES, 3 * co->line_point_count, GL_UNSIGNED_SHORT, 0);
+
+ instance = instance->next;
+ }
+
+ Transform2D to_shadow;
+ to_shadow.columns[0].x = 1.0 / -(half_size * 2.0);
+ to_shadow.columns[2].x = 0.5;
+
+ cl->shadow.directional_xform = to_shadow * to_light_xform;
+
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_CULL_FACE);
+}
+
+void RasterizerCanvasGLES3::_update_shadow_atlas() {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+
+ if (state.shadow_fb == 0) {
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenFramebuffers(1, &state.shadow_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, state.shadow_fb);
+
+ glGenRenderbuffers(1, &state.shadow_depth_buffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, state.shadow_depth_buffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, state.shadow_texture_size, data.max_lights_per_render * 2);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, state.shadow_depth_buffer);
+
+ glGenTextures(1, &state.shadow_texture);
+ glBindTexture(GL_TEXTURE_2D, state.shadow_texture);
+ if (config->float_texture_supported) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RED, GL_FLOAT, nullptr);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, state.shadow_texture_size, data.max_lights_per_render * 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ }
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, state.shadow_texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &state.shadow_fb);
+ glDeleteTextures(1, &state.shadow_texture);
+ glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
+ state.shadow_fb = 0;
+ state.shadow_texture = 0;
+ state.shadow_depth_buffer = 0;
+ WARN_PRINT("Could not create CanvasItem shadow atlas, status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+ }
}
void RasterizerCanvasGLES3::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ GLuint fb = texture_storage->render_target_get_sdf_framebuffer(p_render_target);
+ Rect2i rect = texture_storage->render_target_get_sdf_rect(p_render_target);
+
+ Transform2D to_sdf;
+ to_sdf.columns[0] *= rect.size.width;
+ to_sdf.columns[1] *= rect.size.height;
+ to_sdf.columns[2] = rect.position;
+
+ Transform2D to_clip;
+ to_clip.columns[0] *= 2.0;
+ to_clip.columns[1] *= 2.0;
+ to_clip.columns[2] = -Vector2(1.0, 1.0);
+
+ to_clip = to_clip * to_sdf.affine_inverse();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ glViewport(0, 0, rect.size.width, rect.size.height);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_SCISSOR_TEST);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ CanvasOcclusionShaderGLES3::ShaderVariant variant = CanvasOcclusionShaderGLES3::MODE_SDF;
+ shadow_render.shader.version_bind_shader(shadow_render.shader_version, variant);
+
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::PROJECTION, Projection(), shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::DIRECTION, 0.0, 0.0, shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::Z_FAR, 0.0, shadow_render.shader_version, variant);
+
+ LightOccluderInstance *instance = p_occluders;
+
+ while (instance) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(instance->occluder);
+
+ if (!oc || oc->sdf_vertex_array == 0) {
+ instance = instance->next;
+ continue;
+ }
+
+ Transform2D modelview = to_clip * instance->xform_cache;
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW1, modelview.columns[0][0], modelview.columns[1][0], 0, modelview.columns[2][0], shadow_render.shader_version, variant);
+ shadow_render.shader.version_set_uniform(CanvasOcclusionShaderGLES3::MODELVIEW2, modelview.columns[0][1], modelview.columns[1][1], 0, modelview.columns[2][1], shadow_render.shader_version, variant);
+
+ glBindVertexArray(oc->sdf_vertex_array);
+ glDrawElements(oc->sdf_is_lines ? GL_LINES : GL_TRIANGLES, oc->sdf_index_count, GL_UNSIGNED_INT, 0);
+
+ instance = instance->next;
+ }
+
+ texture_storage->render_target_sdf_process(p_render_target); //done rendering, process it
+ glBindVertexArray(0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
RID RasterizerCanvasGLES3::occluder_polygon_create() {
- return RID();
+ OccluderPolygon occluder;
+
+ return occluder_polygon_owner.make_rid(occluder);
}
void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
+ ERR_FAIL_COND(!oc);
+
+ Vector<Vector2> lines;
+
+ if (p_points.size()) {
+ int lc = p_points.size() * 2;
+
+ lines.resize(lc - (p_closed ? 0 : 2));
+ {
+ Vector2 *w = lines.ptrw();
+ const Vector2 *r = p_points.ptr();
+
+ int max = lc / 2;
+ if (!p_closed) {
+ max--;
+ }
+ for (int i = 0; i < max; i++) {
+ Vector2 a = r[i];
+ Vector2 b = r[(i + 1) % (lc / 2)];
+ w[i * 2 + 0] = a;
+ w[i * 2 + 1] = b;
+ }
+ }
+ }
+
+ if (oc->line_point_count != lines.size() && oc->vertex_array != 0) {
+ glDeleteVertexArrays(1, &oc->vertex_array);
+ glDeleteBuffers(1, &oc->vertex_buffer);
+ glDeleteBuffers(1, &oc->index_buffer);
+
+ oc->vertex_array = 0;
+ oc->vertex_buffer = 0;
+ oc->index_buffer = 0;
+ }
+
+ if (lines.size()) {
+ Vector<uint8_t> geometry;
+ Vector<uint8_t> indices;
+ int lc = lines.size();
+
+ geometry.resize(lc * 6 * sizeof(float));
+ indices.resize(lc * 3 * sizeof(uint16_t));
+
+ {
+ uint8_t *vw = geometry.ptrw();
+ float *vwptr = reinterpret_cast<float *>(vw);
+ uint8_t *iw = indices.ptrw();
+ uint16_t *iwptr = (uint16_t *)iw;
+
+ const Vector2 *lr = lines.ptr();
+
+ const int POLY_HEIGHT = 16384;
+
+ for (int i = 0; i < lc / 2; i++) {
+ vwptr[i * 12 + 0] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 1] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 2] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 3] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 4] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 5] = POLY_HEIGHT;
+
+ vwptr[i * 12 + 6] = lr[i * 2 + 1].x;
+ vwptr[i * 12 + 7] = lr[i * 2 + 1].y;
+ vwptr[i * 12 + 8] = -POLY_HEIGHT;
+
+ vwptr[i * 12 + 9] = lr[i * 2 + 0].x;
+ vwptr[i * 12 + 10] = lr[i * 2 + 0].y;
+ vwptr[i * 12 + 11] = -POLY_HEIGHT;
+
+ iwptr[i * 6 + 0] = i * 4 + 0;
+ iwptr[i * 6 + 1] = i * 4 + 1;
+ iwptr[i * 6 + 2] = i * 4 + 2;
+
+ iwptr[i * 6 + 3] = i * 4 + 2;
+ iwptr[i * 6 + 4] = i * 4 + 3;
+ iwptr[i * 6 + 5] = i * 4 + 0;
+ }
+ }
+
+ if (oc->vertex_array == 0) {
+ oc->line_point_count = lc;
+ glGenVertexArrays(1, &oc->vertex_array);
+ glBindVertexArray(oc->vertex_array);
+ glGenBuffers(1, &oc->vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
+
+ glGenBuffers(1, &oc->index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ } else {
+ glBindVertexArray(oc->vertex_array);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(float), geometry.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * lc * sizeof(uint16_t), indices.ptr(), GL_STATIC_DRAW);
+ }
+ }
+
+ // sdf
+
+ Vector<int> sdf_indices;
+
+ if (p_points.size()) {
+ if (p_closed) {
+ sdf_indices = Geometry2D::triangulate_polygon(p_points);
+ oc->sdf_is_lines = false;
+ } else {
+ int max = p_points.size();
+ sdf_indices.resize(max * 2);
+
+ int *iw = sdf_indices.ptrw();
+ for (int i = 0; i < max; i++) {
+ iw[i * 2 + 0] = i;
+ iw[i * 2 + 1] = (i + 1) % max;
+ }
+ oc->sdf_is_lines = true;
+ }
+ }
+
+ if (oc->sdf_index_count != sdf_indices.size() && oc->sdf_point_count != p_points.size() && oc->sdf_vertex_array != 0) {
+ glDeleteVertexArrays(1, &oc->sdf_vertex_array);
+ glDeleteBuffers(1, &oc->sdf_vertex_buffer);
+ glDeleteBuffers(1, &oc->sdf_index_buffer);
+
+ oc->sdf_vertex_array = 0;
+ oc->sdf_vertex_buffer = 0;
+ oc->sdf_index_buffer = 0;
+
+ oc->sdf_index_count = sdf_indices.size();
+ oc->sdf_point_count = p_points.size();
+ }
+
+ if (sdf_indices.size()) {
+ if (oc->sdf_vertex_array == 0) {
+ oc->sdf_index_count = sdf_indices.size();
+ oc->sdf_point_count = p_points.size();
+ glGenVertexArrays(1, &oc->sdf_vertex_array);
+ glBindVertexArray(oc->sdf_vertex_array);
+ glGenBuffers(1, &oc->sdf_vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
+
+ glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), nullptr);
+
+ glGenBuffers(1, &oc->sdf_index_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ } else {
+ glBindBuffer(GL_ARRAY_BUFFER, oc->sdf_vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_points.size() * 2 * sizeof(float), p_points.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, oc->sdf_index_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sdf_indices.size() * sizeof(uint32_t), sdf_indices.to_byte_array().ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
}
void RasterizerCanvasGLES3::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
+ OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
+ ERR_FAIL_COND(!oc);
+ oc->cull_mode = p_mode;
}
void RasterizerCanvasGLES3::set_shadow_texture_size(int p_size) {
+ GLES3::Config *config = GLES3::Config::get_singleton();
+ p_size = nearest_power_of_2_templated(p_size);
+ if (p_size == state.shadow_texture_size) {
+ return;
+ }
+
+ if (p_size > config->max_texture_size) {
+ p_size = config->max_texture_size;
+ WARN_PRINT("Attempting to set CanvasItem shadow atlas size to " + itos(p_size) + " which is beyond limit of " + itos(config->max_texture_size) + "supported by hardware.");
+ }
+
+ state.shadow_texture_size = p_size;
}
bool RasterizerCanvasGLES3::free(RID p_rid) {
+ if (canvas_light_owner.owns(p_rid)) {
+ CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
+ ERR_FAIL_COND_V(!cl, false);
+ canvas_light_owner.free(p_rid);
+ } else if (occluder_polygon_owner.owns(p_rid)) {
+ occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false);
+ occluder_polygon_owner.free(p_rid);
+ } else {
+ return false;
+ }
+
return true;
}
@@ -1100,12 +1944,12 @@ void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backb
glBindTexture(GL_TEXTURE_2D, render_target->backbuffer);
}
- if (render_target->is_transparent) {
+ if (render_target->is_transparent || p_to_backbuffer) {
state.transparent_render_target = true;
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} else {
state.transparent_render_target = false;
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
}
if (render_target && render_target->clear_requested) {
@@ -1121,30 +1965,28 @@ void RasterizerCanvasGLES3::canvas_begin(RID p_to_render_target, bool p_to_backb
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
}
-void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index) {
+void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
if (p_texture == RID()) {
- p_texture = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ p_texture = default_canvas_texture;
}
- if (state.current_tex == p_texture) {
- return; //nothing to do, its the same
+ if (state.current_tex == p_texture && state.current_filter_mode == p_base_filter && state.current_repeat_mode == p_base_repeat) {
+ return;
}
+
state.current_tex = p_texture;
+ state.current_filter_mode = p_base_filter;
+ state.current_repeat_mode = p_base_repeat;
GLES3::CanvasTexture *ct = nullptr;
GLES3::Texture *t = texture_storage->get_texture(p_texture);
if (t) {
- //regular texture
- if (!t->canvas_texture) {
- t->canvas_texture = memnew(GLES3::CanvasTexture);
- t->canvas_texture->diffuse = p_texture;
- }
-
+ ERR_FAIL_COND(!t->canvas_texture);
ct = t->canvas_texture;
} else {
ct = texture_storage->get_canvas_texture(p_texture);
@@ -1152,7 +1994,7 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
if (!ct) {
// Invalid Texture RID.
- _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index);
+ _bind_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat);
return;
}
@@ -1165,20 +2007,12 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
if (!texture) {
- state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
- GLES3::Texture *tex = texture_storage->get_texture(state.current_tex);
- state.current_tex_ptr = tex;
- ct->size_cache = Size2i(tex->width, tex->height);
+ GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
-
- state.current_tex = p_texture;
- state.current_tex_ptr = texture;
- ct->size_cache = Size2i(texture->width, texture->height);
-
texture->gl_set_filter(filter);
texture->gl_set_repeat(repeat);
}
@@ -1186,45 +2020,78 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
if (!normal_map) {
- state.current_normal = RID();
- ct->use_normal_cache = false;
- glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 6);
+ glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_NORMAL));
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
-
} else {
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 6);
glBindTexture(GL_TEXTURE_2D, normal_map->tex_id);
- state.current_normal = ct->normal_map;
- ct->use_normal_cache = true;
- texture->gl_set_filter(filter);
- texture->gl_set_repeat(repeat);
+ normal_map->gl_set_filter(filter);
+ normal_map->gl_set_repeat(repeat);
}
GLES3::Texture *specular_map = texture_storage->get_texture(ct->specular);
if (!specular_map) {
- state.current_specular = RID();
- ct->use_specular_cache = false;
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
GLES3::Texture *tex = texture_storage->get_texture(texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE));
glBindTexture(GL_TEXTURE_2D, tex->tex_id);
} else {
glActiveTexture(GL_TEXTURE0 + config->max_texture_image_units - 7);
glBindTexture(GL_TEXTURE_2D, specular_map->tex_id);
- state.current_specular = ct->specular;
- ct->use_specular_cache = true;
- texture->gl_set_filter(filter);
- texture->gl_set_repeat(repeat);
+ specular_map->gl_set_filter(filter);
+ specular_map->gl_set_repeat(repeat);
+ }
+}
+
+void RasterizerCanvasGLES3::_prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size) {
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+
+ if (p_texture == RID()) {
+ p_texture = default_canvas_texture;
+ }
+
+ GLES3::CanvasTexture *ct = nullptr;
+
+ GLES3::Texture *t = texture_storage->get_texture(p_texture);
+
+ if (t) {
+ //regular texture
+ if (!t->canvas_texture) {
+ t->canvas_texture = memnew(GLES3::CanvasTexture);
+ t->canvas_texture->diffuse = p_texture;
+ }
+
+ ct = t->canvas_texture;
+ } else {
+ ct = texture_storage->get_canvas_texture(p_texture);
}
- if (ct->use_specular_cache) {
+ if (!ct) {
+ // Invalid Texture RID.
+ _prepare_canvas_texture(default_canvas_texture, p_base_filter, p_base_repeat, r_index, r_texpixel_size);
+ return;
+ }
+
+ GLES3::Texture *texture = texture_storage->get_texture(ct->diffuse);
+ Size2i size_cache;
+ if (!texture) {
+ ct->diffuse = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
+ GLES3::Texture *tex = texture_storage->get_texture(ct->diffuse);
+ size_cache = Size2i(tex->width, tex->height);
+ } else {
+ size_cache = Size2i(texture->width, texture->height);
+ }
+
+ GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
+
+ if (ct->specular_color.a < 0.999) {
state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
} else {
state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
- if (ct->use_normal_cache) {
+ if (normal_map) {
state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
} else {
state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_NORMAL_MAP_USED;
@@ -1235,11 +2102,11 @@ void RasterizerCanvasGLES3::_bind_canvas_texture(RID p_texture, RS::CanvasItemTe
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.g * 255.0, 0, 255)) << 8;
state.instance_data_array[r_index].specular_shininess |= uint32_t(CLAMP(ct->specular_color.r * 255.0, 0, 255));
- state.current_pixel_size.x = 1.0 / float(ct->size_cache.x);
- state.current_pixel_size.y = 1.0 / float(ct->size_cache.y);
+ r_texpixel_size.x = 1.0 / float(size_cache.x);
+ r_texpixel_size.y = 1.0 / float(size_cache.y);
- state.instance_data_array[r_index].color_texture_pixel_size[0] = state.current_pixel_size.x;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = state.current_pixel_size.y;
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = r_texpixel_size.x;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = r_texpixel_size.y;
}
void RasterizerCanvasGLES3::reset_canvas() {
@@ -1249,16 +2116,16 @@ void RasterizerCanvasGLES3::reset_canvas() {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 2);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0 + GLES3::Config::get_singleton()->max_texture_image_units - 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
-void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {
-}
-
-void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, Projection *p_xform_cache) {
-}
-
void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {
}
@@ -1289,7 +2156,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
polygon_buffer.resize(buffer_size * sizeof(float));
{
glBindBuffer(GL_ARRAY_BUFFER, pb.vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, stride * vertex_count * sizeof(float), nullptr, GL_STATIC_DRAW); // TODO may not be necessary
uint8_t *r = polygon_buffer.ptrw();
float *fptr = reinterpret_cast<float *>(r);
uint32_t *uptr = (uint32_t *)r;
@@ -1398,7 +2264,6 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
}
glGenBuffers(1, &pb.index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, pb.index_buffer);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, nullptr, GL_STATIC_DRAW); // TODO may not be necessary
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_indices.size() * 4, index_buffer.ptr(), GL_STATIC_DRAW);
pb.count = p_indices.size();
}
@@ -1431,20 +2296,53 @@ void RasterizerCanvasGLES3::free_polygon(PolygonID p_polygon) {
// Creates a new uniform buffer and uses it right away
// This expands the instance buffer continually
-// In theory allocations can reach as high as number_of_draw_calls * 3 frames
+// In theory allocations can reach as high as number of windows * 3 frames
// because OpenGL can start rendering subsequent frames before finishing the current one
void RasterizerCanvasGLES3::_allocate_instance_data_buffer() {
- GLuint new_buffer;
- glGenBuffers(1, &new_buffer);
- glBindBuffer(GL_UNIFORM_BUFFER, new_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * state.max_instances_per_batch, nullptr, GL_DYNAMIC_DRAW);
+ GLuint new_buffers[3];
+ glGenBuffers(3, new_buffers);
+ // Batch UBO.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[0]);
+ glBufferData(GL_UNIFORM_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ // Light uniform buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ // State buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+
state.current_buffer = (state.current_buffer + 1);
- state.canvas_instance_data_buffers.insert(state.current_buffer, new_buffer);
- state.fences.insert(state.current_buffer, GLsync());
+ DataBuffer db;
+ db.ubo = new_buffers[0];
+ db.light_ubo = new_buffers[1];
+ db.state_ubo = new_buffers[2];
+ db.last_frame_used = RSG::rasterizer->get_frame_number();
+ state.canvas_instance_data_buffers.insert(state.current_buffer, db);
state.current_buffer = state.current_buffer % state.canvas_instance_data_buffers.size();
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
+// Batch start positions need to be aligned to the device's GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT.
+// This needs to be called anytime a new batch is created.
+void RasterizerCanvasGLES3::_align_instance_data_buffer(uint32_t &r_index) {
+ if (GLES3::Config::get_singleton()->uniform_buffer_offset_alignment > int(sizeof(InstanceData))) {
+ uint32_t offset = state.canvas_instance_batches[state.current_batch_index].start % GLES3::Config::get_singleton()->uniform_buffer_offset_alignment;
+ if (offset > 0) {
+ // uniform_buffer_offset_alignment can be 4, 16, 32, or 256. Our instance batches are 128 bytes.
+ // Accordingly, this branch is only triggered if we are 128 bytes off.
+ uint32_t offset_bytes = GLES3::Config::get_singleton()->uniform_buffer_offset_alignment - offset;
+ state.canvas_instance_batches[state.current_batch_index].start += offset_bytes;
+ // Offset the instance array so it stays in sync with batch start points.
+ // This creates gaps in the instance buffer with wasted space, but we can't help it.
+ r_index += offset_bytes / sizeof(InstanceData);
+ if (r_index > 0) {
+ // In this case we need to copy over the basic data.
+ state.instance_data_array[r_index] = state.instance_data_array[r_index - 1];
+ }
+ }
+ }
+}
+
void RasterizerCanvasGLES3::set_time(double p_time) {
state.time = p_time;
}
@@ -1457,9 +2355,11 @@ RasterizerCanvasGLES3 *RasterizerCanvasGLES3::get_singleton() {
RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
singleton = this;
+ GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
+ polygon_buffers.last_id = 1;
// quad buffer
{
glGenBuffers(1, &data.canvas_quad_vertices);
@@ -1583,39 +2483,80 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
int uniform_max_size = config->max_uniform_buffer_size;
if (uniform_max_size < 65536) {
- state.max_lights_per_render = 64;
- state.max_instances_per_batch = 128;
+ data.max_lights_per_render = 64;
+ data.max_instances_per_batch = 128;
} else {
- state.max_lights_per_render = 256;
- state.max_instances_per_batch = 512;
+ data.max_lights_per_render = 256;
+ data.max_instances_per_batch = 512;
}
- // Reserve 64 Uniform Buffers for instance data
- state.canvas_instance_data_buffers.resize(64);
- state.fences.resize(64);
- glGenBuffers(64, state.canvas_instance_data_buffers.ptr());
- for (int i = 0; i < 64; i++) {
- state.fences[i] = GLsync();
- glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_instance_data_buffers[i]);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * state.max_instances_per_batch, nullptr, GL_DYNAMIC_DRAW);
+ // Reserve 3 Uniform Buffers for instance data Frame N, N+1 and N+2
+ data.max_instances_per_ubo = MAX(data.max_instances_per_batch, uint32_t(GLOBAL_GET("rendering/gl_compatibility/item_buffer_size")));
+ data.max_instance_buffer_size = data.max_instances_per_ubo * sizeof(InstanceData); // 16,384 instances * 128 bytes = 2,097,152 bytes = 2,048 kb
+ state.canvas_instance_data_buffers.resize(3);
+ state.canvas_instance_batches.reserve(200);
+
+ for (int i = 0; i < 3; i++) {
+ GLuint new_buffers[3];
+ glGenBuffers(3, new_buffers);
+ // Batch UBO.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[0]);
+ glBufferData(GL_UNIFORM_BUFFER, data.max_instance_buffer_size, nullptr, GL_STREAM_DRAW);
+ // Light uniform buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[1]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(LightUniform) * data.max_lights_per_render, nullptr, GL_STREAM_DRAW);
+ // State buffer.
+ glBindBuffer(GL_UNIFORM_BUFFER, new_buffers[2]);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
+ DataBuffer db;
+ db.ubo = new_buffers[0];
+ db.light_ubo = new_buffers[1];
+ db.state_ubo = new_buffers[2];
+ db.last_frame_used = 0;
+ db.fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ state.canvas_instance_data_buffers[i] = db;
}
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- state.instance_data_array = memnew_arr(InstanceData, state.max_instances_per_batch);
+ state.instance_data_array = memnew_arr(InstanceData, data.max_instances_per_ubo);
+ state.light_uniforms = memnew_arr(LightUniform, data.max_lights_per_render);
- glGenBuffers(1, &state.canvas_state_buffer);
- glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_state_buffer);
- glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), nullptr, GL_STREAM_DRAW);
- glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ {
+ const uint32_t no_of_instances = data.max_instances_per_batch;
+
+ glGenVertexArrays(1, &data.indexed_quad_array);
+ glBindVertexArray(data.indexed_quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices);
+
+ const uint32_t num_indices = 6;
+ const uint32_t quad_indices[num_indices] = { 0, 2, 1, 3, 2, 0 };
+
+ const uint32_t total_indices = no_of_instances * num_indices;
+ uint32_t *indices = new uint32_t[total_indices];
+ for (uint32_t i = 0; i < total_indices; i++) {
+ uint32_t quad = i / num_indices;
+ uint32_t quad_local = i % num_indices;
+ indices[i] = quad_indices[quad_local] + quad * num_indices;
+ }
+
+ glGenBuffers(1, &data.indexed_quad_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.indexed_quad_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * total_indices, indices, GL_STATIC_DRAW);
+ glBindVertexArray(0);
+ delete[] indices;
+ }
String global_defines;
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
- global_defines += "#define MAX_LIGHTS " + itos(state.max_instances_per_batch) + "\n";
- global_defines += "#define MAX_DRAW_DATA_INSTANCES " + itos(state.max_instances_per_batch) + "\n";
+ global_defines += "#define MAX_LIGHTS " + itos(data.max_lights_per_render) + "\n";
+ global_defines += "#define MAX_DRAW_DATA_INSTANCES " + itos(data.max_instances_per_batch) + "\n";
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.initialize(global_defines);
- state.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
+ data.canvas_shader_default_version = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_create();
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(data.canvas_shader_default_version, CanvasShaderGLES3::MODE_QUAD);
+
+ shadow_render.shader.initialize();
+ shadow_render.shader_version = shadow_render.shader.version_create();
{
default_canvas_group_shader = material_storage->shader_allocate();
@@ -1642,18 +2583,42 @@ void fragment() {
material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
}
- state.current_shader_version = state.canvas_shader_default_version;
+ {
+ default_clip_children_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(default_clip_children_shader);
+
+ material_storage->shader_set_code(default_clip_children_shader, R"(
+// Default clip children shader.
+
+shader_type canvas_item;
+
+void fragment() {
+ vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ COLOR.rgb = c.rgb;
+}
+)");
+ default_clip_children_material = material_storage->material_allocate();
+ material_storage->material_initialize(default_clip_children_material);
+
+ material_storage->material_set_shader(default_clip_children_material, default_clip_children_shader);
+ }
+
+ default_canvas_texture = texture_storage->canvas_texture_allocate();
+ texture_storage->canvas_texture_initialize(default_canvas_texture);
+
state.time = 0.0;
}
RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
- GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
-
- memdelete_arr(state.instance_data_array);
+ singleton = nullptr;
- GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version);
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ material_storage->shaders.canvas_shader.version_free(data.canvas_shader_default_version);
+ shadow_render.shader.version_free(shadow_render.shader_version);
material_storage->material_free(default_canvas_group_material);
material_storage->shader_free(default_canvas_group_shader);
+ material_storage->material_free(default_clip_children_material);
+ material_storage->shader_free(default_clip_children_shader);
singleton = nullptr;
glDeleteBuffers(1, &data.canvas_quad_vertices);
@@ -1661,6 +2626,19 @@ RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
glDeleteBuffers(1, &data.canvas_quad_vertices);
glDeleteVertexArrays(1, &data.canvas_quad_array);
+
+ GLES3::TextureStorage::get_singleton()->canvas_texture_free(default_canvas_texture);
+ memdelete_arr(state.instance_data_array);
+ memdelete_arr(state.light_uniforms);
+
+ if (state.shadow_fb != 0) {
+ glDeleteFramebuffers(1, &state.shadow_fb);
+ glDeleteTextures(1, &state.shadow_texture);
+ glDeleteRenderbuffers(1, &state.shadow_depth_buffer);
+ state.shadow_fb = 0;
+ state.shadow_texture = 0;
+ state.shadow_depth_buffer = 0;
+ }
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 372ac00493..d672d05e14 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -40,6 +40,7 @@
#include "storage/texture_storage.h"
#include "shaders/canvas.glsl.gen.h"
+#include "shaders/canvas_occlusion.glsl.gen.h"
class RasterizerSceneGLES3;
@@ -96,6 +97,63 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
DEFAULT_MAX_LIGHTS_PER_RENDER = 256,
};
+ /******************/
+ /**** LIGHTING ****/
+ /******************/
+
+ struct CanvasLight {
+ RID texture;
+ struct {
+ bool enabled = false;
+ float z_far;
+ float y_offset;
+ Transform2D directional_xform;
+ } shadow;
+ };
+
+ RID_Owner<CanvasLight> canvas_light_owner;
+
+ struct OccluderPolygon {
+ RS::CanvasOccluderPolygonCullMode cull_mode = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED;
+ int line_point_count = 0;
+ GLuint vertex_buffer = 0;
+ GLuint vertex_array = 0;
+ GLuint index_buffer = 0;
+
+ int sdf_point_count = 0;
+ int sdf_index_count = 0;
+ GLuint sdf_vertex_buffer = 0;
+ GLuint sdf_vertex_array = 0;
+ GLuint sdf_index_buffer = 0;
+ bool sdf_is_lines = false;
+ };
+
+ RID_Owner<OccluderPolygon> occluder_polygon_owner;
+
+ void _update_shadow_atlas();
+
+ struct {
+ CanvasOcclusionShaderGLES3 shader;
+ RID shader_version;
+ } shadow_render;
+
+ struct LightUniform {
+ float matrix[8]; //light to texture coordinate matrix
+ float shadow_matrix[8]; //light to shadow coordinate matrix
+ float color[4];
+
+ uint8_t shadow_color[4];
+ uint32_t flags; //index to light texture
+ float shadow_pixel_size;
+ float height;
+
+ float position[2];
+ float shadow_z_far_inv;
+ float shadow_y_ofs;
+
+ float atlas_rect[4];
+ };
+
public:
enum {
BASE_UNIFORM_LOCATION = 0,
@@ -125,6 +183,23 @@ public:
uint32_t pad2;
};
+ struct PolygonBuffers {
+ GLuint vertex_buffer = 0;
+ GLuint vertex_array = 0;
+ GLuint index_buffer = 0;
+ int count = 0;
+ bool color_disabled = false;
+ Color color;
+ };
+
+ struct {
+ HashMap<PolygonID, PolygonBuffers> polygons;
+ PolygonID last_id = 0;
+ } polygon_buffers;
+
+ RendererCanvasRender::PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) override;
+ void free_polygon(PolygonID p_polygon) override;
+
struct InstanceData {
float world[6];
float color_texture_pixel_size[2];
@@ -156,42 +231,86 @@ public:
GLuint canvas_quad_vertices;
GLuint canvas_quad_array;
+ GLuint indexed_quad_buffer;
+ GLuint indexed_quad_array;
+
GLuint particle_quad_vertices;
GLuint particle_quad_array;
GLuint ninepatch_vertices;
GLuint ninepatch_elements;
+
+ RID canvas_shader_default_version;
+
+ uint32_t max_lights_per_render = 256;
+ uint32_t max_lights_per_item = 16;
+ uint32_t max_instances_per_batch = 512;
+ uint32_t max_instances_per_ubo = 16384;
+ uint32_t max_instance_buffer_size = 16384 * 128;
} data;
+ struct Batch {
+ // Position in the UBO measured in bytes
+ uint32_t start = 0;
+ uint32_t instance_count = 0;
+
+ RID tex = RID();
+ RS::CanvasItemTextureFilter filter = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
+ RS::CanvasItemTextureRepeat repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
+
+ GLES3::CanvasShaderData::BlendMode blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
+ Color blend_color = Color(1.0, 1.0, 1.0, 1.0);
+
+ Item *clip = nullptr;
+
+ RID material = RID();
+ GLES3::CanvasMaterialData *material_data = nullptr;
+ CanvasShaderGLES3::ShaderVariant shader_variant = CanvasShaderGLES3::MODE_QUAD;
+
+ const Item::Command *command = nullptr;
+ Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
+ uint32_t primitive_points = 0;
+
+ bool lights_disabled = false;
+ };
+
+ // DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.
+ // We track them and ensure that they don't get reused until at least 2 frames have passed
+ // to avoid the GPU stalling to wait for a resource to become available.
+ struct DataBuffer {
+ GLuint ubo = 0;
+ GLuint light_ubo = 0;
+ GLuint state_ubo = 0;
+ uint64_t last_frame_used = -3;
+ GLsync fence = GLsync();
+ };
+
struct State {
- GLuint canvas_state_buffer;
- LocalVector<GLuint> canvas_instance_data_buffers;
- LocalVector<GLsync> fences;
+ LocalVector<DataBuffer> canvas_instance_data_buffers;
+ LocalVector<Batch> canvas_instance_batches;
uint32_t current_buffer = 0;
+ uint32_t current_buffer_index = 0;
+ uint32_t current_batch_index = 0;
InstanceData *instance_data_array = nullptr;
- bool canvas_texscreen_used;
- RID canvas_shader_current_version;
- RID canvas_shader_default_version;
+
+ LightUniform *light_uniforms = nullptr;
+
+ GLuint shadow_texture = 0;
+ GLuint shadow_depth_buffer = 0;
+ GLuint shadow_fb = 0;
+ int shadow_texture_size = 2048;
+
+ bool using_directional_lights = false;
RID current_tex = RID();
- Size2 current_pixel_size = Size2();
- RID current_normal = RID();
- RID current_specular = RID();
- GLES3::Texture *current_tex_ptr;
- RID current_shader_version = RID();
- RS::PrimitiveType current_primitive = RS::PRIMITIVE_MAX;
- uint32_t current_primitive_points = 0;
- Item::Command::Type current_command = Item::Command::TYPE_RECT;
+ RS::CanvasItemTextureFilter current_filter_mode = RS::CANVAS_ITEM_TEXTURE_FILTER_MAX;
+ RS::CanvasItemTextureRepeat current_repeat_mode = RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX;
bool transparent_render_target = false;
double time = 0.0;
- uint32_t max_lights_per_render;
- uint32_t max_lights_per_item;
- uint32_t max_instances_per_batch;
-
RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
} state;
@@ -201,6 +320,8 @@ public:
RID default_canvas_texture;
RID default_canvas_group_material;
RID default_canvas_group_shader;
+ RID default_clip_children_material;
+ RID default_clip_children_shader;
typedef void Texture;
@@ -210,9 +331,6 @@ public:
void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample);
void reset_canvas();
- void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, Projection *p_xform_cache);
-
- virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override;
RID light_create() override;
void light_set_texture(RID p_rid, RID p_texture) override;
@@ -229,31 +347,18 @@ public:
bool free(RID p_rid) override;
void update() override;
- void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index);
-
- struct PolygonBuffers {
- GLuint vertex_buffer;
- GLuint vertex_array;
- GLuint index_buffer;
- int count;
- bool color_disabled = false;
- Color color;
- };
-
- struct {
- HashMap<PolygonID, PolygonBuffers> polygons;
- PolygonID last_id;
- } polygon_buffers;
-
- RendererCanvasRender::PolygonID request_polygon(const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>()) override;
- void free_polygon(PolygonID p_polygon) override;
+ void _bind_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat);
+ void _prepare_canvas_texture(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, uint32_t &r_index, Size2 &r_texpixel_size);
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override;
- void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
- void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color);
- void _render_batch(uint32_t &p_max_index);
- void _bind_instance_data_buffer(uint32_t p_max_index);
+ void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, uint32_t &r_last_index, bool p_to_backbuffer = false);
+ void _record_item_commands(const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_break_batch);
+ void _render_batch(Light *p_lights, uint32_t p_index);
+ void _bind_material(GLES3::CanvasMaterialData *p_material_data, CanvasShaderGLES3::ShaderVariant p_variant, uint64_t p_specialization);
+ void _new_batch(bool &r_batch_broken, uint32_t &r_index);
+ void _add_to_batch(uint32_t &r_index, bool &r_batch_broken);
void _allocate_instance_data_buffer();
+ void _align_instance_data_buffer(uint32_t &r_index);
void set_time(double p_time);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 3575837794..b2d01b02fb 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -100,9 +100,8 @@ void RasterizerGLES3::begin_frame(double frame_step) {
canvas->set_time(time_total);
scene->set_time(time_total, frame_step);
- GLES3::Utilities *utilities = GLES3::Utilities::get_singleton();
- utilities->info.render_final = utilities->info.render;
- utilities->info.render.reset();
+ GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
+ utils->_capture_timestamps_begin();
//scene->iteration();
}
@@ -272,23 +271,41 @@ RasterizerGLES3::~RasterizerGLES3() {
}
void RasterizerGLES3::prepare_for_blitting_render_targets() {
+ // This is a hack, but this function is called one time after all viewports have been updated.
+ // So it marks the end of the frame for all viewports
+ // In the OpenGL renderer we have to call end_frame for each viewport so we can swap the
+ // buffers for each window before proceeding to the next.
+ // This allows us to only increment the frame after all viewports are done.
+ GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
+ utils->capture_timestamps_end();
}
-void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect) {
- GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer) {
+ GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
- GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
ERR_FAIL_COND(!rt);
- if (rt->external.fbo != 0) {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
+ GLuint read_fbo = 0;
+ if (rt->view_count > 1) {
+ glGenFramebuffers(1, &read_fbo);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, read_fbo);
+ glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, p_layer);
} else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo);
}
+
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
// Flip content upside down to correct for coordinates.
- glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ Vector2i screen_rect_end = p_screen_rect.get_end();
+ glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
+ p_screen_rect.position.x, screen_rect_end.y, screen_rect_end.x, p_screen_rect.position.y,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ if (read_fbo != 0) {
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glDeleteFramebuffers(1, &read_fbo);
+ }
}
// is this p_screen useless in a multi window environment?
@@ -299,7 +316,7 @@ void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_sc
RID rid_rt = blit.render_target;
Rect2 dst_rect = blit.dst_rect;
- _blit_render_target_to_screen(rid_rt, p_screen, dst_rect);
+ _blit_render_target_to_screen(rid_rt, p_screen, dst_rect, blit.multi_view.use_layer ? blit.multi_view.layer : 0);
}
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 97543af0d5..d7d26685b4 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -68,7 +68,7 @@ protected:
RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr;
- void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect);
+ void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer);
public:
RendererUtilities *get_utilities() { return utilities; }
@@ -103,8 +103,9 @@ public:
low_end = true;
}
- uint64_t get_frame_number() const { return frame; }
- double get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; }
+ _ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
+ _ALWAYS_INLINE_ double get_total_time() const { return time_total; }
RasterizerGLES3();
~RasterizerGLES3();
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index d106bb31c7..6e9d4e5963 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -34,7 +34,6 @@
#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/rendering_server_globals.h"
#include "storage/config.h"
-#include "storage/light_storage.h"
#include "storage/mesh_storage.h"
#include "storage/texture_storage.h"
@@ -70,7 +69,7 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID
spot_lights.clear();
for (uint32_t i = 0; i < p_light_instance_count; i++) {
- RS::LightType type = RasterizerSceneGLES3::get_singleton()->light_instance_get_type(p_light_instances[i]);
+ RS::LightType type = GLES3::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]);
switch (type) {
case RS::LIGHT_OMNI: {
if (omni_light_count < (uint32_t)config->max_lights_per_object) {
@@ -399,32 +398,6 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
ginstance->dirty_list_element.remove_from_list();
}
-/* SHADOW ATLAS API */
-
-RID RasterizerSceneGLES3::shadow_atlas_create() {
- return RID();
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
-}
-
-bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
- return false;
-}
-
-void RasterizerSceneGLES3::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
-}
-
-int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) {
- return 0;
-}
-
-void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
-}
-
/* SKY API */
void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
@@ -625,7 +598,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
if (shader_data->uses_light) {
sky_globals.directional_light_count = 0;
for (int i = 0; i < (int)p_lights.size(); i++) {
- LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
+ GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(p_lights[i]);
if (!li) {
continue;
}
@@ -780,7 +753,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
- GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.columns[2][0], camera.columns[0][0], camera.columns[2][1], camera.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
@@ -881,7 +854,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
- GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.matrix[2][0], cm.matrix[0][0], cm.matrix[2][1], cm.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.columns[2][0], cm.columns[0][0], cm.columns[2][1], cm.columns[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::LUMINANCE_MULTIPLIER, p_luminance_multiplier, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
glBindVertexArray(sky_globals.screen_triangle_array);
@@ -1084,38 +1057,6 @@ void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQ
void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
}
-RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
- RID li = light_instance_owner.make_rid(LightInstance());
-
- LightInstance *light_instance = light_instance_owner.get_or_null(li);
-
- light_instance->self = li;
- light_instance->light = p_light;
- light_instance->light_type = RSG::light_storage->light_get_type(p_light);
-
- return li;
-}
-
-void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->transform = p_transform;
-}
-
-void RasterizerSceneGLES3::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->aabb = p_aabb;
-}
-
-void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
-}
-
-void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
-}
-
RID RasterizerSceneGLES3::fog_volume_instance_create(RID p_fog_volume) {
return RID();
}
@@ -1134,57 +1075,6 @@ Vector3 RasterizerSceneGLES3::fog_volume_instance_get_position(RID p_fog_volume_
return Vector3();
}
-RID RasterizerSceneGLES3::reflection_atlas_create() {
- return RID();
-}
-
-int RasterizerSceneGLES3::reflection_atlas_get_size(RID p_ref_atlas) const {
- return 0;
-}
-
-void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
-}
-
-RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) {
- return RID();
-}
-
-void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
-}
-
-void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) {
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
- return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) {
- return true;
-}
-
-RID RasterizerSceneGLES3::decal_instance_create(RID p_decal) {
- return RID();
-}
-
-void RasterizerSceneGLES3::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
-}
-
-RID RasterizerSceneGLES3::lightmap_instance_create(RID p_lightmap) {
- return RID();
-}
-
-void RasterizerSceneGLES3::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
-}
-
RID RasterizerSceneGLES3::voxel_gi_instance_create(RID p_voxel_gi) {
return RID();
}
@@ -1257,13 +1147,13 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
if (inst->omni_light_count) {
inst->omni_light_gl_cache.resize(inst->omni_light_count);
for (uint32_t j = 0; j < inst->omni_light_count; j++) {
- inst->omni_light_gl_cache[j] = light_instance_get_gl_id(inst->omni_lights[j]);
+ inst->omni_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(inst->omni_lights[j]);
}
}
if (inst->spot_light_count) {
inst->spot_light_gl_cache.resize(inst->spot_light_count);
for (uint32_t j = 0; j < inst->spot_light_count; j++) {
- inst->spot_light_gl_cache[j] = light_instance_get_gl_id(inst->spot_lights[j]);
+ inst->spot_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(inst->spot_lights[j]);
}
}
}
@@ -1276,12 +1166,13 @@ void RasterizerSceneGLES3::_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)) {
- //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);
+ // Get the LOD support points on the mesh AABB.
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
- 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);
+ // Get the distances to those points on the AABB from the camera origin.
+ float distance_min = (float)p_render_data->cam_transform.origin.distance_to(lod_support_min);
+ float distance_max = (float)p_render_data->cam_transform.origin.distance_to(lod_support_max);
float distance = 0.0;
@@ -1298,8 +1189,8 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
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);
+ uint32_t indices = 0;
+ 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);
/*
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
@@ -1382,6 +1273,19 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
GLES3::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
GLES3::MaterialStorage::store_transform(p_render_data->inv_cam_transform, scene_state.ubo.view_matrix);
+ if (p_render_data->view_count > 1) {
+ for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ projection = correction * p_render_data->view_projection[v];
+ GLES3::MaterialStorage::store_camera(projection, scene_state.multiview_ubo.projection_matrix_view[v]);
+ GLES3::MaterialStorage::store_camera(projection.inverse(), scene_state.multiview_ubo.inv_projection_matrix_view[v]);
+
+ scene_state.multiview_ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
+ scene_state.multiview_ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
+ scene_state.multiview_ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
+ scene_state.multiview_ubo.eye_offset[v][3] = 0.0;
+ }
+ }
+
scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
scene_state.ubo.z_far = p_render_data->z_far;
@@ -1483,6 +1387,15 @@ void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_da
glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+ if (p_render_data->view_count > 1) {
+ if (scene_state.multiview_buffer == 0) {
+ glGenBuffers(1, &scene_state.multiview_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MULTIVIEW_UNIFORM_LOCATION, scene_state.multiview_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::MultiviewUBO), &scene_state.multiview_ubo, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
}
// Puts lights into Uniform Buffers. Needs to be called before _fill_list as this caches the index of each light in the Uniform Buffer
@@ -1501,7 +1414,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
int num_lights = lights.size();
for (int i = 0; i < num_lights; i++) {
- LightInstance *li = light_instance_owner.get_or_null(lights[i]);
+ GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(lights[i]);
if (!li) {
continue;
}
@@ -1606,12 +1519,12 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
if (r_omni_light_count) {
- SortArray<InstanceSort<LightInstance>> sorter;
+ SortArray<InstanceSort<GLES3::LightInstance>> sorter;
sorter.sort(scene_state.omni_light_sort, r_omni_light_count);
}
if (r_spot_light_count) {
- SortArray<InstanceSort<LightInstance>> sorter;
+ SortArray<InstanceSort<GLES3::LightInstance>> sorter;
sorter.sort(scene_state.spot_light_sort, r_spot_light_count);
}
@@ -1619,7 +1532,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
uint32_t index = (i < r_omni_light_count) ? i : i - (r_omni_light_count);
LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
RS::LightType type = (i < r_omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
- LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+ GLES3::LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
RID base = li->light;
Transform3D light_transform = li->transform;
@@ -1760,7 +1673,6 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
// 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;
@@ -2026,8 +1938,14 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
GLES3::SceneShaderData *prev_shader = nullptr;
GeometryInstanceGLES3 *prev_inst = nullptr;
SceneShaderGLES3::ShaderVariant prev_variant = SceneShaderGLES3::ShaderVariant::MODE_COLOR;
+ SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized
+
+ // @todo Get this from p_params->spec_constant_base_flags instead of hardcoding it.
+ uint32_t base_spec_constants = 0;
- SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
+ if (p_render_data->view_count > 1) {
+ base_spec_constants |= 1 << SPEC_CONSTANT_USE_MULTIVIEW;
+ }
switch (p_pass_mode) {
case PASS_MODE_COLOR:
@@ -2067,8 +1985,6 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
continue;
}
- //uint32_t base_spec_constants = p_params->spec_constant_base_flags;
-
GLES3::SceneShaderData *shader;
GLES3::SceneMaterialData *material_data;
void *mesh_surface;
@@ -2238,7 +2154,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
if (prev_shader != shader || prev_variant != instance_variant) {
- material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_bind_shader(shader->version, instance_variant, base_spec_constants);
float opaque_prepass_threshold = 0.0;
if constexpr (p_pass_mode == PASS_MODE_DEPTH) {
opaque_prepass_threshold = 0.99;
@@ -2246,7 +2162,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
opaque_prepass_threshold = 0.1;
}
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OPAQUE_PREPASS_THRESHOLD, opaque_prepass_threshold, shader->version, instance_variant, base_spec_constants);
prev_shader = shader;
prev_variant = instance_variant;
@@ -2254,21 +2170,21 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
if (prev_inst != inst || prev_shader != shader || prev_variant != instance_variant) {
// Rebind the light indices.
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant);
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::OMNI_LIGHT_COUNT, inst->omni_light_count, shader->version, instance_variant, base_spec_constants);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::SPOT_LIGHT_COUNT, inst->spot_light_count, shader->version, instance_variant, base_spec_constants);
if (inst->omni_light_count) {
- glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::OMNI_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->omni_light_count, inst->omni_light_gl_cache.ptr());
}
if (inst->spot_light_count) {
- glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
+ glUniform1uiv(material_storage->shaders.scene_shader.version_get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES, shader->version, instance_variant, base_spec_constants), inst->spot_light_count, inst->spot_light_gl_cache.ptr());
}
prev_inst = inst;
}
- material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant);
+ material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, base_spec_constants);
if (inst->instance_count > 0) {
// Using MultiMesh.
// Bind instance buffers.
@@ -2390,10 +2306,8 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
ERR_FAIL_COND_V(!sky, false);
_free_sky_data(sky);
sky_owner.free(p_rid);
- } else if (light_instance_owner.owns(p_rid)) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
- ERR_FAIL_COND_V(!light_instance, false);
- light_instance_owner.free(p_rid);
+ } else if (GLES3::LightStorage::get_singleton()->owns_light_instance(p_rid)) {
+ GLES3::LightStorage::get_singleton()->light_instance_free(p_rid);
} else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
//not much to delete, just free it
RSG::camera_attributes->camera_attributes_free(p_rid);
@@ -2433,13 +2347,13 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
uint32_t light_buffer_size = config->max_renderable_lights * sizeof(LightData);
scene_state.omni_lights = memnew_arr(LightData, config->max_renderable_lights);
- scene_state.omni_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ scene_state.omni_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
glGenBuffers(1, &scene_state.omni_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
- scene_state.spot_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+ scene_state.spot_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
glGenBuffers(1, &scene_state.spot_light_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index f0dc972678..3a759425e2 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -44,6 +44,7 @@
#include "shader_gles3.h"
#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/sky.glsl.gen.h"
+#include "storage/light_storage.h"
#include "storage/material_storage.h"
#include "storage/render_scene_buffers_gles3.h"
#include "storage/utilities.h"
@@ -73,6 +74,7 @@ enum SceneUniformLocation {
SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SCENE_MULTIVIEW_UNIFORM_LOCATION,
};
enum SkyUniformLocation {
@@ -89,6 +91,8 @@ enum {
SPEC_CONSTANT_DISABLE_OMNI_LIGHTS = 2,
SPEC_CONSTANT_DISABLE_SPOT_LIGHTS = 3,
SPEC_CONSTANT_DISABLE_FOG = 4,
+ SPEC_CONSTANT_USE_RADIANCE_MAP = 5,
+ SPEC_CONSTANT_USE_MULTIVIEW = 6,
};
struct RenderDataGLES3 {
@@ -117,7 +121,6 @@ struct RenderDataGLES3 {
int reflection_probe_pass = 0;
float lod_distance_multiplier = 0.0;
- Plane lod_camera_plane = Plane();
float screen_mesh_lod_threshold = 0.0;
uint32_t directional_light_count = 0;
@@ -183,34 +186,6 @@ private:
};
static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
- struct LightInstance {
- RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
-
- AABB aabb;
- RID self;
- RID light;
- Transform3D transform;
-
- Vector3 light_vector;
- Vector3 spot_vector;
- float linear_att = 0.0;
-
- uint64_t shadow_pass = 0;
- uint64_t last_scene_pass = 0;
- uint64_t last_scene_shadow_pass = 0;
- uint64_t last_pass = 0;
- uint32_t cull_mask = 0;
- uint32_t light_directional_index = 0;
-
- Rect2 directional_rect;
-
- uint32_t gl_id = -1;
-
- LightInstance() {}
- };
-
- mutable RID_Owner<LightInstance> light_instance_owner;
-
class GeometryInstanceGLES3;
// Cached data for drawing surfaces
@@ -371,6 +346,13 @@ private:
};
static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+ struct MultiviewUBO {
+ 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];
+ };
+ static_assert(sizeof(MultiviewUBO) % 16 == 0, "Multiview UBO size must be a multiple of 16 bytes");
+
struct TonemapUBO {
float exposure = 1.0;
float white = 1.0;
@@ -381,6 +363,8 @@ private:
UBO ubo;
GLuint ubo_buffer = 0;
+ MultiviewUBO multiview_ubo;
+ GLuint multiview_buffer = 0;
GLuint tonemap_buffer = 0;
bool used_depth_prepass = false;
@@ -398,8 +382,8 @@ private:
LightData *omni_lights = nullptr;
LightData *spot_lights = nullptr;
- InstanceSort<LightInstance> *omni_light_sort;
- InstanceSort<LightInstance> *spot_light_sort;
+ InstanceSort<GLES3::LightInstance> *omni_light_sort;
+ InstanceSort<GLES3::LightInstance> *spot_light_sort;
GLuint omni_light_buffer = 0;
GLuint spot_light_buffer = 0;
uint32_t omni_light_count = 0;
@@ -605,17 +589,6 @@ public:
uint32_t geometry_instance_get_pair_mask() override;
- /* SHADOW ATLAS API */
-
- RID shadow_atlas_create() override;
- void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
- void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
- bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
-
- void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
- int get_directional_light_shadow_size(RID p_light_intance) override;
- void set_directional_shadow_count(int p_count) override;
-
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
@@ -666,45 +639,12 @@ public:
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
- RID light_instance_create(RID p_light) override;
- void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
- void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
- void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
- void light_instance_mark_visible(RID p_light_instance) override;
-
- _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->light_type;
- }
- _FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->gl_id;
- }
-
RID fog_volume_instance_create(RID p_fog_volume) override;
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
- RID reflection_atlas_create() override;
- int reflection_atlas_get_size(RID p_ref_atlas) const override;
- void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
-
- RID reflection_probe_instance_create(RID p_probe) override;
- void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
- void reflection_probe_release_atlas_index(RID p_instance) override;
- bool reflection_probe_instance_needs_redraw(RID p_instance) override;
- bool reflection_probe_instance_has_reflection(RID p_instance) override;
- bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
- bool reflection_probe_instance_postprocess_step(RID p_instance) override;
-
- RID decal_instance_create(RID p_decal) override;
- void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
-
- RID lightmap_instance_create(RID p_lightmap) override;
- void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
-
RID voxel_gi_instance_create(RID p_voxel_gi) override;
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override;
bool voxel_gi_needs_update(RID p_probe) const override;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 033f10dbc5..2ff7f72180 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -142,7 +142,7 @@ RID ShaderGLES3::version_create() {
return version_owner.make_rid(version);
}
-void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization) {
+void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) {
#ifdef GLES_OVER_GL
builder.append("#version 330\n");
builder.append("#define USE_GLES_OVER_GL\n");
@@ -171,6 +171,24 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
}
builder.append("\n"); //make sure defines begin at newline
+ // Insert multiview extension loading, because it needs to appear before
+ // any non-preprocessor code (like the "precision highp..." lines below).
+ builder.append("#ifdef USE_MULTIVIEW\n");
+ builder.append("#if defined(GL_OVR_multiview2)\n");
+ builder.append("#extension GL_OVR_multiview2 : require\n");
+ builder.append("#elif defined(GL_OVR_multiview)\n");
+ builder.append("#extension GL_OVR_multiview : require\n");
+ builder.append("#endif\n");
+ if (p_stage_type == StageType::STAGE_TYPE_VERTEX) {
+ builder.append("layout(num_views=2) in;\n");
+ }
+ builder.append("#define ViewIndex gl_ViewID_OVR\n");
+ builder.append("#define MAX_VIEWS 2\n");
+ builder.append("#else\n");
+ builder.append("#define ViewIndex 0\n");
+ builder.append("#define MAX_VIEWS 1\n");
+ builder.append("#endif\n");
+
// Default to highp precision unless specified otherwise.
builder.append("precision highp float;\n");
builder.append("precision highp int;\n");
@@ -180,8 +198,9 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
builder.append("precision highp sampler2DArray;\n");
#endif
- for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
- const StageTemplate::Chunk &chunk = p_template.chunks[i];
+ const StageTemplate &stage_template = stage_templates[p_stage_type];
+ for (uint32_t i = 0; i < stage_template.chunks.size(); i++) {
+ const StageTemplate::Chunk &chunk = stage_template.chunks[i];
switch (chunk.type) {
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
@@ -224,7 +243,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//vertex stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_VERTEX], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_VERTEX, p_specialization);
spec.vert_id = glCreateShader(GL_VERTEX_SHADER);
String builder_string = builder.as_string();
@@ -272,7 +291,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, p_variant, p_version, stage_templates[STAGE_TYPE_FRAGMENT], p_specialization);
+ _build_variant_code(builder, p_variant, p_version, STAGE_TYPE_FRAGMENT, p_specialization);
spec.frag_id = glCreateShader(GL_FRAGMENT_SHADER);
String builder_string = builder.as_string();
@@ -413,7 +432,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_VERTEX, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "vertex";
@@ -425,7 +444,7 @@ RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_ver
//fragment stage
{
StringBuilder builder;
- _build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT], specialization_default_mask);
+ _build_variant_code(builder, i, version, STAGE_TYPE_FRAGMENT, specialization_default_mask);
RS::ShaderNativeSourceCode::Version::Stage stage;
stage.name = "fragment";
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 2b72549b5b..f5b4a8cb3c 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -153,7 +153,7 @@ private:
StageTemplate stage_templates[STAGE_TYPE_MAX];
- void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template, uint64_t p_specialization);
+ void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization);
void _add_stage(const char *p_code, StageType p_stage_type);
@@ -208,8 +208,10 @@ protected:
spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
}
- ERR_FAIL_COND(!spec); // Should never happen
- ERR_FAIL_COND(!spec->ok); // Should never happen
+ if (!spec || !spec->ok) {
+ WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
+ return;
+ }
glUseProgram(spec->id);
current_shader = spec;
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 83ffe8b1e1..b8bb08ec34 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -17,3 +17,5 @@ if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("scene.glsl")
env.GLES3_GLSL("sky.glsl")
env.GLES3_GLSL("cubemap_filter.glsl")
+ env.GLES3_GLSL("canvas_occlusion.glsl")
+ env.GLES3_GLSL("canvas_sdf.glsl")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 7334100575..ca806304c5 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -10,6 +10,7 @@ mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
#[specializations]
DISABLE_LIGHTING = false
+USE_RGBA_SHADOWS = false
#[vertex]
@@ -60,20 +61,18 @@ out vec2 pixel_size_interp;
void main() {
vec4 instance_custom = vec4(0.0);
- draw_data_instance = gl_InstanceID;
-#ifdef USE_PRIMITIVE
- //weird bug,
- //this works
+#ifdef USE_PRIMITIVE
+ draw_data_instance = gl_InstanceID;
vec2 vertex;
vec2 uv;
vec4 color;
- if (gl_VertexID == 0) {
+ if (gl_VertexID % 3 == 0) {
vertex = draw_data[draw_data_instance].point_a;
uv = draw_data[draw_data_instance].uv_a;
color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_a_rg), unpackHalf2x16(draw_data[draw_data_instance].color_a_ba));
- } else if (gl_VertexID == 1) {
+ } else if (gl_VertexID % 3 == 1) {
vertex = draw_data[draw_data_instance].point_b;
uv = draw_data[draw_data_instance].uv_b;
color = vec4(unpackHalf2x16(draw_data[draw_data_instance].color_b_rg), unpackHalf2x16(draw_data[draw_data_instance].color_b_ba));
@@ -86,6 +85,7 @@ void main() {
vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
+ draw_data_instance = gl_InstanceID;
#ifdef USE_INSTANCING
draw_data_instance = 0;
#endif
@@ -103,9 +103,9 @@ void main() {
#endif
#else
-
- vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
- vec2 vertex_base = vertex_base_arr[gl_VertexID];
+ draw_data_instance = gl_VertexID / 6;
+ vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
+ vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
vec2 uv = draw_data[draw_data_instance].src_rect.xy + abs(draw_data[draw_data_instance].src_rect.zw) * ((draw_data[draw_data_instance].flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
vec4 color = draw_data[draw_data_instance].modulation;
@@ -127,6 +127,8 @@ void main() {
}
#endif
+ vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
@@ -210,8 +212,10 @@ void main() {
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
-//uniform sampler2D atlas_texture; //texunit:-2
-//uniform sampler2D shadow_atlas_texture; //texunit:-3
+#ifndef DISABLE_LIGHTING
+uniform sampler2D atlas_texture; //texunit:-2
+uniform sampler2D shadow_atlas_texture; //texunit:-3
+#endif // DISABLE_LIGHTING
uniform sampler2D screen_texture; //texunit:-4
uniform sampler2D sdf_texture; //texunit:-5
uniform sampler2D normal_texture; //texunit:-6
@@ -243,6 +247,170 @@ layout(std140) uniform MaterialUniforms{
#GLOBALS
+float vec4_to_float(vec4 p_vec) {
+ return dot(p_vec, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0;
+}
+
+vec2 screen_uv_to_sdf(vec2 p_uv) {
+ return screen_to_sdf * p_uv;
+}
+
+float texture_sdf(vec2 p_sdf) {
+ vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
+ float d = vec4_to_float(texture(sdf_texture, uv));
+ d *= SDF_MAX_LENGTH;
+ return d * tex_to_sdf;
+}
+
+vec2 texture_sdf_normal(vec2 p_sdf) {
+ vec2 uv = p_sdf * sdf_to_tex.xy + sdf_to_tex.zw;
+
+ const float EPSILON = 0.001;
+ return normalize(vec2(
+ vec4_to_float(texture(sdf_texture, uv + vec2(EPSILON, 0.0))) - vec4_to_float(texture(sdf_texture, uv - vec2(EPSILON, 0.0))),
+ vec4_to_float(texture(sdf_texture, uv + vec2(0.0, EPSILON))) - vec4_to_float(texture(sdf_texture, uv - vec2(0.0, EPSILON)))));
+}
+
+vec2 sdf_to_screen_uv(vec2 p_sdf) {
+ return p_sdf * sdf_to_screen;
+}
+
+#ifndef DISABLE_LIGHTING
+#ifdef LIGHT_CODE_USED
+
+vec4 light_compute(
+ vec3 light_vertex,
+ vec3 light_position,
+ vec3 normal,
+ vec4 light_color,
+ float light_energy,
+ vec4 specular_shininess,
+ inout vec4 shadow_modulate,
+ vec2 screen_uv,
+ vec2 uv,
+ vec4 color, bool is_directional) {
+ vec4 light = vec4(0.0);
+ vec3 light_direction = vec3(0.0);
+
+ if (is_directional) {
+ light_direction = normalize(mix(vec3(light_position.xy, 0.0), vec3(0, 0, 1), light_position.z));
+ light_position = vec3(0.0);
+ } else {
+ light_direction = normalize(light_position - light_vertex);
+ }
+
+#CODE : LIGHT
+
+ return light;
+}
+
+#endif
+
+vec3 light_normal_compute(vec3 light_vec, vec3 normal, vec3 base_color, vec3 light_color, vec4 specular_shininess, bool specular_shininess_used) {
+ float cNdotL = max(0.0, dot(normal, light_vec));
+
+ if (specular_shininess_used) {
+ //blinn
+ vec3 view = vec3(0.0, 0.0, 1.0); // not great but good enough
+ vec3 half_vec = normalize(view + light_vec);
+
+ float cNdotV = max(dot(normal, view), 0.0);
+ float cNdotH = max(dot(normal, half_vec), 0.0);
+ float cVdotH = max(dot(view, half_vec), 0.0);
+ float cLdotH = max(dot(light_vec, half_vec), 0.0);
+ float shininess = exp2(15.0 * specular_shininess.a + 1.0) * 0.25;
+ float blinn = pow(cNdotH, shininess);
+ blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI));
+ float s = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75);
+
+ return specular_shininess.rgb * light_color * s + light_color * base_color * cNdotL;
+ } else {
+ return light_color * base_color * cNdotL;
+ }
+}
+
+#ifdef USE_RGBA_SHADOWS
+
+#define SHADOW_DEPTH(m_uv) (dot(textureLod(shadow_atlas_texture, (m_uv), 0.0), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) * 2.0 - 1.0)
+
+#else
+
+#define SHADOW_DEPTH(m_uv) (textureLod(shadow_atlas_texture, (m_uv), 0.0).r)
+
+#endif
+
+#define SHADOW_TEST(m_uv) \
+ { \
+ highp float sd = SHADOW_DEPTH(m_uv); \
+ shadow += step(sd, shadow_uv.z / shadow_uv.w); \
+ }
+
+//float distance = length(shadow_pos);
+vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
+#ifdef LIGHT_CODE_USED
+ ,
+ vec3 shadow_modulate
+#endif
+) {
+ float shadow = 0.0;
+ uint shadow_mode = light_array[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
+
+ if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
+ SHADOW_TEST(shadow_uv.xy);
+ } else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
+ vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
+ shadow /= 5.0;
+ } else { //PCF13
+ vec2 shadow_pixel_size = vec2(light_array[light_base].shadow_pixel_size, 0.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 6.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 5.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 4.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 3.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy - shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 2.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 3.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 4.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 5.0);
+ SHADOW_TEST(shadow_uv.xy + shadow_pixel_size * 6.0);
+ shadow /= 13.0;
+ }
+
+ vec4 shadow_color = unpackUnorm4x8(light_array[light_base].shadow_color);
+#ifdef LIGHT_CODE_USED
+ shadow_color.rgb *= shadow_modulate;
+#endif
+
+ shadow_color.a *= light_color.a; //respect light alpha
+
+ return mix(light_color, shadow_color, shadow);
+}
+
+void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
+ uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
+
+ switch (blend_mode) {
+ case LIGHT_FLAGS_BLEND_MODE_ADD: {
+ color.rgb += light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_SUB: {
+ color.rgb -= light_color.rgb * light_color.a;
+ } break;
+ case LIGHT_FLAGS_BLEND_MODE_MIX: {
+ color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
+ } break;
+ }
+}
+
+#endif
+
#ifdef USE_NINEPATCH
float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
@@ -352,7 +520,8 @@ void main() {
color *= texture(color_texture, uv);
}
- bool using_light = false;
+ uint light_count = (draw_data[draw_data_instance].flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -393,6 +562,8 @@ void main() {
vec2 screen_uv = vec2(0.0);
#endif
+ vec2 color_texture_pixel_size = draw_data[draw_data_instance].color_texture_pixel_size.xy;
+
vec3 light_vertex = vec3(vertex, 0.0);
vec2 shadow_vertex = vertex;
@@ -411,11 +582,158 @@ void main() {
#endif
}
+ if (normal_used) {
+ //convert by item transform
+ normal.xy = mat2(normalize(draw_data[draw_data_instance].world_x), normalize(draw_data[draw_data_instance].world_y)) * normal.xy;
+ //convert by canvas transform
+ normal = normalize((canvas_normal_transform * vec4(normal, 0.0)).xyz);
+ }
+
+ vec4 base_color = color;
+
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
#else
color *= canvas_modulation;
#endif
+#if !defined(DISABLE_LIGHTING) && !defined(MODE_UNSHADED)
+
+ // Directional Lights
+
+ for (uint i = 0u; i < directional_light_count; i++) {
+ uint light_base = i;
+
+ vec2 direction = light_array[light_base].position;
+ vec4 light_color = light_array[light_base].color;
+
+#ifdef LIGHT_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ light_color = light_compute(light_vertex, vec3(direction, light_array[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
+#else
+
+ if (normal_used) {
+ vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array[light_base].height));
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
+ }
+#endif
+
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+
+ vec4 shadow_uv = vec4(shadow_pos.x, light_array[light_base].shadow_y_ofs, shadow_pos.y * light_array[light_base].shadow_zfar_inv, 1.0);
+
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_CODE_USED
+ ,
+ shadow_modulate.rgb
+#endif
+ );
+ }
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+
+ // Positional Lights
+
+ for (uint i = 0u; i < MAX_LIGHTS_PER_ITEM; i++) {
+ if (i >= light_count) {
+ break;
+ }
+ uint light_base;
+ if (i < 8u) {
+ if (i < 4u) {
+ light_base = draw_data[draw_data_instance].lights[0];
+ } else {
+ light_base = draw_data[draw_data_instance].lights[1];
+ }
+ } else {
+ if (i < 12u) {
+ light_base = draw_data[draw_data_instance].lights[2];
+ } else {
+ light_base = draw_data[draw_data_instance].lights[3];
+ }
+ }
+ light_base >>= (i & 3u) * 8u;
+ light_base &= uint(0xFF);
+
+ vec2 tex_uv = (vec4(vertex, 0.0, 1.0) * mat4(light_array[light_base].texture_matrix[0], light_array[light_base].texture_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+ vec2 tex_uv_atlas = tex_uv * light_array[light_base].atlas_rect.zw + light_array[light_base].atlas_rect.xy;
+ vec4 light_color = textureLod(atlas_texture, tex_uv_atlas, 0.0);
+ vec4 light_base_color = light_array[light_base].color;
+
+#ifdef LIGHT_CODE_USED
+
+ vec4 shadow_modulate = vec4(1.0);
+ vec3 light_position = vec3(light_array[light_base].position, light_array[light_base].height);
+
+ light_color.rgb *= light_base_color.rgb;
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
+#else
+
+ light_color.rgb *= light_base_color.rgb * light_base_color.a;
+
+ if (normal_used) {
+ vec3 light_pos = vec3(light_array[light_base].position, light_array[light_base].height);
+ vec3 pos = light_vertex;
+ vec3 light_vec = normalize(light_pos - pos);
+
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
+ }
+#endif
+ if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
+ //if outside the light texture, light color is zero
+ light_color.a = 0.0;
+ }
+
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
+
+ vec2 pos_norm = normalize(shadow_pos);
+ vec2 pos_abs = abs(pos_norm);
+ vec2 pos_box = pos_norm / max(pos_abs.x, pos_abs.y);
+ vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
+ float tex_ofs;
+ float dist;
+ if (pos_rot.y > 0.0) {
+ if (pos_rot.x > 0.0) {
+ tex_ofs = pos_box.y * 0.125 + 0.125;
+ dist = shadow_pos.x;
+ } else {
+ tex_ofs = pos_box.x * -0.125 + (0.25 + 0.125);
+ dist = shadow_pos.y;
+ }
+ } else {
+ if (pos_rot.x < 0.0) {
+ tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
+ dist = -shadow_pos.x;
+ } else {
+ tex_ofs = pos_box.x * 0.125 + (0.75 + 0.125);
+ dist = -shadow_pos.y;
+ }
+ }
+
+ dist *= light_array[light_base].shadow_zfar_inv;
+
+ //float distance = length(shadow_pos);
+ vec4 shadow_uv = vec4(tex_ofs, light_array[light_base].shadow_y_ofs, dist, 1.0);
+
+ light_color = light_shadow_compute(light_base, light_color, shadow_uv
+#ifdef LIGHT_CODE_USED
+ ,
+ shadow_modulate.rgb
+#endif
+ );
+ }
+
+ light_blend_compute(light_base, light_color, color.rgb);
+ }
+#endif
+
frag_color = color;
}
diff --git a/drivers/gles3/shaders/canvas_occlusion.glsl b/drivers/gles3/shaders/canvas_occlusion.glsl
new file mode 100644
index 0000000000..512800839a
--- /dev/null
+++ b/drivers/gles3/shaders/canvas_occlusion.glsl
@@ -0,0 +1,68 @@
+/* clang-format off */
+#[modes]
+
+mode_sdf =
+mode_shadow = #define MODE_SHADOW
+mode_shadow_RGBA = #define MODE_SHADOW \n#define USE_RGBA_SHADOWS
+
+#[specializations]
+
+#[vertex]
+
+layout(location = 0) in vec3 vertex;
+
+uniform highp mat4 projection;
+uniform highp vec4 modelview1;
+uniform highp vec4 modelview2;
+uniform highp vec2 direction;
+uniform highp float z_far;
+
+#ifdef MODE_SHADOW
+out float depth;
+#endif
+
+void main() {
+ highp vec4 vtx = vec4(vertex, 1.0) * mat4(modelview1, modelview2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
+
+#ifdef MODE_SHADOW
+ depth = dot(direction, vtx.xy);
+#endif
+ gl_Position = projection * vtx;
+}
+
+#[fragment]
+
+
+uniform highp mat4 projection;
+uniform highp vec4 modelview1;
+uniform highp vec4 modelview2;
+uniform highp vec2 direction;
+uniform highp float z_far;
+
+#ifdef MODE_SHADOW
+in highp float depth;
+#endif
+
+#ifdef USE_RGBA_SHADOWS
+layout(location = 0) out lowp vec4 out_buf;
+#else
+layout(location = 0) out highp float out_buf;
+#endif
+
+void main() {
+ float out_depth = 1.0;
+
+#ifdef MODE_SHADOW
+ out_depth = depth / z_far;
+#endif
+
+#ifdef USE_RGBA_SHADOWS
+ out_depth = clamp(out_depth, -1.0, 1.0);
+ out_depth = out_depth * 0.5 + 0.5;
+ highp vec4 comp = fract(out_depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
+ comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
+ out_buf = comp;
+#else
+ out_buf = out_depth;
+#endif
+}
diff --git a/drivers/gles3/shaders/canvas_sdf.glsl b/drivers/gles3/shaders/canvas_sdf.glsl
new file mode 100644
index 0000000000..424ec22457
--- /dev/null
+++ b/drivers/gles3/shaders/canvas_sdf.glsl
@@ -0,0 +1,205 @@
+/* clang-format off */
+#[modes]
+
+mode_load = #define MODE_LOAD
+mode_load_shrink = #define MODE_LOAD_SHRINK
+mode_process = #define MODE_PROCESS
+mode_store = #define MODE_STORE
+mode_store_shrink = #define MODE_STORE_SHRINK
+
+#[specializations]
+
+#[vertex]
+
+layout(location = 0) in vec2 vertex_attrib;
+
+/* clang-format on */
+
+uniform ivec2 size;
+uniform int stride;
+uniform int shift;
+uniform ivec2 base_size;
+
+void main() {
+ gl_Position = vec4(vertex_attrib, 1.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#define SDF_MAX_LENGTH 16384.0
+
+#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK)
+uniform lowp sampler2D src_pixels;//texunit:0
+#else
+uniform highp isampler2D src_process;//texunit:0
+#endif
+
+uniform ivec2 size;
+uniform int stride;
+uniform int shift;
+uniform ivec2 base_size;
+
+#if defined(MODE_LOAD) || defined(MODE_LOAD_SHRINK) || defined(MODE_PROCESS)
+layout(location = 0) out ivec4 distance_field;
+#else
+layout(location = 0) out vec4 distance_field;
+#endif
+
+vec4 float_to_vec4(float p_float) {
+ highp vec4 comp = fract(p_float * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
+ comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
+ return comp;
+}
+
+void main() {
+ ivec2 pos = ivec2(gl_FragCoord.xy);
+
+#ifdef MODE_LOAD
+
+ bool solid = texelFetch(src_pixels, pos, 0).r > 0.5;
+ distance_field = solid ? ivec4(ivec2(-32767), 0, 0) : ivec4(ivec2(32767), 0, 0);
+#endif
+
+#ifdef MODE_LOAD_SHRINK
+
+ int s = 1 << shift;
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = ivec2(32767);
+ float d = 1e20;
+ int found = 0;
+ int solid_found = 0;
+ for (int i = 0; i < s; i++) {
+ for (int j = 0; j < s; j++) {
+ ivec2 src_pos = base + ivec2(i, j);
+ if (any(greaterThanEqual(src_pos, base_size))) {
+ continue;
+ }
+ bool solid = texelFetch(src_pixels, src_pos, 0).r > 0.5;
+ if (solid) {
+ float dist = length(vec2(src_pos - center));
+ if (dist < d) {
+ d = dist;
+ rel = src_pos;
+ }
+ solid_found++;
+ }
+ found++;
+ }
+ }
+
+ if (solid_found == found) {
+ //mark solid only if all are solid
+ rel = ivec2(-32767);
+ }
+
+ distance_field = ivec4(rel, 0, 0);
+#endif
+
+#ifdef MODE_PROCESS
+
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ if (center != rel) {
+ //only process if it does not point to itself
+ const int ofs_table_size = 8;
+ const ivec2 ofs_table[ofs_table_size] = ivec2[](
+ ivec2(-1, -1),
+ ivec2(0, -1),
+ ivec2(+1, -1),
+
+ ivec2(-1, 0),
+ ivec2(+1, 0),
+
+ ivec2(-1, +1),
+ ivec2(0, +1),
+ ivec2(+1, +1));
+
+ float dist = length(vec2(rel - center));
+ for (int i = 0; i < ofs_table_size; i++) {
+ ivec2 src_pos = pos + ofs_table[i] * stride;
+ if (any(lessThan(src_pos, ivec2(0))) || any(greaterThanEqual(src_pos, size))) {
+ continue;
+ }
+ ivec2 src_rel = texelFetch(src_process, src_pos, 0).xy;
+ bool src_solid = src_rel.x < 0;
+ if (src_solid) {
+ src_rel = -src_rel - ivec2(1);
+ }
+
+ if (src_solid != solid) {
+ src_rel = ivec2(src_pos << shift); //point to itself if of different type
+ }
+
+ float src_dist = length(vec2(src_rel - center));
+ if (src_dist < dist) {
+ dist = src_dist;
+ rel = src_rel;
+ }
+ }
+ }
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ distance_field = ivec4(rel, 0, 0);
+#endif
+
+#ifdef MODE_STORE
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ float d = length(vec2(rel - pos));
+
+ if (solid) {
+ d = -d;
+ }
+
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, -1.0, 1.0);
+ distance_field = float_to_vec4(d*0.5+0.5);
+
+#endif
+
+#ifdef MODE_STORE_SHRINK
+
+ ivec2 base = pos << shift;
+ ivec2 center = base + ivec2(shift);
+
+ ivec2 rel = texelFetch(src_process, pos, 0).xy;
+
+ bool solid = rel.x < 0;
+
+ if (solid) {
+ rel = -rel - ivec2(1);
+ }
+
+ float d = length(vec2(rel - center));
+
+ if (solid) {
+ d = -d;
+ }
+ d /= SDF_MAX_LENGTH;
+ d = clamp(d, -1.0, 1.0);
+ distance_field = float_to_vec4(d*0.5+0.5);
+
+#endif
+}
diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl
deleted file mode 100644
index 94485abd11..0000000000
--- a/drivers/gles3/shaders/canvas_shadow.glsl
+++ /dev/null
@@ -1,60 +0,0 @@
-/* clang-format off */
-[vertex]
-
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
-
-layout(location = 0) in highp vec3 vertex;
-
-uniform highp mat4 projection_matrix;
-/* clang-format on */
-uniform highp mat4 light_matrix;
-uniform highp mat4 model_matrix;
-uniform highp float distance_norm;
-
-out highp vec4 position_interp;
-
-void main() {
- gl_Position = projection_matrix * (light_matrix * (model_matrix * vec4(vertex, 1.0)));
- position_interp = gl_Position;
-}
-
-/* clang-format off */
-[fragment]
-
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-#if defined(USE_HIGHP_PRECISION)
-precision highp float;
-precision highp int;
-#else
-precision mediump float;
-precision mediump int;
-#endif
-#endif
-
-in highp vec4 position_interp;
-/* clang-format on */
-
-void main() {
- highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
-
-#ifdef USE_RGBA_SHADOWS
-
- highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0));
- comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
- frag_color = comp;
-#else
-
- frag_color = vec4(depth);
-#endif
-}
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index 6b65e09cbf..dd5ebecb1a 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -82,6 +82,7 @@ layout(std140) uniform CanvasData { //ubo:0
uint pad2;
};
+#ifndef DISABLE_LIGHTING
#define LIGHT_FLAGS_BLEND_MASK uint(3 << 16)
#define LIGHT_FLAGS_BLEND_MODE_ADD uint(0 << 16)
#define LIGHT_FLAGS_BLEND_MODE_SUB uint(1 << 16)
@@ -94,6 +95,27 @@ layout(std140) uniform CanvasData { //ubo:0
#define LIGHT_FLAGS_SHADOW_PCF5 uint(1 << 22)
#define LIGHT_FLAGS_SHADOW_PCF13 uint(2 << 22)
+struct Light {
+ mat2x4 texture_matrix; //light to texture coordinate matrix (transposed)
+ mat2x4 shadow_matrix; //light to shadow coordinate matrix (transposed)
+ vec4 color;
+
+ uint shadow_color; // packed
+ uint flags; //index to light texture
+ float shadow_pixel_size;
+ float height;
+
+ vec2 position;
+ float shadow_zfar_inv;
+ float shadow_y_ofs;
+
+ vec4 atlas_rect;
+};
+
+layout(std140) uniform LightData { //ubo:2
+ Light light_array[MAX_LIGHTS];
+};
+#endif // DISABLE_LIGHTING
layout(std140) uniform DrawDataInstances { //ubo:3
DrawData draw_data[MAX_DRAW_DATA_INSTANCES];
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index ca2fc7e36d..796ba79c2e 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -2,7 +2,7 @@
#[modes]
mode_default = #define MODE_SIMPLE_COPY
-mode_copy_section = #define USE_COPY_SECTION
+mode_copy_section = #define USE_COPY_SECTION \n#define MODE_SIMPLE_COPY
mode_gaussian_blur = #define MODE_GAUSSIAN_BLUR
mode_mipmap = #define MODE_MIPMAP
mode_simple_color = #define MODE_SIMPLE_COLOR \n#define USE_COPY_SECTION
@@ -25,8 +25,7 @@ void main() {
gl_Position = vec4(vertex_attrib, 1.0, 1.0);
#ifdef USE_COPY_SECTION
- gl_Position.xy = (copy_section.xy + (uv_interp.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
- uv_interp = copy_section.xy + uv_interp * copy_section.zw;
+ gl_Position.xy = (copy_section.xy + uv_interp.xy * copy_section.zw) * 2.0 - 1.0;
#endif
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index efd6036ba9..ed176c7829 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -16,6 +16,7 @@ DISABLE_LIGHT_OMNI = false
DISABLE_LIGHT_SPOT = false
DISABLE_FOG = false
USE_RADIANCE_MAP = true
+USE_MULTIVIEW = false
#[vertex]
@@ -153,6 +154,15 @@ layout(std140) uniform SceneData { // ubo:2
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
uniform highp mat4 world_transform;
#ifdef USE_LIGHTMAP
@@ -250,8 +260,14 @@ void main() {
#if defined(OVERRIDE_POSITION)
highp vec4 position;
#endif
- highp mat4 projection_matrix = scene_data.projection_matrix;
- highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+
+#ifdef USE_MULTIVIEW
+ mat4 projection_matrix = multiview_data.projection_matrix_view[ViewIndex];
+ mat4 inv_projection_matrix = multiview_data.inv_projection_matrix_view[ViewIndex];
+#else
+ mat4 projection_matrix = scene_data.projection_matrix;
+ mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
+#endif //USE_MULTIVIEW
#ifdef USE_INSTANCING
vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w));
@@ -339,7 +355,6 @@ void main() {
/* clang-format off */
#[fragment]
-
// Default to SPECULAR_SCHLICK_GGX.
#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
#define SPECULAR_SCHLICK_GGX
@@ -463,6 +478,15 @@ layout(std140) uniform SceneData { // ubo:2
}
scene_data;
+#ifdef USE_MULTIVIEW
+layout(std140) uniform MultiviewData { // ubo:8
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+}
+multiview_data;
+#endif
+
/* clang-format off */
#GLOBALS
@@ -530,8 +554,13 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#endif // !defined(DISABLE_LIGHT_OMNI) && !defined(DISABLE_LIGHT_SPOT)
-uniform highp sampler2D screen_texture; // texunit:-5
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray depth_buffer; // texunit:-6
+uniform highp sampler2DArray screen_texture; // texunit:-5
+#else
uniform highp sampler2D depth_buffer; // texunit:-6
+uniform highp sampler2D screen_texture; // texunit:-5
+#endif
uniform highp mat4 world_transform;
uniform mediump float opaque_prepass_threshold;
@@ -884,7 +913,11 @@ vec4 fog_process(vec3 vertex) {
void main() {
//lay out everything, whatever is unused is optimized away anyway
vec3 vertex = vertex_interp;
+#ifdef USE_MULTIVIEW
+ vec3 view = -normalize(vertex_interp - multiview_data.eye_offset[ViewIndex].xyz);
+#else
vec3 view = -normalize(vertex_interp);
+#endif
vec3 albedo = vec3(1.0);
vec3 backlight = vec3(0.0);
vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
@@ -1096,9 +1129,15 @@ void main() {
#if defined(CUSTOM_IRRADIANCE_USED)
ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a);
#endif // CUSTOM_IRRADIANCE_USED
- ambient_light *= albedo.rgb;
- ambient_light *= ao;
+ {
+#if defined(AMBIENT_LIGHT_DISABLED)
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+#endif // AMBIENT_LIGHT_DISABLED
+ }
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl
index a478cf9170..0b769e77f2 100644
--- a/drivers/gles3/shaders/tonemap.glsl
+++ b/drivers/gles3/shaders/tonemap.glsl
@@ -44,7 +44,11 @@ in vec2 uv_interp;
layout(location = 0) out vec4 frag_color;
+#ifdef USE_MULTIVIEW
+uniform highp sampler2DArray source; //texunit:0
+#else
uniform highp sampler2D source; //texunit:0
+#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW // only use glow when at least one glow level is selected
@@ -191,10 +195,17 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
const float FXAA_REDUCE_MUL = (1.0 / 8.0);
const float FXAA_SPAN_MAX = 8.0;
+#ifdef USE_MULTIVIEW
+ vec3 rgbNW = textureLod(source, vec3(uv_interp + vec2(-1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbNE = textureLod(source, vec3(uv_interp + vec2(1.0, -1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSW = textureLod(source, vec3(uv_interp + vec2(-1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+ vec3 rgbSE = textureLod(source, vec3(uv_interp + vec2(1.0, 1.0) * pixel_size, ViewIndex), 0.0).xyz;
+#else
vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz;
vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz;
vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz;
+#endif
vec3 rgbM = color;
vec3 luma = vec3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
@@ -219,8 +230,13 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
dir * rcpDirMin)) *
pixel_size;
+#ifdef USE_MULTIVIEW
+ vec3 rgbA = 0.5 * (textureLod(source, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz);
+ vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz);
+#else
vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz);
vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz);
+#endif
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax)) {
@@ -231,7 +247,11 @@ vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) {
}
void main() {
+#ifdef USE_MULTIVIEW
+ vec4 color = textureLod(source, vec3(uv_interp, ViewIndex), 0.0);
+#else
vec4 color = textureLod(source, uv_interp, 0.0);
+#endif
#ifdef USE_FXAA
color.rgb = apply_fxaa(color.rgb, uv_interp, pixel_size);
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 6cc65e7bb2..9b496c0999 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -34,6 +34,15 @@
#include "core/config/project_settings.h"
#include "core/templates/vector.h"
+#ifdef ANDROID_ENABLED
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#include <GLES3/gl3platform.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
using namespace GLES3;
#define _GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
@@ -62,7 +71,7 @@ Config::Config() {
s3tc_supported = true;
rgtc_supported = true; //RGTC - core since OpenGL version 3.0
#else
- float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
+ float_texture_supported = extensions.has("GL_EXT_color_buffer_float");
etc2_supported = true;
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
// Some Android devices report support for S3TC but we don't expect that and don't export the textures.
@@ -75,27 +84,30 @@ Config::Config() {
rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
#endif
-#ifdef GLES_OVER_GL
- use_rgba_2d_shadows = false;
-#else
- use_rgba_2d_shadows = !(float_texture_supported && extensions.has("GL_EXT_texture_rg"));
-#endif
-
glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_uniform_buffer_size);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_viewport_size);
- // the use skeleton software path should be used if either float texture is not supported,
- // OR max_vertex_texture_image_units is zero
- use_skeleton_software = (float_texture_supported == false) || (max_vertex_texture_image_units == 0);
+ glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_offset_alignment);
support_anisotropic_filter = extensions.has("GL_EXT_texture_filter_anisotropic");
if (support_anisotropic_filter) {
glGetFloatv(_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic_level);
- anisotropic_level = MIN(float(1 << int(ProjectSettings::get_singleton()->get("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
+ anisotropic_level = MIN(float(1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"))), anisotropic_level);
}
+ multiview_supported = extensions.has("GL_OVR_multiview2") || extensions.has("GL_OVR_multiview");
+#ifdef ANDROID_ENABLED
+ if (multiview_supported) {
+ eglFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)eglGetProcAddress("glFramebufferTextureMultiviewOVR");
+ if (eglFramebufferTextureMultiviewOVR == nullptr) {
+ multiview_supported = false;
+ }
+ }
+#endif
+
force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index b83c83f425..87202fde84 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -44,6 +44,10 @@
#include OPENGL_INCLUDE_H
#endif
+#ifdef ANDROID_ENABLED
+typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
+#endif
+
namespace GLES3 {
class Config {
@@ -52,18 +56,19 @@ private:
public:
bool use_nearest_mip_filter = false;
- bool use_skeleton_software = false;
bool use_depth_prepass = true;
- bool use_rgba_2d_shadows = false;
int max_vertex_texture_image_units = 0;
int max_texture_image_units = 0;
int max_texture_size = 0;
+ int max_viewport_size[2] = { 0, 0 };
int max_uniform_buffer_size = 0;
int max_renderable_elements = 0;
int max_renderable_lights = 0;
int max_lights_per_object = 0;
+ int uniform_buffer_offset_alignment = 0;
+
// TODO implement wireframe in OpenGL
// bool generate_wireframes;
@@ -80,6 +85,11 @@ public:
bool support_anisotropic_filter = false;
float anisotropic_level = 0.0f;
+ bool multiview_supported = false;
+#ifdef ANDROID_ENABLED
+ PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
+#endif
+
static Config *get_singleton() { return singleton; };
Config();
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 6411590aee..b6bd4a2760 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -333,6 +333,46 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
ERR_FAIL_V(AABB());
}
+/* LIGHT INSTANCE API */
+
+RID LightStorage::light_instance_create(RID p_light) {
+ RID li = light_instance_owner.make_rid(LightInstance());
+
+ LightInstance *light_instance = light_instance_owner.get_or_null(li);
+
+ light_instance->self = li;
+ light_instance->light = p_light;
+ light_instance->light_type = light_get_type(p_light);
+
+ return li;
+}
+
+void LightStorage::light_instance_free(RID p_light_instance) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+ light_instance_owner.free(p_light_instance);
+}
+
+void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
+}
+
+void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->aabb = p_aabb;
+}
+
+void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+}
+
+void LightStorage::light_instance_mark_visible(RID p_light_instance) {
+}
+
/* PROBE API */
RID LightStorage::reflection_probe_allocate() {
@@ -419,6 +459,53 @@ float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
return 0.0;
}
+/* REFLECTION ATLAS */
+
+RID LightStorage::reflection_atlas_create() {
+ return RID();
+}
+
+void LightStorage::reflection_atlas_free(RID p_ref_atlas) {
+}
+
+int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
+ return 0;
+}
+
+void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+}
+
+/* REFLECTION PROBE INSTANCE */
+
+RID LightStorage::reflection_probe_instance_create(RID p_probe) {
+ return RID();
+}
+
+void LightStorage::reflection_probe_instance_free(RID p_instance) {
+}
+
+void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+}
+
+void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
+}
+
+bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
+ return false;
+}
+
+bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
+ return false;
+}
+
+bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
+ return false;
+}
+
+bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
+ return true;
+}
+
/* LIGHTMAP CAPTURE */
RID LightStorage::lightmap_allocate() {
@@ -484,6 +571,18 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const {
return 0;
}
+/* LIGHTMAP INSTANCE */
+
+RID LightStorage::lightmap_instance_create(RID p_lightmap) {
+ return RID();
+}
+
+void LightStorage::lightmap_instance_free(RID p_lightmap) {
+}
+
+void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+}
+
/* LIGHT SHADOW MAPPING */
/*
@@ -584,4 +683,36 @@ void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const Poo
}
*/
+/* SHADOW ATLAS API */
+
+RID LightStorage::shadow_atlas_create() {
+ return RID();
+}
+
+void LightStorage::shadow_atlas_free(RID p_atlas) {
+}
+
+void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
+}
+
+void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+}
+
+bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+ return false;
+}
+
+void LightStorage::shadow_atlas_update(RID p_atlas) {
+}
+
+void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+}
+
+int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
+ return 0;
+}
+
+void LightStorage::set_directional_shadow_count(int p_count) {
+}
+
#endif // !GLES3_ENABLED
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 8b708116ac..12cb2c4393 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -76,6 +76,33 @@ struct Light {
Dependency dependency;
};
+/* Light instance */
+struct LightInstance {
+ RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+ AABB aabb;
+ RID self;
+ RID light;
+ Transform3D transform;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att = 0.0;
+
+ uint64_t shadow_pass = 0;
+ uint64_t last_scene_pass = 0;
+ uint64_t last_scene_shadow_pass = 0;
+ uint64_t last_pass = 0;
+ uint32_t cull_mask = 0;
+ uint32_t light_directional_index = 0;
+
+ Rect2 directional_rect;
+
+ uint32_t gl_id = -1;
+
+ LightInstance() {}
+};
+
/* REFLECTION PROBE */
struct ReflectionProbe {
@@ -128,6 +155,9 @@ private:
/* LIGHT */
mutable RID_Owner<Light, true> light_owner;
+ /* Light instance */
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
/* REFLECTION PROBE */
mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
@@ -268,6 +298,28 @@ public:
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
virtual uint64_t light_get_version(RID p_light) const override;
+ /* LIGHT INSTANCE API */
+
+ LightInstance *get_light_instance(RID p_rid) { return light_instance_owner.get_or_null(p_rid); };
+ bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+
+ virtual RID light_instance_create(RID p_light) override;
+ virtual void light_instance_free(RID p_light_instance) override;
+
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+ virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
+ virtual void light_instance_mark_visible(RID p_light_instance) override;
+
+ _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->light_type;
+ }
+ _FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->gl_id;
+ }
+
/* PROBE API */
virtual RID reflection_probe_allocate() override;
@@ -298,6 +350,24 @@ public:
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override;
virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
+ /* REFLECTION ATLAS */
+
+ virtual RID reflection_atlas_create() override;
+ virtual void reflection_atlas_free(RID p_ref_atlas) override;
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ virtual RID reflection_probe_instance_create(RID p_probe) override;
+ virtual void reflection_probe_instance_free(RID p_instance) override;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
+
/* LIGHTMAP CAPTURE */
Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); };
@@ -338,6 +408,26 @@ public:
RID canvas_light_occluder_create();
void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
*/
+
+ /* LIGHTMAP INSTANCE */
+
+ virtual RID lightmap_instance_create(RID p_lightmap) override;
+ virtual void lightmap_instance_free(RID p_lightmap) override;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
+
+ /* SHADOW ATLAS API */
+
+ virtual RID shadow_atlas_create() override;
+ virtual void shadow_atlas_free(RID p_atlas) override;
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
+
+ virtual void shadow_atlas_update(RID p_atlas) override;
+
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+ virtual void set_directional_shadow_count(int p_count) override;
};
} // namespace GLES3
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index d9a797778c..6748eb3676 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -89,7 +89,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = v & 1 ? 1 : 0;
gui[1] = v & 2 ? 1 : 0;
}
@@ -116,7 +116,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -145,7 +145,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
}
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -714,7 +714,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
Projection v = value;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- gui[i * 4 + j] = v.matrix[i][j];
+ gui[i * 4 + j] = v.columns[i][j];
}
}
}
@@ -728,7 +728,7 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type,
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
- *gui = value[0].boolean ? 1 : 0;
+ gui[0] = value[0].boolean ? 1 : 0;
} break;
case ShaderLanguage::TYPE_BVEC2: {
uint32_t *gui = (uint32_t *)data;
@@ -897,7 +897,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
case ShaderLanguage::TYPE_UVEC3:
- case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_VEC3: {
+ memset(data, 0, 12 * p_array_size);
+ } break;
case ShaderLanguage::TYPE_BVEC4:
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
@@ -1393,7 +1395,7 @@ MaterialStorage::MaterialStorage() {
actions.renames["NORMAL_MAP"] = "normal_map";
actions.renames["NORMAL_MAP_DEPTH"] = "normal_map_depth";
actions.renames["TEXTURE"] = "color_texture";
- actions.renames["TEXTURE_PIXEL_SIZE"] = "draw_data.color_texture_pixel_size";
+ actions.renames["TEXTURE_PIXEL_SIZE"] = "color_texture_pixel_size";
actions.renames["NORMAL_TEXTURE"] = "normal_texture";
actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
@@ -2212,7 +2214,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
for (const PropertyInfo &E : settings) {
if (E.name.begins_with("shader_globals/")) {
StringName name = E.name.get_slice("/", 1);
- Dictionary d = ProjectSettings::get_singleton()->get(E.name);
+ Dictionary d = GLOBAL_GET(E.name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
@@ -2312,7 +2314,7 @@ void MaterialStorage::global_shader_parameters_instance_free(RID p_instance) {
global_shader_uniforms.instance_buffer_pos.erase(p_instance);
}
-void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count) {
if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
@@ -2322,7 +2324,9 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
return; //again, not allocated, ignore
}
ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
- ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ Variant::Type value_type = p_value.get_type();
+ ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
ShaderLanguage::TYPE_MAX, //nil
@@ -2348,9 +2352,24 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
ShaderLanguage::TYPE_VEC4 //color
};
- ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
+ ShaderLanguage::DataType datatype = ShaderLanguage::TYPE_MAX;
+ if (value_type == Variant::INT && p_flags_count > 0) {
+ switch (p_flags_count) {
+ case 1:
+ datatype = ShaderLanguage::TYPE_BVEC2;
+ break;
+ case 2:
+ datatype = ShaderLanguage::TYPE_BVEC3;
+ break;
+ case 3:
+ datatype = ShaderLanguage::TYPE_BVEC4;
+ break;
+ }
+ } else {
+ datatype = datatype_from_value[value_type];
+ }
- ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+ ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
pos += p_index;
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 65c46631ed..24d9a0fee1 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -494,7 +494,7 @@ public:
static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ p_array[i * 4 + j] = p_mtx.columns[i][j];
}
}
}
@@ -530,7 +530,7 @@ public:
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
virtual void global_shader_parameters_instance_free(RID p_instance) override;
- virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override;
GLuint global_shader_parameters_get_uniform_buffer() const;
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 22d84eba93..9ec0fc0286 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -309,12 +309,48 @@ RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
}
void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->vertex_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->attribute_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->attribute_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
+ ERR_FAIL_COND(p_data.size() == 0);
+
+ uint64_t data_size = p_data.size();
+ ERR_FAIL_COND(p_offset + data_size > mesh->surfaces[p_surface]->skin_buffer_size);
+ const uint8_t *r = p_data.ptr();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->skin_buffer);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, data_size, r);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
@@ -968,7 +1004,7 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
#define MULTIMESH_DIRTY_REGION_SIZE 512
void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
- if (multimesh->data_cache.size() > 0) {
+ if (multimesh->data_cache.size() > 0 || multimesh->instances == 0) {
return; //already local
}
ERR_FAIL_COND(multimesh->data_cache.size() > 0);
@@ -1385,7 +1421,7 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Vector<float>());
Vector<float> ret;
- if (multimesh->buffer == 0) {
+ if (multimesh->buffer == 0 || multimesh->instances == 0) {
return Vector<float>();
} else if (multimesh->data_cache.size()) {
ret = multimesh->data_cache;
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 74f5800795..a31db24f2d 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -325,13 +325,12 @@ public:
return s->index_count ? s->index_count : s->vertex_count;
}
- _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t *r_index_count = nullptr) const {
+ _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
int32_t current_lod = -1;
- if (r_index_count) {
- *r_index_count = s->index_count;
- }
+ r_index_count = s->index_count;
+
for (uint32_t i = 0; i < s->lod_count; i++) {
float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
if (screen_size > p_mesh_lod_threshold) {
@@ -342,9 +341,7 @@ public:
if (current_lod == -1) {
return 0;
} else {
- if (r_index_count) {
- *r_index_count = s->lods[current_lod].index_count;
- }
+ r_index_count = s->lods[current_lod].index_count;
return current_lod + 1;
}
}
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 9123984dc7..b8e4530f56 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -33,12 +33,17 @@
#include "render_scene_buffers_gles3.h"
#include "texture_storage.h"
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#endif
+
RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
@@ -50,7 +55,7 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
//msaa = p_msaa;
//screen_space_aa = p_screen_space_aa;
//use_debanding = p_use_debanding;
- //view_count = p_view_count;
+ view_count = p_view_count;
free_render_buffer_data();
@@ -62,24 +67,43 @@ void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_inte
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- glBindTexture(GL_TEXTURE_2D, rt->color);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ if (view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, view_count);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ }
glGenTextures(1, &depth_texture);
- glBindTexture(GL_TEXTURE_2D, depth_texture);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, depth_texture);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, view_count, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, depth_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
+ if (view_count > 1 && config->multiview_supported) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture, 0, 0, view_count);
+ } else {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);
+ }
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
glBindTexture(GL_TEXTURE_2D, 0);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glBindFramebuffer(GL_FRAMEBUFFER, texture_storage->system_fbo);
if (status != GL_FRAMEBUFFER_COMPLETE) {
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index ad0d2032b0..dbedbd22c3 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -56,7 +56,7 @@ public:
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
//RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
//bool use_debanding = false;
- //uint32_t view_count = 1;
+ uint32_t view_count = 1;
bool is_transparent = false;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index e18c0ec649..11151c4100 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -34,6 +34,10 @@
#include "config.h"
#include "drivers/gles3/effects/copy_effects.h"
+#ifdef ANDROID_ENABLED
+#define glFramebufferTextureMultiviewOVR GLES3::Config::get_singleton()->eglFramebufferTextureMultiviewOVR
+#endif
+
using namespace GLES3;
TextureStorage *TextureStorage::singleton = nullptr;
@@ -59,9 +63,7 @@ TextureStorage::TextureStorage() {
{ //create default textures
{ // White Textures
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1, 1, 1, 1));
image->generate_mipmaps();
@@ -90,9 +92,7 @@ TextureStorage::TextureStorage() {
}
{ // black
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0, 0, 0, 1));
image->generate_mipmaps();
@@ -116,9 +116,7 @@ TextureStorage::TextureStorage() {
}
{ // transparent black
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0, 0, 0, 0));
image->generate_mipmaps();
@@ -127,9 +125,7 @@ TextureStorage::TextureStorage() {
}
{
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0.5, 0.5, 1, 1));
image->generate_mipmaps();
@@ -138,9 +134,7 @@ TextureStorage::TextureStorage() {
}
{
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, true, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1.0, 0.5, 1, 1));
image->generate_mipmaps();
@@ -197,6 +191,27 @@ TextureStorage::TextureStorage() {
glBindTexture(GL_TEXTURE_2D, 0);
+ { // Atlas Texture initialize.
+ uint8_t pixel_data[4 * 4 * 4];
+ for (int i = 0; i < 16; i++) {
+ pixel_data[i * 4 + 0] = 0;
+ pixel_data[i * 4 + 1] = 0;
+ pixel_data[i * 4 + 2] = 0;
+ pixel_data[i * 4 + 3] = 255;
+ }
+
+ glGenTextures(1, &texture_atlas.texture);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ {
+ sdf_shader.shader.initialize();
+ sdf_shader.shader_version = sdf_shader.shader.version_create();
+ }
+
#ifdef GLES_OVER_GL
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
@@ -207,6 +222,12 @@ TextureStorage::~TextureStorage() {
for (int i = 0; i < DEFAULT_GL_TEXTURE_MAX; i++) {
texture_free(default_gl_textures[i]);
}
+
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ sdf_shader.shader.version_free(sdf_shader.shader_version);
}
//TODO, move back to storage
@@ -261,55 +282,6 @@ void TextureStorage::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS:
ct->texture_repeat = p_repeat;
}
-/* CANVAS SHADOW */
-
-RID TextureStorage::canvas_light_shadow_buffer_create(int p_width) {
- Config *config = Config::get_singleton();
- CanvasLightShadow *cls = memnew(CanvasLightShadow);
-
- if (p_width > config->max_texture_size) {
- p_width = config->max_texture_size;
- }
-
- cls->size = p_width;
- cls->height = 16;
-
- glActiveTexture(GL_TEXTURE0);
-
- glGenFramebuffers(1, &cls->fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo);
-
- glGenRenderbuffers(1, &cls->depth);
- glBindRenderbuffer(GL_RENDERBUFFER, cls->depth);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, cls->size, cls->height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth);
-
- glGenTextures(1, &cls->distance);
- glBindTexture(GL_TEXTURE_2D, cls->distance);
- if (config->use_rgba_2d_shadows) {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- } else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, GL_RED, GL_FLOAT, nullptr);
- }
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0);
-
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- //printf("errnum: %x\n",status);
- glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
-
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- memdelete(cls);
- ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
- }
-
- return canvas_light_shadow_owner.make_rid(cls);
-}
-
/* Texture API */
Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const {
@@ -653,7 +625,7 @@ void TextureStorage::texture_free(RID p_texture) {
}
}
- //decal_atlas_remove_texture(p_texture);
+ texture_atlas_remove_texture(p_texture);
for (int i = 0; i < t->proxies.size(); i++) {
Texture *p = texture_owner.get_or_null(t->proxies[i]);
@@ -709,8 +681,7 @@ void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
}
void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) {
- // only 1 layer so far
- texture_set_data(p_texture, p_image);
+ texture_set_data(p_texture, p_image, p_layer);
#ifdef TOOLS_ENABLED
Texture *tex = texture_owner.get_or_null(p_texture);
@@ -724,9 +695,7 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
texture_2d_initialize(p_texture, image);
@@ -735,9 +704,7 @@ void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -756,9 +723,7 @@ void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, Re
void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -782,6 +747,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
#ifdef GLES_OVER_GL
// OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+ // It also allows for reading compressed textures, mipmaps, and more formats.
Vector<uint8_t> data;
int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
@@ -812,16 +778,71 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
data.resize(data_size);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image;
- image.instantiate();
- image->create(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
+ Ref<Image> image = Image::create_from_data(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (texture->format != texture->real_format) {
image->convert(texture->format);
}
#else
- // Support for Web and Mobile will come later.
- Ref<Image> image;
+
+ Vector<uint8_t> data;
+
+ // On web and mobile we always read an RGBA8 image with no mipmaps.
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ uint8_t *w = data.ptrw();
+
+ GLuint temp_framebuffer;
+ glGenFramebuffers(1, &temp_framebuffer);
+
+ GLuint temp_color_texture;
+ glGenTextures(1, &temp_color_texture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
+
+ glBindTexture(GL_TEXTURE_2D, temp_color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture->tex_id);
+
+ glViewport(0, 0, texture->alloc_width, texture->alloc_height);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ CopyEffects::get_singleton()->copy_to_rect(Rect2i(0, 0, 1.0, 1.0));
+
+ glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteTextures(1, &temp_color_texture);
+ glDeleteFramebuffers(1, &temp_framebuffer);
+
+ data.resize(data_size);
+
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ Ref<Image> image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+
+ if (texture->format != Image::FORMAT_RGBA8) {
+ image->convert(texture->format);
+ }
+
+ if (texture->mipmaps > 1) {
+ image->generate_mipmaps();
+ }
+
#endif
#ifdef TOOLS_ENABLED
@@ -875,7 +896,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
//delete last, so proxies can be updated
texture_owner.free(p_by_texture);
- //decal_atlas_mark_dirty_on_texture(p_texture);
+ texture_atlas_mark_dirty_on_texture(p_texture);
}
void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
@@ -1009,7 +1030,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
img->resize_to_po2(false);
}
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : texture->target;
Vector<uint8_t> read = img->get_data();
@@ -1066,7 +1087,11 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
} else {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ if (texture->target == GL_TEXTURE_2D_ARRAY) {
+ glTexSubImage3D(GL_TEXTURE_2D_ARRAY, i, 0, 0, p_layer, w, h, 0, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
}
tsize += size;
@@ -1143,6 +1168,217 @@ RID TextureStorage::texture_create_radiance_cubemap(RID p_source, int p_resoluti
return RID();
}
+/* TEXTURE ATLAS API */
+
+void TextureStorage::texture_add_to_texture_atlas(RID p_texture) {
+ if (!texture_atlas.textures.has(p_texture)) {
+ TextureAtlas::Texture t;
+ t.users = 1;
+ texture_atlas.textures[p_texture] = t;
+ texture_atlas.dirty = true;
+ } else {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ t->users++;
+ }
+}
+
+void TextureStorage::texture_remove_from_texture_atlas(RID p_texture) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ ERR_FAIL_COND(!t);
+ t->users--;
+ if (t->users == 0) {
+ texture_atlas.textures.erase(p_texture);
+ // Do not mark it dirty, there is no need to since it remains working.
+ }
+}
+
+void TextureStorage::texture_atlas_mark_dirty_on_texture(RID p_texture) {
+ if (texture_atlas.textures.has(p_texture)) {
+ texture_atlas.dirty = true; // Mark it dirty since it was most likely modified.
+ }
+}
+
+void TextureStorage::texture_atlas_remove_texture(RID p_texture) {
+ if (texture_atlas.textures.has(p_texture)) {
+ texture_atlas.textures.erase(p_texture);
+ // There is not much a point of making it dirty, texture can be removed next time the atlas is updated.
+ }
+}
+
+GLuint TextureStorage::texture_atlas_get_texture() const {
+ return texture_atlas.texture;
+}
+
+void TextureStorage::update_texture_atlas() {
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
+ ERR_FAIL_NULL(copy_effects);
+
+ if (!texture_atlas.dirty) {
+ return; //nothing to do
+ }
+
+ texture_atlas.dirty = false;
+
+ if (texture_atlas.texture != 0) {
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ }
+
+ const int border = 2;
+
+ if (texture_atlas.textures.size()) {
+ //generate atlas
+ Vector<TextureAtlas::SortItem> itemsv;
+ itemsv.resize(texture_atlas.textures.size());
+ int base_size = 8;
+
+ int idx = 0;
+
+ for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) {
+ TextureAtlas::SortItem &si = itemsv.write[idx];
+
+ Texture *src_tex = get_texture(E.key);
+
+ si.size.width = (src_tex->width / border) + 1;
+ si.size.height = (src_tex->height / border) + 1;
+ si.pixel_size = Size2i(src_tex->width, src_tex->height);
+
+ if (base_size < si.size.width) {
+ base_size = nearest_power_of_2_templated(si.size.width);
+ }
+
+ si.texture = E.key;
+ idx++;
+ }
+
+ //sort items by size
+ itemsv.sort();
+
+ //attempt to create atlas
+ int item_count = itemsv.size();
+ TextureAtlas::SortItem *items = itemsv.ptrw();
+
+ int atlas_height = 0;
+
+ while (true) {
+ Vector<int> v_offsetsv;
+ v_offsetsv.resize(base_size);
+
+ int *v_offsets = v_offsetsv.ptrw();
+ memset(v_offsets, 0, sizeof(int) * base_size);
+
+ int max_height = 0;
+
+ for (int i = 0; i < item_count; i++) {
+ //best fit
+ TextureAtlas::SortItem &si = items[i];
+ int best_idx = -1;
+ int best_height = 0x7FFFFFFF;
+ for (int j = 0; j <= base_size - si.size.width; j++) {
+ int height = 0;
+ for (int k = 0; k < si.size.width; k++) {
+ int h = v_offsets[k + j];
+ if (h > height) {
+ height = h;
+ if (height > best_height) {
+ break; //already bad
+ }
+ }
+ }
+
+ if (height < best_height) {
+ best_height = height;
+ best_idx = j;
+ }
+ }
+
+ //update
+ for (int k = 0; k < si.size.width; k++) {
+ v_offsets[k + best_idx] = best_height + si.size.height;
+ }
+
+ si.pos.x = best_idx;
+ si.pos.y = best_height;
+
+ if (si.pos.y + si.size.height > max_height) {
+ max_height = si.pos.y + si.size.height;
+ }
+ }
+
+ if (max_height <= base_size * 2) {
+ atlas_height = max_height;
+ break; //good ratio, break;
+ }
+
+ base_size *= 2;
+ }
+
+ texture_atlas.size.width = base_size * border;
+ texture_atlas.size.height = nearest_power_of_2_templated(atlas_height * border);
+
+ for (int i = 0; i < item_count; i++) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(items[i].texture);
+ t->uv_rect.position = items[i].pos * border + Vector2i(border / 2, border / 2);
+ t->uv_rect.size = items[i].pixel_size;
+
+ t->uv_rect.position /= Size2(texture_atlas.size);
+ t->uv_rect.size /= Size2(texture_atlas.size);
+ }
+ } else {
+ texture_atlas.size.width = 4;
+ texture_atlas.size.height = 4;
+ }
+
+ { // Atlas Texture initialize.
+ // TODO validate texture atlas size with maximum texture size
+ glGenTextures(1, &texture_atlas.texture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_atlas.texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture_atlas.size.width, texture_atlas.size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+
+ glGenFramebuffers(1, &texture_atlas.framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, texture_atlas.framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_atlas.texture, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ glDeleteFramebuffers(1, &texture_atlas.framebuffer);
+ texture_atlas.framebuffer = 0;
+ glDeleteTextures(1, &texture_atlas.texture);
+ texture_atlas.texture = 0;
+ WARN_PRINT("Could not create texture atlas, status: " + get_framebuffer_error(status));
+ return;
+ }
+ glViewport(0, 0, texture_atlas.size.width, texture_atlas.size.height);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ glDisable(GL_BLEND);
+
+ if (texture_atlas.textures.size()) {
+ for (const KeyValue<RID, TextureAtlas::Texture> &E : texture_atlas.textures) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(E.key);
+ Texture *src_tex = get_texture(E.key);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, src_tex->tex_id);
+ copy_effects->copy_to_rect(t->uv_rect);
+ }
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
/* DECAL API */
RID TextureStorage::decal_allocate() {
@@ -1183,6 +1419,18 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
return AABB();
}
+/* DECAL INSTANCE API */
+
+RID TextureStorage::decal_instance_create(RID p_decal) {
+ return RID();
+}
+
+void TextureStorage::decal_instance_free(RID p_decal_instance) {
+}
+
+void TextureStorage::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
+}
+
/* RENDER TARGET API */
GLuint TextureStorage::system_fbo = 0;
@@ -1199,6 +1447,8 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
return;
}
+ Config *config = Config::get_singleton();
+
rt->color_internal_format = rt->is_transparent ? GL_RGBA8 : GL_RGB10_A2;
rt->color_format = GL_RGBA;
rt->color_type = rt->is_transparent ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_2_10_10_10_REV;
@@ -1220,17 +1470,29 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
// color
glGenTextures(1, &rt->color);
- glBindTexture(GL_TEXTURE_2D, rt->color);
-
- glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ if (rt->view_count > 1 && config->multiview_supported) {
+ glBindTexture(GL_TEXTURE_2D_ARRAY, rt->color);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, rt->color_internal_format, rt->size.x, rt->size.y, rt->view_count, 0, rt->color_format, rt->color_type, nullptr);
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ glBindTexture(GL_TEXTURE_2D, rt->color);
+ glTexImage2D(GL_TEXTURE_2D, 0, rt->color_internal_format, rt->size.x, rt->size.y, 0, rt->color_format, rt->color_type, nullptr);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ if (rt->view_count > 1 && config->multiview_supported) {
+ glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rt->color, 0, 0, rt->view_count);
+ } else {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0);
+ }
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -1249,8 +1511,15 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
texture->format = rt->image_format;
texture->real_format = rt->image_format;
- texture->type = Texture::TYPE_2D;
- texture->target = GL_TEXTURE_2D;
+ if (rt->view_count > 1 && config->multiview_supported) {
+ texture->type = Texture::TYPE_LAYERED;
+ texture->target = GL_TEXTURE_2D_ARRAY;
+ texture->layers = rt->view_count;
+ } else {
+ texture->type = Texture::TYPE_2D;
+ texture->target = GL_TEXTURE_2D;
+ texture->layers = 1;
+ }
texture->gl_format_cache = rt->color_format;
texture->gl_type_cache = GL_UNSIGNED_BYTE;
texture->gl_internal_format_cache = rt->color_internal_format;
@@ -1331,24 +1600,6 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->fbo = 0;
rt->color = 0;
}
- /*
- if (rt->external.fbo != 0) {
- // free this
- glDeleteFramebuffers(1, &rt->external.fbo);
-
- // clean up our texture
- Texture *t = get_texture(rt->external.texture);
- t->alloc_height = 0;
- t->alloc_width = 0;
- t->width = 0;
- t->height = 0;
- t->active = false;
- texture_free(rt->external.texture);
- memdelete(t);
-
- rt->external.fbo = 0;
- }
- */
Texture *tex = get_texture(rt->texture);
tex->alloc_height = 0;
@@ -1363,6 +1614,7 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
rt->backbuffer = 0;
rt->backbuffer_fbo = 0;
}
+ _render_target_clear_sdf(rt);
}
RID TextureStorage::render_target_create() {
@@ -1400,25 +1652,33 @@ void TextureStorage::render_target_set_position(RID p_render_target, int p_x, in
rt->position = Point2i(p_x, p_y);
}
+Point2i TextureStorage::render_target_get_position(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Point2i());
+
+ return rt->position;
+};
+
void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
- if (p_width == rt->size.x && p_height == rt->size.y) {
+ if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
return;
}
_clear_render_target(rt);
rt->size = Size2i(p_width, p_height);
+ rt->view_count = p_view_count;
_update_render_target(rt);
}
// TODO: convert to Size2i internally
-Size2i TextureStorage::render_target_get_size(RID p_render_target) {
+Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2());
+ ERR_FAIL_COND_V(!rt, Size2i());
return rt->size;
}
@@ -1427,105 +1687,7 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- if (rt->external.fbo == 0) {
- return rt->texture;
- } else {
- return rt->external.texture;
- }
-}
-
-void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
- RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
-
- if (p_texture_id == 0) {
- if (rt->external.fbo != 0) {
- // free this
- glDeleteFramebuffers(1, &rt->external.fbo);
-
- // and this
- if (rt->external.depth != 0) {
- glDeleteRenderbuffers(1, &rt->external.depth);
- }
-
- // clean up our texture
- Texture *t = get_texture(rt->external.texture);
- t->alloc_height = 0;
- t->alloc_width = 0;
- t->width = 0;
- t->height = 0;
- t->active = false;
- texture_free(rt->external.texture);
- //memdelete(t);
-
- rt->external.fbo = 0;
- rt->external.color = 0;
- rt->external.depth = 0;
- }
- } else {
- Texture *t;
-
- if (rt->external.fbo == 0) {
- // create our fbo
- glGenFramebuffers(1, &rt->external.fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
-
- // allocate a texture
- t = memnew(Texture);
-
- t->type = Texture::TYPE_2D;
- t->width = 0;
- t->height = 0;
- t->alloc_height = 0;
- t->alloc_width = 0;
- t->format = Image::FORMAT_RGBA8;
- t->target = GL_TEXTURE_2D;
- t->gl_format_cache = 0;
- t->gl_internal_format_cache = 0;
- t->gl_type_cache = 0;
- t->total_data_size = 0;
- t->mipmaps = 1;
- t->active = true;
- t->tex_id = 0;
- t->render_target = rt;
- t->is_render_target = true;
-
- //rt->external.texture = make_rid(t);
-
- } else {
- // bind our frame buffer
- glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo);
-
- // find our texture
- t = get_texture(rt->external.texture);
- }
-
- // set our texture
- t->tex_id = p_texture_id;
- rt->external.color = p_texture_id;
-
- // size shouldn't be different
- t->width = rt->size.x;
- t->height = rt->size.y;
- t->alloc_height = rt->size.x;
- t->alloc_width = rt->size.y;
-
- // Switch our texture on our frame buffer
- {
- // set our texture as the destination for our framebuffer
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
- }
-
- // check status and unbind
- GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
-
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- WARN_PRINT("framebuffer fail, status: " + get_framebuffer_error(status));
- }
-
- ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
- }
+ return rt->texture;
}
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
@@ -1538,6 +1700,13 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
_update_render_target(rt);
}
+bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->is_transparent;
+}
+
void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
@@ -1552,7 +1721,14 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
_update_render_target(rt);
}
-bool TextureStorage::render_target_was_used(RID p_render_target) {
+bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->direct_to_screen;
+}
+
+bool TextureStorage::render_target_was_used(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, false);
@@ -1579,6 +1755,13 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
_update_render_target(rt);
}
+RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED);
+
+ return rt->msaa;
+}
+
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
@@ -1609,19 +1792,279 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
if (!rt->clear_requested) {
return;
}
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
glClearBufferfv(GL_COLOR, 0, rt->clear_color.components);
rt->clear_requested = false;
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
}
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
+ return;
+ }
+
+ rt->sdf_oversize = p_size;
+ rt->sdf_scale = p_scale;
+
+ _render_target_clear_sdf(rt);
+}
+
+Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const {
+ Size2i margin;
+ int scale;
+ switch (rt->sdf_oversize) {
+ case RS::VIEWPORT_SDF_OVERSIZE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT: {
+ scale = 120;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_150_PERCENT: {
+ scale = 150;
+ } break;
+ case RS::VIEWPORT_SDF_OVERSIZE_200_PERCENT: {
+ scale = 200;
+ } break;
+ default: {
+ }
+ }
+
+ margin = (rt->size * scale / 100) - rt->size;
+
+ Rect2i r(Vector2i(), rt->size);
+ r.position -= margin;
+ r.size += margin * 2;
+
+ return r;
}
Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
- return Rect2i();
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Rect2i());
+
+ return _render_target_get_sdf_rect(rt);
}
void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->sdf_enabled = p_enabled;
+}
+
+bool TextureStorage::render_target_is_sdf_enabled(RID p_render_target) const {
+ const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->sdf_enabled;
+}
+
+GLuint TextureStorage::render_target_get_sdf_texture(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, 0);
+ if (rt->sdf_texture_read == 0) {
+ Texture *texture = texture_owner.get_or_null(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK]);
+ return texture->tex_id;
+ }
+
+ return rt->sdf_texture_read;
+}
+
+void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
+ ERR_FAIL_COND(rt->sdf_texture_write_fb != 0);
+
+ Size2i size = _render_target_get_sdf_rect(rt).size;
+
+ glGenTextures(1, &rt->sdf_texture_write);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, size.width, size.height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenFramebuffers(1, &rt->sdf_texture_write_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, rt->sdf_texture_write_fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_write, 0);
+
+ int scale;
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_100_PERCENT: {
+ scale = 100;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ scale = 50;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ scale = 25;
+ } break;
+ default: {
+ scale = 100;
+ } break;
+ }
+
+ rt->process_size = size * scale / 100;
+ rt->process_size.x = MAX(rt->process_size.x, 1);
+ rt->process_size.y = MAX(rt->process_size.y, 1);
+
+ glGenTextures(2, rt->sdf_texture_process);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[1]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16I, rt->process_size.width, rt->process_size.height, 0, GL_RG_INTEGER, GL_SHORT, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenTextures(1, &rt->sdf_texture_read);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_read);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, rt->process_size.width, rt->process_size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
+ if (rt->sdf_texture_write_fb != 0) {
+ glDeleteTextures(1, &rt->sdf_texture_read);
+ glDeleteTextures(1, &rt->sdf_texture_write);
+ glDeleteTextures(2, rt->sdf_texture_process);
+ glDeleteFramebuffers(1, &rt->sdf_texture_write_fb);
+ rt->sdf_texture_read = 0;
+ rt->sdf_texture_write = 0;
+ rt->sdf_texture_process[0] = 0;
+ rt->sdf_texture_process[1] = 0;
+ rt->sdf_texture_write_fb = 0;
+ }
+}
+
+GLuint TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, 0);
+
+ if (rt->sdf_texture_write_fb == 0) {
+ _render_target_allocate_sdf(rt);
+ }
+
+ return rt->sdf_texture_write_fb;
+}
+void TextureStorage::render_target_sdf_process(RID p_render_target) {
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
+
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND(rt->sdf_texture_write_fb == 0);
+
+ Rect2i r = _render_target_get_sdf_rect(rt);
+
+ Size2i size = r.size;
+ int32_t shift = 0;
+
+ bool shrink = false;
+
+ switch (rt->sdf_scale) {
+ case RS::VIEWPORT_SDF_SCALE_50_PERCENT: {
+ size[0] >>= 1;
+ size[1] >>= 1;
+ shift = 1;
+ shrink = true;
+ } break;
+ case RS::VIEWPORT_SDF_SCALE_25_PERCENT: {
+ size[0] >>= 2;
+ size[1] >>= 2;
+ shift = 2;
+ shrink = true;
+ } break;
+ default: {
+ };
+ }
+
+ GLuint temp_fb;
+ glGenFramebuffers(1, &temp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_fb);
+
+ // Load
+ CanvasSdfShaderGLES3::ShaderVariant variant = shrink ? CanvasSdfShaderGLES3::MODE_LOAD_SHRINK : CanvasSdfShaderGLES3::MODE_LOAD;
+ sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, 0, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_write);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[0], 0);
+ glViewport(0, 0, size.width, size.height);
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, size.width, size.height);
+
+ copy_effects->draw_screen_triangle();
+
+ // Process
+
+ int stride = nearest_power_of_2_templated(MAX(size.width, size.height) / 2);
+
+ variant = CanvasSdfShaderGLES3::MODE_PROCESS;
+ sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ bool swap = false;
+
+ //jumpflood
+ while (stride > 0) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 0 : 1], 0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
+
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+
+ copy_effects->draw_screen_triangle();
+
+ stride /= 2;
+ swap = !swap;
+ }
+
+ // Store
+ variant = shrink ? CanvasSdfShaderGLES3::MODE_STORE_SHRINK : CanvasSdfShaderGLES3::MODE_STORE;
+ sdf_shader.shader.version_bind_shader(sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::BASE_SIZE, r.size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SIZE, size, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::STRIDE, stride, sdf_shader.shader_version, variant);
+ sdf_shader.shader.version_set_uniform(CanvasSdfShaderGLES3::SHIFT, shift, sdf_shader.shader_version, variant);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->sdf_texture_read, 0);
+ glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[swap ? 1 : 0]);
+
+ copy_effects->draw_screen_triangle();
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, system_fbo);
+ glDeleteFramebuffers(1, &temp_fb);
+ glDisable(GL_SCISSOR_TEST);
}
void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 4f4032723b..0b025c4370 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -39,6 +39,8 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering/storage/texture_storage.h"
+#include "../shaders/canvas_sdf.glsl.gen.h"
+
// This must come first to avoid windows.h mess
#include "platform_config.h"
#ifndef OPENGL_INCLUDE_H
@@ -84,18 +86,8 @@ namespace GLES3 {
#define _GL_TEXTURE_EXTERNAL_OES 0x8D65
-#ifdef GLES_OVER_GL
-#define _GL_HALF_FLOAT_OES 0x140B
-#else
-#define _GL_HALF_FLOAT_OES 0x8D61
-#endif
-
#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
-#define _RED_OES 0x1903
-
-#define _DEPTH_COMPONENT24_OES 0x81A6
-
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif //!GLES_OVER_GL
@@ -126,22 +118,6 @@ struct CanvasTexture {
RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
-
- Size2i size_cache = Size2i(1, 1);
- bool use_normal_cache = false;
- bool use_specular_cache = false;
- bool cleared_cache = true;
-};
-
-/* CANVAS SHADOW */
-
-struct CanvasLightShadow {
- RID self;
- int size;
- int height;
- GLuint fbo;
- GLuint depth;
- GLuint distance; //for older devices
};
struct RenderTarget;
@@ -327,18 +303,9 @@ private:
};
struct RenderTarget {
- struct External {
- GLuint fbo = 0;
- GLuint color = 0;
- GLuint depth = 0;
- RID texture;
-
- External() {
- }
- } external;
-
Point2i position = Point2i(0, 0);
Size2i size = Size2i(0, 0);
+ uint32_t view_count = 1;
int mipmap_count = 1;
RID self;
GLuint fbo = 0;
@@ -351,6 +318,15 @@ struct RenderTarget {
GLuint color_type = GL_UNSIGNED_BYTE;
Image::Format image_format = Image::FORMAT_RGBA8;
+ GLuint sdf_texture_write = 0;
+ GLuint sdf_texture_write_fb = 0;
+ GLuint sdf_texture_process[2] = { 0, 0 };
+ GLuint sdf_texture_read = 0;
+ RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
+ RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
+ Size2i process_size;
+ bool sdf_enabled = false;
+
bool is_transparent = false;
bool direct_to_screen = false;
@@ -376,16 +352,44 @@ private:
RID_Owner<CanvasTexture, true> canvas_texture_owner;
- /* CANVAS SHADOW */
-
- RID_PtrOwner<CanvasLightShadow> canvas_light_shadow_owner;
-
/* Texture API */
mutable RID_Owner<Texture> texture_owner;
Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const;
+ /* TEXTURE ATLAS API */
+
+ struct TextureAtlas {
+ struct Texture {
+ int users;
+ Rect2 uv_rect;
+ };
+
+ struct SortItem {
+ RID texture;
+ Size2i pixel_size;
+ Size2i size;
+ Point2i pos;
+
+ bool operator<(const SortItem &p_item) const {
+ //sort larger to smaller
+ if (size.height == p_item.size.height) {
+ return size.width > p_item.size.width;
+ } else {
+ return size.height > p_item.size.height;
+ }
+ }
+ };
+
+ HashMap<RID, Texture> textures;
+ bool dirty = true;
+
+ GLuint texture = 0;
+ GLuint framebuffer = 0;
+ Size2i size;
+ } texture_atlas;
+
/* Render Target API */
mutable RID_Owner<RenderTarget> render_target_owner;
@@ -393,6 +397,14 @@ private:
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
+ void _render_target_allocate_sdf(RenderTarget *rt);
+ void _render_target_clear_sdf(RenderTarget *rt);
+ Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const;
+
+ struct RenderTargetSDF {
+ CanvasSdfShaderGLES3 shader;
+ RID shader_version;
+ } sdf_shader;
public:
static TextureStorage *get_singleton();
@@ -419,10 +431,6 @@ public:
virtual void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override;
virtual void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override;
- /* CANVAS SHADOW */
-
- RID canvas_light_shadow_buffer_create(int p_width);
-
/* Texture API */
Texture *get_texture(RID p_rid) {
@@ -488,6 +496,25 @@ public:
void texture_bind(RID p_texture, uint32_t p_texture_no);
RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const;
+ /* TEXTURE ATLAS API */
+
+ void update_texture_atlas();
+
+ GLuint texture_atlas_get_texture() const;
+ _FORCE_INLINE_ Rect2 texture_atlas_get_texture_rect(RID p_texture) {
+ TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
+ if (!t) {
+ return Rect2();
+ }
+
+ return t->uv_rect;
+ }
+
+ void texture_add_to_texture_atlas(RID p_texture);
+ void texture_remove_from_texture_atlas(RID p_texture);
+ void texture_atlas_mark_dirty_on_texture(RID p_texture);
+ void texture_atlas_remove_texture(RID p_texture);
+
/* DECAL API */
virtual RID decal_allocate() override;
@@ -509,6 +536,12 @@ public:
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+ /* DECAL INSTANCE */
+
+ virtual RID decal_instance_create(RID p_decal) override;
+ virtual void decal_instance_free(RID p_decal_instance) override;
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
+
/* RENDER TARGET API */
static GLuint system_fbo;
@@ -518,17 +551,19 @@ public:
virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;
+
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
+ virtual Point2i render_target_get_position(RID p_render_target) const override;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
- Size2i render_target_get_size(RID p_render_target);
- virtual RID render_target_get_texture(RID p_render_target) override;
- virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
-
+ virtual Size2i render_target_get_size(RID p_render_target) const override;
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+ virtual bool render_target_get_transparent(RID p_render_target) const override;
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
- virtual bool render_target_was_used(RID p_render_target) override;
+ virtual bool render_target_get_direct_to_screen(RID p_render_target) const override;
+ virtual bool render_target_was_used(RID p_render_target) const override;
void render_target_clear_used(RID p_render_target);
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
+ virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override;
// new
void render_target_set_as_unused(RID p_render_target) override {
@@ -541,15 +576,31 @@ public:
void render_target_disable_clear_request(RID p_render_target) override;
void render_target_do_clear_request(RID p_render_target) override;
- void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
- Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
- void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
+ virtual void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override;
+ virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override;
+ GLuint render_target_get_sdf_texture(RID p_render_target);
+ GLuint render_target_get_sdf_framebuffer(RID p_render_target);
+ void render_target_sdf_process(RID p_render_target);
+ virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override;
+ bool render_target_is_sdf_enabled(RID p_render_target) const;
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
void render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region);
- virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{};
- virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{};
+
+ virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {}
+ virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; }
+ virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
+
+ virtual void render_target_set_override_color(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
+ virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
+ virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
+
+ virtual RID render_target_get_texture(RID p_render_target) override;
void bind_framebuffer(GLuint framebuffer) {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 16bacf1829..8e7e218bb9 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -38,20 +38,44 @@
#include "particles_storage.h"
#include "texture_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
+
using namespace GLES3;
Utilities *Utilities::singleton = nullptr;
Utilities::Utilities() {
singleton = this;
+ frame = 0;
+ for (int i = 0; i < FRAME_COUNT; i++) {
+ frames[i].index = 0;
+ glGenQueries(max_timestamp_query_elements, frames[i].queries);
+
+ frames[i].timestamp_names.resize(max_timestamp_query_elements);
+ frames[i].timestamp_cpu_values.resize(max_timestamp_query_elements);
+ frames[i].timestamp_count = 0;
+
+ frames[i].timestamp_result_names.resize(max_timestamp_query_elements);
+ frames[i].timestamp_cpu_result_values.resize(max_timestamp_query_elements);
+ frames[i].timestamp_result_values.resize(max_timestamp_query_elements);
+ frames[i].timestamp_result_count = 0;
+ }
}
Utilities::~Utilities() {
singleton = nullptr;
+ for (int i = 0; i < FRAME_COUNT; i++) {
+ glDeleteQueries(max_timestamp_query_elements, frames[i].queries);
+ }
}
Vector<uint8_t> Utilities::buffer_get_data(GLenum p_target, GLuint p_buffer, uint32_t p_buffer_size) {
Vector<uint8_t> ret;
+
+ if (p_buffer_size == 0) {
+ return ret;
+ }
+
ret.resize(p_buffer_size);
glBindBuffer(p_target, p_buffer);
@@ -213,87 +237,69 @@ void Utilities::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_de
/* TIMING */
-//void Utilities::render_info_begin_capture() {
-// info.snap = info.render;
-//}
-
-//void Utilities::render_info_end_capture() {
-// info.snap.object_count = info.render.object_count - info.snap.object_count;
-// info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count;
-// info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count;
-// info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count;
-// info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count;
-// info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count;
-// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count;
-// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count;
-//}
-
-//int Utilities::get_captured_render_info(RS::RenderInfo p_info) {
-// switch (p_info) {
-// case RS::INFO_OBJECTS_IN_FRAME: {
-// return info.snap.object_count;
-// } break;
-// case RS::INFO_VERTICES_IN_FRAME: {
-// return info.snap.vertices_count;
-// } break;
-// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: {
-// return info.snap.material_switch_count;
-// } break;
-// case RS::INFO_SHADER_CHANGES_IN_FRAME: {
-// return info.snap.shader_rebind_count;
-// } break;
-// case RS::INFO_SURFACE_CHANGES_IN_FRAME: {
-// return info.snap.surface_switch_count;
-// } break;
-// case RS::INFO_DRAW_CALLS_IN_FRAME: {
-// return info.snap.draw_call_count;
-// } break;
-// /*
-// case RS::INFO_2D_ITEMS_IN_FRAME: {
-// return info.snap._2d_item_count;
-// } break;
-// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: {
-// return info.snap._2d_draw_call_count;
-// } break;
-// */
-// default: {
-// return get_render_info(p_info);
-// }
-// }
-//}
-
-//int Utilities::get_render_info(RS::RenderInfo p_info) {
-// switch (p_info) {
-// case RS::INFO_OBJECTS_IN_FRAME:
-// return info.render_final.object_count;
-// case RS::INFO_VERTICES_IN_FRAME:
-// return info.render_final.vertices_count;
-// case RS::INFO_MATERIAL_CHANGES_IN_FRAME:
-// return info.render_final.material_switch_count;
-// case RS::INFO_SHADER_CHANGES_IN_FRAME:
-// return info.render_final.shader_rebind_count;
-// case RS::INFO_SURFACE_CHANGES_IN_FRAME:
-// return info.render_final.surface_switch_count;
-// case RS::INFO_DRAW_CALLS_IN_FRAME:
-// return info.render_final.draw_call_count;
-// /*
-// case RS::INFO_2D_ITEMS_IN_FRAME:
-// return info.render_final._2d_item_count;
-// case RS::INFO_2D_DRAW_CALLS_IN_FRAME:
-// return info.render_final._2d_draw_call_count;
-//*/
-// case RS::INFO_USAGE_VIDEO_MEM_TOTAL:
-// return 0; //no idea
-// case RS::INFO_VIDEO_MEM_USED:
-// return info.vertex_mem + info.texture_mem;
-// case RS::INFO_TEXTURE_MEM_USED:
-// return info.texture_mem;
-// case RS::INFO_VERTEX_MEM_USED:
-// return info.vertex_mem;
-// default:
-// return 0; //no idea either
-// }
-//}
+void Utilities::capture_timestamps_begin() {
+ capture_timestamp("Frame Begin");
+}
+
+void Utilities::capture_timestamp(const String &p_name) {
+ ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
+
+#ifdef GLES_OVER_GL
+ glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
+#endif
+
+ frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
+ frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
+ frames[frame].timestamp_count++;
+}
+
+void Utilities::_capture_timestamps_begin() {
+ // frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
+ if (frames[frame].timestamp_count) {
+#ifdef GLES_OVER_GL
+ for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
+ uint64_t temp = 0;
+ glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
+ frames[frame].timestamp_result_values[i] = temp;
+ }
+#endif
+ SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
+ SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
+ }
+
+ frames[frame].timestamp_result_count = frames[frame].timestamp_count;
+ frames[frame].timestamp_count = 0;
+ frames[frame].index = Engine::get_singleton()->get_frames_drawn();
+ capture_timestamp("Internal Begin");
+}
+
+void Utilities::capture_timestamps_end() {
+ capture_timestamp("Internal End");
+ frame = (frame + 1) % FRAME_COUNT;
+}
+
+uint32_t Utilities::get_captured_timestamps_count() const {
+ return frames[frame].timestamp_result_count;
+}
+
+uint64_t Utilities::get_captured_timestamps_frame() const {
+ return frames[frame].index;
+}
+
+uint64_t Utilities::get_captured_timestamp_gpu_time(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
+ return frames[frame].timestamp_result_values[p_index];
+}
+
+uint64_t Utilities::get_captured_timestamp_cpu_time(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
+ return frames[frame].timestamp_cpu_result_values[p_index];
+}
+
+String Utilities::get_captured_timestamp_name(uint32_t p_index) const {
+ ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, String());
+ return frames[frame].timestamp_result_names[p_index];
+}
/* MISC */
@@ -302,6 +308,7 @@ void Utilities::update_dirty_resources() {
MaterialStorage::get_singleton()->_update_queued_materials();
//MeshStorage::get_singleton()->_update_dirty_skeletons();
MeshStorage::get_singleton()->_update_dirty_multimeshes();
+ TextureStorage::get_singleton()->update_texture_atlas();
}
void Utilities::set_debug_generate_wireframes(bool p_generate) {
@@ -355,4 +362,13 @@ String Utilities::get_video_adapter_api_version() const {
return (const char *)glGetString(GL_VERSION);
}
+Size2i Utilities::get_maximum_viewport_size() const {
+ Config *config = Config::get_singleton();
+ if (!config) {
+ return Size2i();
+ }
+
+ return Size2i(config->max_viewport_size[0], config->max_viewport_size[1]);
+}
+
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index e054f2f816..55a875958e 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -79,62 +79,35 @@ public:
/* TIMING */
- struct Info {
- uint64_t texture_mem = 0;
- uint64_t vertex_mem = 0;
-
- struct Render {
- uint32_t object_count;
- uint32_t draw_call_count;
- uint32_t material_switch_count;
- uint32_t surface_switch_count;
- uint32_t shader_rebind_count;
- uint32_t vertices_count;
- uint32_t _2d_item_count;
- uint32_t _2d_draw_call_count;
-
- void reset() {
- object_count = 0;
- draw_call_count = 0;
- material_switch_count = 0;
- surface_switch_count = 0;
- shader_rebind_count = 0;
- vertices_count = 0;
- _2d_item_count = 0;
- _2d_draw_call_count = 0;
- }
- } render, render_final, snap;
-
- Info() {
- render.reset();
- render_final.reset();
- }
-
- } info;
-
- virtual void capture_timestamps_begin() override {}
- virtual void capture_timestamp(const String &p_name) override {}
- virtual uint32_t get_captured_timestamps_count() const override {
- return 0;
- }
- virtual uint64_t get_captured_timestamps_frame() const override {
- return 0;
- }
- virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override {
- return 0;
- }
- virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override {
- return 0;
- }
- virtual String get_captured_timestamp_name(uint32_t p_index) const override {
- return String();
- }
-
- // void render_info_begin_capture() override;
- // void render_info_end_capture() override;
- // int get_captured_render_info(RS::RenderInfo p_info) override;
-
- // int get_render_info(RS::RenderInfo p_info) override;
+#define MAX_QUERIES 256
+#define FRAME_COUNT 3
+
+ struct Frame {
+ GLuint queries[MAX_QUERIES];
+ TightLocalVector<String> timestamp_names;
+ TightLocalVector<uint64_t> timestamp_cpu_values;
+ uint32_t timestamp_count = 0;
+ TightLocalVector<String> timestamp_result_names;
+ TightLocalVector<uint64_t> timestamp_cpu_result_values;
+ TightLocalVector<uint64_t> timestamp_result_values;
+ uint32_t timestamp_result_count = 0;
+ uint64_t index = 0;
+ };
+
+ const uint32_t max_timestamp_query_elements = MAX_QUERIES;
+
+ Frame frames[FRAME_COUNT]; // Frames for capturing timestamps. We use 3 so we don't need to wait for commands to complete
+ uint32_t frame = 0;
+
+ virtual void capture_timestamps_begin() override;
+ virtual void capture_timestamp(const String &p_name) override;
+ virtual uint32_t get_captured_timestamps_count() const override;
+ virtual uint64_t get_captured_timestamps_frame() const override;
+ virtual uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override;
+ virtual uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override;
+ virtual String get_captured_timestamp_name(uint32_t p_index) const override;
+ void _capture_timestamps_begin();
+ void capture_timestamps_end();
/* MISC */
@@ -150,6 +123,8 @@ public:
virtual String get_video_adapter_vendor() const override;
virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
virtual String get_video_adapter_api_version() const override;
+
+ virtual Size2i get_maximum_viewport_size() const override;
};
} // namespace GLES3
diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp
index bc4bb3782b..79641464d8 100644
--- a/drivers/png/png_driver_common.cpp
+++ b/drivers/png/png_driver_common.cpp
@@ -119,7 +119,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear,
ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT);
//print_line("png width: "+itos(png_img.width)+" height: "+itos(png_img.height));
- p_image->create(png_img.width, png_img.height, false, dest_format, buffer);
+ p_image->set_data(png_img.width, png_img.height, false, dest_format, buffer);
return OK;
}
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index 85e328b49f..ae6e0acc97 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -48,8 +48,8 @@ class AudioDriverPulseAudio : public AudioDriver {
pa_context *pa_ctx = nullptr;
pa_stream *pa_str = nullptr;
pa_stream *pa_rec_str = nullptr;
- pa_channel_map pa_map;
- pa_channel_map pa_rec_map;
+ pa_channel_map pa_map = {};
+ pa_channel_map pa_rec_map = {};
String device_name = "Default";
String new_device = "Default";
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 55ea952696..d894ceba59 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -30,7 +30,7 @@
#include "dir_access_unix.h"
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/os/memory.h"
#include "core/os/os.h"
@@ -41,10 +41,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#ifndef ANDROID_ENABLED
#include <sys/statvfs.h>
-#endif
#ifdef HAVE_MNTENT
#include <mntent.h>
@@ -74,7 +71,7 @@ bool DirAccessUnix::file_exists(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
if (success && S_ISDIR(flags.st_mode)) {
@@ -93,7 +90,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
p_dir = fix_path(p_dir);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);
return (success && S_ISDIR(flags.st_mode));
@@ -128,7 +125,7 @@ uint64_t DirAccessUnix::get_modified_time(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
bool success = (stat(p_file.utf8().get_data(), &flags) == 0);
if (success) {
@@ -161,7 +158,7 @@ String DirAccessUnix::get_next() {
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) {
String f = current_dir.path_join(fname);
- struct stat flags;
+ struct stat flags = {};
if (stat(f.utf8().get_data(), &flags) == 0) {
_cisdir = S_ISDIR(flags.st_mode);
} else {
@@ -415,7 +412,7 @@ Error DirAccessUnix::remove(String p_path) {
p_path = fix_path(p_path);
- struct stat flags;
+ struct stat flags = {};
if ((stat(p_path.utf8().get_data(), &flags) != 0)) {
return FAILED;
}
@@ -434,7 +431,7 @@ bool DirAccessUnix::is_link(String p_file) {
p_file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
if ((lstat(p_file.utf8().get_data(), &flags) != 0)) {
return FAILED;
}
@@ -475,17 +472,12 @@ Error DirAccessUnix::create_link(String p_source, String p_target) {
}
uint64_t DirAccessUnix::get_space_left() {
-#ifndef NO_STATVFS
struct statvfs vfs;
if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {
return 0;
}
return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize;
-#else
- // FIXME: Implement this.
- return 0;
-#endif
}
String DirAccessUnix::get_filesystem_type() const {
@@ -516,4 +508,4 @@ DirAccessUnix::~DirAccessUnix() {
list_dir_end();
}
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index f5dca7c282..4db24a27b9 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -31,7 +31,7 @@
#ifndef DIR_ACCESS_UNIX_H
#define DIR_ACCESS_UNIX_H
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/io/dir_access.h"
@@ -90,6 +90,6 @@ public:
~DirAccessUnix();
};
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
#endif // DIR_ACCESS_UNIX_H
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 300fbcdcfd..0b80fb1491 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -30,24 +30,20 @@
#include "file_access_unix.h"
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include "core/os/os.h"
#include "core/string/print_string.h"
+#include <errno.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <errno.h>
-
#if defined(UNIX_ENABLED)
#include <unistd.h>
#endif
-#ifndef ANDROID_ENABLED
-#include <sys/statvfs.h>
-#endif
-
#ifdef MSVC
#define S_ISREG(m) ((m)&_S_IFREG)
#include <io.h>
@@ -56,12 +52,6 @@
#define S_ISREG(m) ((m)&S_IFREG)
#endif
-#ifndef NO_FCNTL
-#include <fcntl.h>
-#else
-#include <sys/ioctl.h>
-#endif
-
void FileAccessUnix::check_errors() const {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
@@ -96,7 +86,7 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
backend (unix-compatible mostly) supports utf8 encoding */
//printf("opening %s as %s\n", p_path.utf8().get_data(), path.utf8().get_data());
- struct stat st;
+ struct stat st = {};
int err = stat(path.utf8().get_data(), &st);
if (!err) {
switch (st.st_mode & S_IFMT) {
@@ -131,13 +121,8 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
int fd = fileno(f);
if (fd != -1) {
-#if defined(NO_FCNTL)
- unsigned long par = 0;
- ioctl(fd, FIOCLEX, &par);
-#else
int opts = fcntl(fd, F_GETFD);
fcntl(fd, F_SETFD, opts | FD_CLOEXEC);
-#endif
}
last_error = OK;
@@ -267,7 +252,7 @@ void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
bool FileAccessUnix::file_exists(const String &p_path) {
int err;
- struct stat st;
+ struct stat st = {};
String filename = fix_path(p_path);
// Does the name exist at all?
@@ -299,7 +284,7 @@ bool FileAccessUnix::file_exists(const String &p_path) {
uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
int err = stat(file.utf8().get_data(), &flags);
if (!err) {
@@ -312,7 +297,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) {
String file = fix_path(p_file);
- struct stat flags;
+ struct stat flags = {};
int err = stat(file.utf8().get_data(), &flags);
if (!err) {
@@ -339,4 +324,4 @@ FileAccessUnix::~FileAccessUnix() {
_close();
}
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index e1311a80f8..8c9afe75e7 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -36,7 +36,7 @@
#include <stdio.h>
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags);
@@ -86,6 +86,6 @@ public:
virtual ~FileAccessUnix();
};
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
#endif // FILE_ACCESS_UNIX_H
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index 86adf33d62..c6b327eeee 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -30,32 +30,30 @@
#include "net_socket_posix.h"
+// Some proprietary Unix-derived platforms don't expose Unix sockets
+// so this allows skipping this file to reimplement this API differently.
#ifndef UNIX_SOCKET_UNAVAILABLE
+
#if defined(UNIX_ENABLED)
#include <errno.h>
+#include <fcntl.h>
#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
-#ifndef NO_FCNTL
-#include <fcntl.h>
-#else
-#include <sys/ioctl.h>
-#endif
-#include <netinet/in.h>
-#include <sys/socket.h>
#ifdef WEB_ENABLED
#include <arpa/inet.h>
#endif
-#include <netinet/tcp.h>
-
// BSD calls this flag IPV6_JOIN_GROUP
#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
@@ -93,7 +91,7 @@
#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
#endif
-#endif
+#endif // UNIX_ENABLED
size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
@@ -181,8 +179,8 @@ NetSocketPosix::~NetSocketPosix() {
close();
}
-// Silent a warning reported in #27594
-
+// Silence a warning reported in GH-27594.
+// EAGAIN and EWOULDBLOCK have the same value on most platforms, but it's not guaranteed.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlogical-op"
@@ -309,14 +307,9 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_
void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) {
#ifndef WINDOWS_ENABLED
// Enable close on exec to avoid sharing with subprocesses. Off by default on Windows.
-#if defined(NO_FCNTL)
- unsigned long par = p_enabled ? 1 : 0;
- SOCK_IOCTL(_sock, FIOCLEX, &par);
-#else
int opts = fcntl(_sock, F_GETFD);
fcntl(_sock, F_SETFD, opts | FD_CLOEXEC);
#endif
-#endif
}
Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
@@ -658,7 +651,7 @@ void NetSocketPosix::set_blocking_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
int ret = 0;
-#if defined(WINDOWS_ENABLED) || defined(NO_FCNTL)
+#if defined(WINDOWS_ENABLED)
unsigned long par = p_enabled ? 0 : 1;
ret = SOCK_IOCTL(_sock, FIONBIO, &par);
#else
@@ -781,4 +774,5 @@ Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, Str
Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
-#endif
+
+#endif // UNIX_SOCKET_UNAVAILABLE
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 1151c2232e..161706489f 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -135,10 +135,8 @@ void OS_Unix::initialize_core() {
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
-#ifndef NO_NETWORK
NetSocketPosix::make_default();
IPUnix::make_default();
-#endif
_setup_clock();
}
@@ -147,6 +145,10 @@ void OS_Unix::finalize_core() {
NetSocketPosix::cleanup();
}
+Vector<String> OS_Unix::get_video_adapter_driver_info() const {
+ return Vector<String>();
+}
+
String OS_Unix::get_stdin_string(bool p_block) {
if (p_block) {
char buff[1024];
@@ -168,6 +170,7 @@ Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
left -= chunk;
ofs += chunk;
} while (left > 0);
+// Define this yourself if you don't want to fall back to /dev/urandom.
#elif !defined(NO_URANDOM)
int r = open("/dev/urandom", O_RDONLY);
ERR_FAIL_COND_V(r < 0, FAILED);
@@ -501,16 +504,12 @@ bool OS_Unix::set_environment(const String &p_var, const String &p_value) const
return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0;
}
-int OS_Unix::get_processor_count() const {
- return sysconf(_SC_NPROCESSORS_CONF);
-}
-
String OS_Unix::get_user_data_dir() const {
- String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
- bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir");
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
if (use_custom_dir) {
- String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true);
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
if (custom_dir.is_empty()) {
custom_dir = appname;
}
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index b35f161524..ce06a52a95 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -51,9 +51,11 @@ protected:
public:
OS_Unix();
+ virtual Vector<String> get_video_adapter_driver_info() const override;
+
virtual String get_stdin_string(bool p_block) override;
- virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; // Should return cryptographycally-safe random bytes.
+ virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;
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 Error close_dynamic_library(void *p_library_handle) override;
@@ -84,8 +86,6 @@ public:
virtual bool set_environment(const String &p_var, const String &p_value) const override;
virtual String get_locale() const override;
- virtual int get_processor_count() const override;
-
virtual void initialize_debugging() override;
virtual String get_executable_path() const override;
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index 6292d8b3bc..5154feb478 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
+#if defined(UNIX_ENABLED)
#include "thread_posix.h"
@@ -70,7 +70,7 @@ static Error set_name(const String &p_name) {
}
void init_thread_posix() {
- Thread::_set_platform_funcs(&set_name, nullptr);
+ Thread::_set_platform_functions({ .set_name = set_name });
}
-#endif // UNIX_ENABLED || PTHREAD_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index f0f70b62e0..de29363556 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -1655,9 +1655,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.pNext = nullptr;
image_create_info.flags = 0;
-#ifndef _MSC_VER
-#warning TODO check for support via RenderingDevice to enable on mobile when possible
-#endif
+ // TODO: Check for support via RenderingDevice to enable on mobile when possible.
#ifndef ANDROID_ENABLED
@@ -5172,9 +5170,9 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
uint32_t offset = 0;
uint8_t *binptr = ret.ptrw();
binptr[0] = 'G';
- binptr[1] = 'V';
+ binptr[1] = 'S';
binptr[2] = 'B';
- binptr[3] = 'D'; // Godot vulkan binary data.
+ binptr[3] = 'D'; // Godot Shader Binary Data.
offset += 4;
encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
offset += sizeof(uint32_t);
@@ -5235,7 +5233,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
uint32_t read_offset = 0;
// Consistency check.
ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceVulkanShaderBinaryData), RID());
- ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'V' || binptr[2] != 'B' || binptr[3] != 'D', RID());
+ ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'S' || binptr[2] != 'B' || binptr[3] != 'D', RID());
uint32_t bin_version = decode_uint32(binptr + 4);
ERR_FAIL_COND_V(bin_version != SHADER_BINARY_VERSION, RID());
@@ -6561,7 +6559,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_INDEX_V(p_rasterization_state.cull_mode, 3, RID());
rasterization_state_create_info.cullMode = cull_mode[p_rasterization_state.cull_mode];
rasterization_state_create_info.frontFace = (p_rasterization_state.front_face == POLYGON_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE);
- rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enable;
+ rasterization_state_create_info.depthBiasEnable = p_rasterization_state.depth_bias_enabled;
rasterization_state_create_info.depthBiasConstantFactor = p_rasterization_state.depth_bias_constant_factor;
rasterization_state_create_info.depthBiasClamp = p_rasterization_state.depth_bias_clamp;
rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
@@ -7262,12 +7260,12 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
return OK;
}
-void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
+void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil) {
Vector<VkClearAttachment> clear_attachments;
int color_index = 0;
int texture_index = 0;
- for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
- Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
+ for (int i = 0; i < p_framebuffer->texture_ids.size(); i++) {
+ Texture *texture = texture_owner.get_or_null(p_framebuffer->texture_ids[i]);
if (!texture) {
texture_index++;
@@ -7300,12 +7298,12 @@ void RenderingDeviceVulkan::_draw_list_insert_clear_region(DrawList *draw_list,
VkClearRect cr;
cr.baseArrayLayer = 0;
cr.layerCount = 1;
- cr.rect.offset.x = viewport_offset.x;
- cr.rect.offset.y = viewport_offset.y;
- cr.rect.extent.width = viewport_size.width;
- cr.rect.extent.height = viewport_size.height;
+ cr.rect.offset.x = p_viewport_offset.x;
+ cr.rect.offset.y = p_viewport_offset.y;
+ cr.rect.extent.width = p_viewport_size.width;
+ cr.rect.extent.height = p_viewport_size.height;
- vkCmdClearAttachments(draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
+ vkCmdClearAttachments(p_draw_list->command_buffer, clear_attachments.size(), clear_attachments.ptr(), 1, &cr);
}
RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const Vector<RID> &p_storage_textures) {
@@ -9393,7 +9391,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_CONTINUE(err != OK);
}
- max_descriptors_per_pool = GLOBAL_DEF("rendering/rendering_device/descriptor_pools/max_descriptors_per_pool", 64);
+ max_descriptors_per_pool = GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
// Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
@@ -9688,6 +9686,10 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
return limits.maxComputeWorkGroupSize[1];
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
return limits.maxComputeWorkGroupSize[2];
+ case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
+ return limits.maxViewportDimensions[0];
+ case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
+ return limits.maxViewportDimensions[1];
case LIMIT_SUBGROUP_SIZE: {
VulkanContext::SubgroupCapabilities subgroup_capabilities = context->get_subgroup_capabilities();
return subgroup_capabilities.size;
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index abec1b0e1b..7c75e9bb2e 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -905,7 +905,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool draw_list_unbind_color_textures = false;
bool draw_list_unbind_depth_textures = false;
- void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
+ void _draw_list_insert_clear_region(DrawList *p_draw_list, Framebuffer *p_framebuffer, Point2i p_viewport_offset, Point2i p_viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil);
Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count);
Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures);
_FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 98adc0f16e..5df123878e 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -48,15 +48,119 @@
VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
-VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass) {
- if (fpCreateRenderPass2KHR == nullptr) {
- fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetInstanceProcAddr(inst, "vkCreateRenderPass2KHR");
+Vector<VkAttachmentReference> VulkanContext::_convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs) {
+ Vector<VkAttachmentReference> att_refs;
+
+ if (p_refs != nullptr) {
+ for (uint32_t i = 0; i < p_count; i++) {
+ // We lose aspectMask in this conversion but we don't use it currently.
+
+ VkAttachmentReference ref = {
+ p_refs[i].attachment, /* attachment */
+ p_refs[i].layout /* layout */
+ };
+
+ att_refs.push_back(ref);
+ }
}
- if (fpCreateRenderPass2KHR == nullptr) {
- return VK_ERROR_EXTENSION_NOT_PRESENT;
+ return att_refs;
+}
+
+VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass) {
+ if (has_renderpass2_ext) {
+ if (fpCreateRenderPass2KHR == nullptr) {
+ fpCreateRenderPass2KHR = (PFN_vkCreateRenderPass2KHR)vkGetDeviceProcAddr(p_device, "vkCreateRenderPass2KHR");
+ }
+
+ if (fpCreateRenderPass2KHR == nullptr) {
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
+ } else {
+ return (fpCreateRenderPass2KHR)(p_device, p_create_info, p_allocator, p_render_pass);
+ }
} else {
- return (fpCreateRenderPass2KHR)(device, pCreateInfo, pAllocator, pRenderPass);
+ // need to fall back on vkCreateRenderPass
+
+ const void *next = p_create_info->pNext; // ATM we only support multiview which should work if supported.
+
+ Vector<VkAttachmentDescription> attachments;
+ for (uint32_t i = 0; i < p_create_info->attachmentCount; i++) {
+ // Basically the old layout just misses type and next.
+ VkAttachmentDescription att = {
+ p_create_info->pAttachments[i].flags, /* flags */
+ p_create_info->pAttachments[i].format, /* format */
+ p_create_info->pAttachments[i].samples, /* samples */
+ p_create_info->pAttachments[i].loadOp, /* loadOp */
+ p_create_info->pAttachments[i].storeOp, /* storeOp */
+ p_create_info->pAttachments[i].stencilLoadOp, /* stencilLoadOp */
+ p_create_info->pAttachments[i].stencilStoreOp, /* stencilStoreOp */
+ p_create_info->pAttachments[i].initialLayout, /* initialLayout */
+ p_create_info->pAttachments[i].finalLayout /* finalLayout */
+ };
+
+ attachments.push_back(att);
+ }
+
+ Vector<VkSubpassDescription> subpasses;
+ for (uint32_t i = 0; i < p_create_info->subpassCount; i++) {
+ // Here we need to do more, again it's just stripping out type and next
+ // but we have VkAttachmentReference2 to convert to VkAttachmentReference.
+ // Also viewmask is not supported but we don't use it outside of multiview.
+
+ Vector<VkAttachmentReference> input_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].inputAttachmentCount, p_create_info->pSubpasses[i].pInputAttachments);
+ Vector<VkAttachmentReference> color_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pColorAttachments);
+ Vector<VkAttachmentReference> resolve_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pResolveAttachments);
+ Vector<VkAttachmentReference> depth_attachments = _convert_VkAttachmentReference2(p_create_info->pSubpasses[i].colorAttachmentCount, p_create_info->pSubpasses[i].pDepthStencilAttachment);
+
+ VkSubpassDescription subpass = {
+ p_create_info->pSubpasses[i].flags, /* flags */
+ p_create_info->pSubpasses[i].pipelineBindPoint, /* pipelineBindPoint */
+ p_create_info->pSubpasses[i].inputAttachmentCount, /* inputAttachmentCount */
+ input_attachments.size() == 0 ? nullptr : input_attachments.ptr(), /* pInputAttachments */
+ p_create_info->pSubpasses[i].colorAttachmentCount, /* colorAttachmentCount */
+ color_attachments.size() == 0 ? nullptr : color_attachments.ptr(), /* pColorAttachments */
+ resolve_attachments.size() == 0 ? nullptr : resolve_attachments.ptr(), /* pResolveAttachments */
+ depth_attachments.size() == 0 ? nullptr : depth_attachments.ptr(), /* pDepthStencilAttachment */
+ p_create_info->pSubpasses[i].preserveAttachmentCount, /* preserveAttachmentCount */
+ p_create_info->pSubpasses[i].pPreserveAttachments /* pPreserveAttachments */
+ };
+
+ subpasses.push_back(subpass);
+ }
+
+ Vector<VkSubpassDependency> dependencies;
+ for (uint32_t i = 0; i < p_create_info->dependencyCount; i++) {
+ // We lose viewOffset here but again I don't believe we use this anywhere.
+ VkSubpassDependency dep = {
+ p_create_info->pDependencies[i].srcSubpass, /* srcSubpass */
+ p_create_info->pDependencies[i].dstSubpass, /* dstSubpass */
+ p_create_info->pDependencies[i].srcStageMask, /* srcStageMask */
+ p_create_info->pDependencies[i].dstStageMask, /* dstStageMask */
+ p_create_info->pDependencies[i].srcAccessMask, /* srcAccessMask */
+ p_create_info->pDependencies[i].dstAccessMask, /* dstAccessMask */
+ p_create_info->pDependencies[i].dependencyFlags, /* dependencyFlags */
+ };
+
+ dependencies.push_back(dep);
+ }
+
+ // CorrelatedViewMask is not supported in vkCreateRenderPass but we
+ // currently only use this for multiview.
+ // We'll need to look into this.
+
+ VkRenderPassCreateInfo create_info = {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, /* sType */
+ next, /* pNext*/
+ p_create_info->flags, /* flags */
+ (uint32_t)attachments.size(), /* attachmentCount */
+ attachments.ptr(), /* pAttachments */
+ (uint32_t)subpasses.size(), /* subpassCount */
+ subpasses.ptr(), /* pSubpasses */
+ (uint32_t)dependencies.size(), /* */
+ dependencies.ptr(), /* */
+ };
+
+ return vkCreateRenderPass(device, &create_info, p_allocator, p_render_pass);
}
}
@@ -85,19 +189,6 @@ VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
return VK_FALSE;
}
- // Workaround for Vulkan-Loader usability bug: https://github.com/KhronosGroup/Vulkan-Loader/issues/262.
- if (strstr(pCallbackData->pMessage, "wrong ELF class: ELFCLASS32") != nullptr) {
- return VK_FALSE;
- }
-
-#ifdef WINDOWS_ENABLED
- // Some software installs Vulkan overlays in Windows registry and never cleans them up on uninstall.
- // So we get spammy error level messages from the loader about those - make them verbose instead.
- if (strstr(pCallbackData->pMessage, "loader_get_json: Failed to open JSON file") != nullptr) {
- messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
- }
-#endif
-
if (pCallbackData->pMessageIdName && strstr(pCallbackData->pMessageIdName, "UNASSIGNED-CoreValidation-DrawState-ClearCmdBeforeDraw") != nullptr) {
return VK_FALSE;
}
@@ -320,6 +411,16 @@ Error VulkanContext::_initialize_extensions() {
VkBool32 platformSurfaceExtFound = 0;
memset(extension_names, 0, sizeof(extension_names));
+ // Only enable debug utils in verbose mode or DEV_ENABLED.
+ // End users would get spammed with messages of varying verbosity due to the
+ // mess that thirdparty layers/extensions and drivers seem to leave in their
+ // wake, making the Windows registry a bottomless pit of broken layer JSON.
+#ifdef DEV_ENABLED
+ bool want_debug_utils = true;
+#else
+ bool want_debug_utils = OS::get_singleton()->is_stdout_verbose();
+#endif
+
VkResult err = vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr);
ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_INCOMPLETE, ERR_CANT_CREATE);
@@ -347,8 +448,10 @@ Error VulkanContext::_initialize_extensions() {
}
}
if (!strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, instance_extensions[i].extensionName)) {
- extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
- enabled_debug_utils = true;
+ if (want_debug_utils) {
+ extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
+ enabled_debug_utils = true;
+ }
}
if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
@@ -584,21 +687,43 @@ Error VulkanContext::_check_capabilities() {
vkGetPhysicalDeviceFeatures2_func(gpu, &device_features);
- vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
- vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
- vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
+ // We must check that the relative extension is present before assuming a
+ // feature as enabled. Actually, according to the spec we shouldn't add the
+ // structs in pNext at all, but this works fine.
+ // See also: https://github.com/godotengine/godot/issues/65409
+ for (uint32_t i = 0; i < enabled_extension_count; ++i) {
+ if (!strcmp(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, extension_names[i])) {
+ vrs_capabilities.pipeline_vrs_supported = vrs_features.pipelineFragmentShadingRate;
+ vrs_capabilities.primitive_vrs_supported = vrs_features.primitiveFragmentShadingRate;
+ vrs_capabilities.attachment_vrs_supported = vrs_features.attachmentFragmentShadingRate;
+
+ continue;
+ }
+
+ if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, extension_names[i])) {
+ multiview_capabilities.is_supported = multiview_features.multiview;
+ multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
+ multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
+
+ continue;
+ }
+
+ if (!strcmp(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, extension_names[i])) {
+ shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
+ shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
- multiview_capabilities.is_supported = multiview_features.multiview;
- multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
- multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
+ continue;
+ }
- shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
- shader_capabilities.shader_int8_is_supported = shader_features.shaderInt8;
+ if (!strcmp(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, extension_names[i])) {
+ storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
+ storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess;
+ storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
+ storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
- storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
- storage_buffer_capabilities.uniform_and_storage_buffer_16_bit_access_is_supported = storage_feature.uniformAndStorageBuffer16BitAccess;
- storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
- storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
+ continue;
+ }
+ }
}
// Check extended properties.
@@ -614,9 +739,12 @@ Error VulkanContext::_check_capabilities() {
VkPhysicalDeviceProperties2 physicalDeviceProperties{};
void *nextptr = nullptr;
- subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
- subgroupProperties.pNext = nextptr;
- nextptr = &subgroupProperties;
+ if (!(vulkan_major == 1 && vulkan_minor == 0)) {
+ subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+ subgroupProperties.pNext = nextptr;
+
+ nextptr = &subgroupProperties;
+ }
if (multiview_capabilities.is_supported) {
multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
@@ -704,7 +832,7 @@ Error VulkanContext::_create_instance() {
}
}
- CharString cs = ProjectSettings::get_singleton()->get("application/config/name").operator String().utf8();
+ CharString cs = GLOBAL_GET("application/config/name").operator String().utf8();
const VkApplicationInfo app = {
/*sType*/ VK_STRUCTURE_TYPE_APPLICATION_INFO,
/*pNext*/ nullptr,
@@ -1061,6 +1189,7 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
extension_names[enabled_extension_count++] = VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, device_extensions[i].extensionName)) {
+ has_renderpass2_ext = true;
extension_names[enabled_extension_count++] = VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME;
}
if (enabled_extension_count >= MAX_EXTENSIONS) {
@@ -1703,18 +1832,22 @@ Error VulkanContext::_update_swap_chain(Window *window) {
preTransform = surfCapabilities.currentTransform;
}
- // Find a supported composite alpha mode - one of these is guaranteed to be set.
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
- };
- for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
- if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
- compositeAlpha = compositeAlphaFlags[i];
- break;
+
+ if (OS::get_singleton()->is_layered_allowed() || !(surfCapabilities.supportedCompositeAlpha & compositeAlpha)) {
+ // Find a supported composite alpha mode - one of these is guaranteed to be set.
+ VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
+ VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
+ VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
+ VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+ };
+
+ for (uint32_t i = 0; i < ARRAY_SIZE(compositeAlphaFlags); i++) {
+ if (surfCapabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
+ compositeAlpha = compositeAlphaFlags[i];
+ break;
+ }
}
}
@@ -2261,8 +2394,6 @@ Error VulkanContext::swap_buffers() {
}
}
#endif
- static int total_frames = 0;
- total_frames++;
// print_line("current buffer: " + itos(current_buffer));
err = fpQueuePresentKHR(present_queue, &present);
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 9889cf336b..b47aec1de1 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -188,6 +188,7 @@ private:
uint32_t enabled_extension_count = 0;
const char *extension_names[MAX_EXTENSIONS];
bool enabled_debug_utils = false;
+ bool has_renderpass2_ext = false;
/**
* True if VK_EXT_debug_report extension is used. VK_EXT_debug_report is deprecated but it is
@@ -257,6 +258,8 @@ private:
Error _create_swap_chain();
Error _create_semaphores();
+ Vector<VkAttachmentReference> _convert_VkAttachmentReference2(uint32_t p_count, const VkAttachmentReference2 *p_refs);
+
protected:
virtual const char *_get_platform_surface_extension() const = 0;
@@ -270,7 +273,7 @@ protected:
public:
// Extension calls.
- VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
+ VkResult vkCreateRenderPass2KHR(VkDevice p_device, const VkRenderPassCreateInfo2 *p_create_info, const VkAllocationCallbacks *p_allocator, VkRenderPass *p_render_pass);
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index fb90b776cf..d6636606d2 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -127,6 +127,11 @@ static bool default_capture_device_changed = false;
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#endif
+#if defined(__GNUC__)
+// Workaround GCC warning from -Wcast-function-type.
+#define GetProcAddress (void *)GetProcAddress
+#endif
+
class CMMNotificationClient : public IMMNotificationClient {
LONG _cRef = 1;
IMMDeviceEnumerator *_pEnumerator = nullptr;
@@ -201,6 +206,20 @@ public:
static CMMNotificationClient notif_client;
+typedef const char *(CDECL *PWineGetVersionPtr)(void);
+
+bool AudioDriverWASAPI::is_running_on_wine() {
+ HMODULE nt_lib = LoadLibraryW(L"ntdll.dll");
+ if (!nt_lib) {
+ return false;
+ }
+
+ PWineGetVersionPtr wine_get_version = (PWineGetVersionPtr)GetProcAddress(nt_lib, "wine_get_version");
+ FreeLibrary(nt_lib);
+
+ return (bool)wine_get_version;
+}
+
Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
WAVEFORMATEX *pwfex;
IMMDeviceEnumerator *enumerator = nullptr;
@@ -285,6 +304,10 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c
}
using_audio_client_3 = !p_capture; // IID_IAudioClient3 is only used for adjustable output latency (not input)
+ if (using_audio_client_3 && is_running_on_wine()) {
+ using_audio_client_3 = false;
+ print_verbose("WASAPI: Wine detected, falling back to IAudioClient interface");
+ }
if (using_audio_client_3) {
hr = device->Activate(IID_IAudioClient3, CLSCTX_ALL, nullptr, (void **)&p_device->audio_client);
if (hr != S_OK) {
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index c30a54c042..e9f2794e97 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -79,6 +79,8 @@ class AudioDriverWASAPI : public AudioDriver {
SafeFlag exit_thread;
+ static bool is_running_on_wine();
+
static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample);
static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);
static void thread_func(void *p_udata);
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 7dd294c7a1..c085ba372b 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -200,9 +200,9 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
return current_dir;
} else {
if (_get_root_string().is_empty()) {
- int p = current_dir.find(":");
- if (p != -1) {
- return current_dir.substr(p + 1);
+ int pos = current_dir.find(":");
+ if (pos != -1) {
+ return current_dir.substr(pos + 1);
}
}
return current_dir;
@@ -309,39 +309,13 @@ Error DirAccessWindows::remove(String p_path) {
}
}
-/*
-
-FileType DirAccessWindows::get_file_type(const String& p_file) const {
- WCHAR real_current_dir_name[2048];
- GetCurrentDirectoryW(2048, real_current_dir_name);
- String prev_dir = Strong::utf16((const char16_t *)real_current_dir_name);
-
- bool worked = SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
-
- DWORD attr;
- if (worked) {
- WIN32_FILE_ATTRIBUTE_DATA fileInfo;
- attr = GetFileAttributesExW((LPCWSTR)(p_file.utf16().get_data()), GetFileExInfoStandard, &fileInfo);
- }
-
- SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
-
- if (!worked) {
- return FILE_TYPE_NONE;
- }
-
- return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_
-}
-
-*/
-
uint64_t DirAccessWindows::get_space_left() {
uint64_t bytes = 0;
if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) {
return 0;
}
- //this is either 0 or a value in bytes.
+ // This is either 0 or a value in bytes.
return bytes;
}
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 095d936c78..4e8b327ffe 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -95,8 +95,8 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
// platforms).
if (p_mode_flags == READ) {
WIN32_FIND_DATAW d;
- HANDLE f = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d);
- if (f != INVALID_HANDLE_VALUE) {
+ HANDLE fnd = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d);
+ if (fnd != INVALID_HANDLE_VALUE) {
String fname = String::utf16((const char16_t *)(d.cFileName));
if (!fname.is_empty()) {
String base_file = path.get_file();
@@ -104,7 +104,7 @@ Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms.");
}
}
- FindClose(f);
+ FindClose(fnd);
}
}
#endif
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index b6348c5952..9b1ff78727 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -28,731 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "action_map_editor.h"
-
-#include "core/input/input_map.h"
-#include "core/os/keyboard.h"
+#include "editor/action_map_editor.h"
#include "editor/editor_scale.h"
-#include "scene/gui/separator.h"
-
-/////////////////////////////////////////
-
-// Maps to 2*axis if value is neg, or 2*axis+1 if value is pos.
-static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = {
- TTRC("Left Stick Left, Joystick 0 Left"),
- TTRC("Left Stick Right, Joystick 0 Right"),
- TTRC("Left Stick Up, Joystick 0 Up"),
- TTRC("Left Stick Down, Joystick 0 Down"),
- TTRC("Right Stick Left, Joystick 1 Left"),
- TTRC("Right Stick Right, Joystick 1 Right"),
- TTRC("Right Stick Up, Joystick 1 Up"),
- TTRC("Right Stick Down, Joystick 1 Down"),
- TTRC("Joystick 2 Left"),
- TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"),
- TTRC("Joystick 2 Up"),
- TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"),
- TTRC("Joystick 3 Left"),
- TTRC("Joystick 3 Right"),
- TTRC("Joystick 3 Up"),
- TTRC("Joystick 3 Down"),
- TTRC("Joystick 4 Left"),
- TTRC("Joystick 4 Right"),
- TTRC("Joystick 4 Up"),
- TTRC("Joystick 4 Down"),
-};
-
-String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const {
- ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent");
-
- String text = p_event->as_text();
-
- Ref<InputEventKey> key = p_event;
- if (key.is_valid() && key->is_command_or_control_autoremap()) {
-#ifdef MACOS_ENABLED
- text = text.replace("Command", "Command/Ctrl");
-#else
- text = text.replace("Ctrl", "Command/Ctrl");
-#endif
- }
- Ref<InputEventMouse> mouse = p_event;
- Ref<InputEventJoypadMotion> jp_motion = p_event;
- Ref<InputEventJoypadButton> jp_button = p_event;
- if (jp_motion.is_valid()) {
- // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660.
- String desc = TTR("Unknown Joypad Axis");
- if (jp_motion->get_axis() < JoyAxis::MAX) {
- desc = RTR(_joy_axis_descriptions[2 * (size_t)jp_motion->get_axis() + (jp_motion->get_axis_value() < 0 ? 0 : 1)]);
- }
-
- text = vformat("Joypad Axis %s %s (%s)", itos((int64_t)jp_motion->get_axis()), jp_motion->get_axis_value() < 0 ? "-" : "+", desc);
- }
- if (p_include_device && (mouse.is_valid() || jp_button.is_valid() || jp_motion.is_valid())) {
- String device_string = _get_device_string(p_event->get_device());
- text += vformat(" - %s", device_string);
- }
-
- return text;
-}
-
-void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection) {
- if (p_event.is_valid()) {
- event = p_event;
-
- // Update Label
- event_as_text->set_text(get_event_text(event, true));
-
- Ref<InputEventKey> k = p_event;
- Ref<InputEventMouseButton> mb = p_event;
- Ref<InputEventJoypadButton> joyb = p_event;
- Ref<InputEventJoypadMotion> joym = p_event;
- Ref<InputEventWithModifiers> mod = p_event;
-
- // Update option values and visibility
- bool show_mods = false;
- bool show_device = false;
- bool show_phys_key = false;
-
- if (mod.is_valid()) {
- show_mods = true;
- mod_checkboxes[MOD_ALT]->set_pressed(mod->is_alt_pressed());
- mod_checkboxes[MOD_SHIFT]->set_pressed(mod->is_shift_pressed());
- mod_checkboxes[MOD_CTRL]->set_pressed(mod->is_ctrl_pressed());
- mod_checkboxes[MOD_META]->set_pressed(mod->is_meta_pressed());
-
- autoremap_command_or_control_checkbox->set_pressed(mod->is_command_or_control_autoremap());
- }
-
- if (k.is_valid()) {
- show_phys_key = true;
- physical_key_checkbox->set_pressed(k->get_physical_keycode() != Key::NONE && k->get_keycode() == Key::NONE);
-
- } else if (joyb.is_valid() || joym.is_valid() || mb.is_valid()) {
- show_device = true;
- _set_current_device(event->get_device());
- }
-
- mod_container->set_visible(show_mods);
- device_container->set_visible(show_device);
- physical_key_checkbox->set_visible(show_phys_key);
- additional_options_container->show();
-
- // Update selected item in input list.
- if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid())) {
- TreeItem *category = input_list_tree->get_root()->get_first_child();
- while (category) {
- TreeItem *input_item = category->get_first_child();
-
- if (input_item != nullptr) {
- // input_type should always be > 0, unless the tree structure has been misconfigured.
- int input_type = input_item->get_parent()->get_meta("__type", 0);
- if (input_type == 0) {
- return;
- }
-
- // If event type matches input types of this category.
- if ((k.is_valid() && input_type == INPUT_KEY) || (joyb.is_valid() && input_type == INPUT_JOY_BUTTON) || (joym.is_valid() && input_type == INPUT_JOY_MOTION) || (mb.is_valid() && input_type == INPUT_MOUSE_BUTTON)) {
- // Loop through all items of this category until one matches.
- while (input_item) {
- bool key_match = k.is_valid() && (Variant(k->get_keycode()) == input_item->get_meta("__keycode") || Variant(k->get_physical_keycode()) == input_item->get_meta("__keycode"));
- bool joyb_match = joyb.is_valid() && Variant(joyb->get_button_index()) == input_item->get_meta("__index");
- bool joym_match = joym.is_valid() && Variant(joym->get_axis()) == input_item->get_meta("__axis") && joym->get_axis_value() == (float)input_item->get_meta("__value");
- bool mb_match = mb.is_valid() && Variant(mb->get_button_index()) == input_item->get_meta("__index");
- if (key_match || joyb_match || joym_match || mb_match) {
- category->set_collapsed(false);
- input_item->select(0);
- input_list_tree->ensure_cursor_is_visible();
- return;
- }
- input_item = input_item->get_next();
- }
- }
- }
-
- category->set_collapsed(true); // Event not in this category, so collapse;
- category = category->get_next();
- }
- }
- } else {
- // Event is not valid, reset dialog
- event = p_event;
- Vector<String> strings;
-
- // Reset message, promp for input according to which input types are allowed.
- String text = TTR("Perform an Input (%s).");
-
- if (allowed_input_types & INPUT_KEY) {
- strings.append(TTR("Key"));
- }
-
- if (allowed_input_types & INPUT_JOY_BUTTON) {
- strings.append(TTR("Joypad Button"));
- }
- if (allowed_input_types & INPUT_JOY_MOTION) {
- strings.append(TTR("Joypad Axis"));
- }
- if (allowed_input_types & INPUT_MOUSE_BUTTON) {
- strings.append(TTR("Mouse Button in area below"));
- }
- if (strings.size() == 0) {
- text = TTR("Input Event dialog has been misconfigured: No input types are allowed.");
- event_as_text->set_text(text);
- } else {
- String insert_text = String(", ").join(strings);
- event_as_text->set_text(vformat(text, insert_text));
- }
-
- additional_options_container->hide();
- input_list_tree->deselect_all();
- _update_input_list();
- }
-}
-
-void InputEventConfigurationDialog::_tab_selected(int p_tab) {
- Callable signal_method = callable_mp(this, &InputEventConfigurationDialog::_listen_window_input);
- if (p_tab == 0) {
- // Start Listening.
- if (!is_connected("window_input", signal_method)) {
- connect("window_input", signal_method);
- }
- } else {
- // Stop Listening.
- if (is_connected("window_input", signal_method)) {
- disconnect("window_input", signal_method);
- }
- input_list_tree->call_deferred(SNAME("ensure_cursor_is_visible"));
- if (input_list_tree->get_selected() == nullptr) {
- // If nothing selected, scroll to top.
- input_list_tree->scroll_to_item(input_list_tree->get_root());
- }
- }
-}
-
-void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &p_event) {
- // Ignore if echo or not pressed
- if (p_event->is_echo() || !p_event->is_pressed()) {
- return;
- }
-
- // Ignore mouse motion
- Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
- return;
- }
-
- // Ignore mouse button if not in the detection rect
- Ref<InputEventMouseButton> mb = p_event;
- if (mb.is_valid()) {
- Rect2 r = mouse_detection_rect->get_rect();
- if (!r.has_point(mouse_detection_rect->get_local_mouse_position() + r.get_position())) {
- return;
- }
- }
-
- // Create an editable reference
- Ref<InputEvent> received_event = p_event;
-
- // Check what the type is and if it is allowed.
- Ref<InputEventKey> k = received_event;
- Ref<InputEventJoypadButton> joyb = received_event;
- Ref<InputEventJoypadMotion> joym = received_event;
-
- int type = 0;
- if (k.is_valid()) {
- type = INPUT_KEY;
- } else if (joyb.is_valid()) {
- type = INPUT_JOY_BUTTON;
- } else if (joym.is_valid()) {
- type = INPUT_JOY_MOTION;
- } else if (mb.is_valid()) {
- type = INPUT_MOUSE_BUTTON;
- }
-
- if (!(allowed_input_types & type)) {
- return;
- }
-
- if (joym.is_valid()) {
- float axis_value = joym->get_axis_value();
- if (ABS(axis_value) < 0.9) {
- // Ignore motion below 0.9 magnitude to avoid accidental touches
- return;
- } else {
- // Always make the value 1 or -1 for display consistency
- joym->set_axis_value(SIGN(axis_value));
- }
- }
-
- if (k.is_valid()) {
- k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway.
- // Maintain physical keycode option state
- if (physical_key_checkbox->is_pressed()) {
- k->set_keycode(Key::NONE);
- } else {
- k->set_physical_keycode(Key::NONE);
- }
- }
-
- Ref<InputEventWithModifiers> mod = received_event;
- if (mod.is_valid()) {
- mod->set_window_id(0);
- }
-
- // Maintain device selection.
- received_event->set_device(_get_current_device());
-
- _set_event(received_event);
- set_input_as_handled();
-}
-
-void InputEventConfigurationDialog::_search_term_updated(const String &) {
- _update_input_list();
-}
-
-void InputEventConfigurationDialog::_update_input_list() {
- input_list_tree->clear();
-
- TreeItem *root = input_list_tree->create_item();
- String search_term = input_list_search->get_text();
-
- bool collapse = input_list_search->get_text().is_empty();
-
- if (allowed_input_types & INPUT_KEY) {
- TreeItem *kb_root = input_list_tree->create_item(root);
- kb_root->set_text(0, TTR("Keyboard Keys"));
- kb_root->set_icon(0, icon_cache.keyboard);
- kb_root->set_collapsed(collapse);
- kb_root->set_meta("__type", INPUT_KEY);
-
- for (int i = 0; i < keycode_get_count(); i++) {
- String name = keycode_get_name_by_index(i);
-
- if (!search_term.is_empty() && name.findn(search_term) == -1) {
- continue;
- }
-
- TreeItem *item = input_list_tree->create_item(kb_root);
- item->set_text(0, name);
- item->set_meta("__keycode", keycode_get_value_by_index(i));
- }
- }
-
- if (allowed_input_types & INPUT_MOUSE_BUTTON) {
- TreeItem *mouse_root = input_list_tree->create_item(root);
- mouse_root->set_text(0, TTR("Mouse Buttons"));
- mouse_root->set_icon(0, icon_cache.mouse);
- mouse_root->set_collapsed(collapse);
- mouse_root->set_meta("__type", INPUT_MOUSE_BUTTON);
-
- MouseButton mouse_buttons[9] = { MouseButton::LEFT, MouseButton::RIGHT, MouseButton::MIDDLE, MouseButton::WHEEL_UP, MouseButton::WHEEL_DOWN, MouseButton::WHEEL_LEFT, MouseButton::WHEEL_RIGHT, MouseButton::MB_XBUTTON1, MouseButton::MB_XBUTTON2 };
- for (int i = 0; i < 9; i++) {
- Ref<InputEventMouseButton> mb;
- mb.instantiate();
- mb->set_button_index(mouse_buttons[i]);
- String desc = get_event_text(mb, false);
-
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
- continue;
- }
-
- TreeItem *item = input_list_tree->create_item(mouse_root);
- item->set_text(0, desc);
- item->set_meta("__index", mouse_buttons[i]);
- }
- }
-
- if (allowed_input_types & INPUT_JOY_BUTTON) {
- TreeItem *joyb_root = input_list_tree->create_item(root);
- joyb_root->set_text(0, TTR("Joypad Buttons"));
- joyb_root->set_icon(0, icon_cache.joypad_button);
- joyb_root->set_collapsed(collapse);
- joyb_root->set_meta("__type", INPUT_JOY_BUTTON);
-
- for (int i = 0; i < (int)JoyButton::MAX; i++) {
- Ref<InputEventJoypadButton> joyb;
- joyb.instantiate();
- joyb->set_button_index((JoyButton)i);
- String desc = get_event_text(joyb, false);
-
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
- continue;
- }
-
- TreeItem *item = input_list_tree->create_item(joyb_root);
- item->set_text(0, desc);
- item->set_meta("__index", i);
- }
- }
-
- if (allowed_input_types & INPUT_JOY_MOTION) {
- TreeItem *joya_root = input_list_tree->create_item(root);
- joya_root->set_text(0, TTR("Joypad Axes"));
- joya_root->set_icon(0, icon_cache.joypad_axis);
- joya_root->set_collapsed(collapse);
- joya_root->set_meta("__type", INPUT_JOY_MOTION);
-
- for (int i = 0; i < (int)JoyAxis::MAX * 2; i++) {
- int axis = i / 2;
- int direction = (i & 1) ? 1 : -1;
- Ref<InputEventJoypadMotion> joym;
- joym.instantiate();
- joym->set_axis((JoyAxis)axis);
- joym->set_axis_value(direction);
- String desc = get_event_text(joym, false);
-
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
- continue;
- }
-
- TreeItem *item = input_list_tree->create_item(joya_root);
- item->set_text(0, desc);
- item->set_meta("__axis", i >> 1);
- item->set_meta("__value", (i & 1) ? 1 : -1);
- }
- }
-}
-
-void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
- Ref<InputEventWithModifiers> ie = event;
-
- // Not event with modifiers
- if (ie.is_null()) {
- return;
- }
-
- if (p_index == 0) {
- ie->set_alt_pressed(p_checked);
- } else if (p_index == 1) {
- ie->set_shift_pressed(p_checked);
- } else if (p_index == 2) {
- if (!autoremap_command_or_control_checkbox->is_pressed()) {
- ie->set_ctrl_pressed(p_checked);
- }
- } else if (p_index == 3) {
- if (!autoremap_command_or_control_checkbox->is_pressed()) {
- ie->set_meta_pressed(p_checked);
- }
- }
-
- _set_event(ie);
-}
-
-void InputEventConfigurationDialog::_autoremap_command_or_control_toggled(bool p_checked) {
- Ref<InputEventWithModifiers> ie = event;
- if (ie.is_valid()) {
- ie->set_command_or_control_autoremap(p_checked);
- _set_event(ie);
- }
-
- if (p_checked) {
- mod_checkboxes[MOD_META]->hide();
- mod_checkboxes[MOD_CTRL]->hide();
- } else {
- mod_checkboxes[MOD_META]->show();
- mod_checkboxes[MOD_CTRL]->show();
- }
-}
-
-void InputEventConfigurationDialog::_physical_keycode_toggled(bool p_checked) {
- Ref<InputEventKey> k = event;
-
- if (k.is_null()) {
- return;
- }
-
- if (p_checked) {
- k->set_physical_keycode(k->get_keycode());
- k->set_keycode(Key::NONE);
- } else {
- k->set_keycode((Key)k->get_physical_keycode());
- k->set_physical_keycode(Key::NONE);
- }
-
- _set_event(k);
-}
-
-void InputEventConfigurationDialog::_input_list_item_selected() {
- TreeItem *selected = input_list_tree->get_selected();
-
- // Invalid tree selection - type only exists on the "category" items, which are not a valid selection.
- if (selected->has_meta("__type")) {
- return;
- }
-
- InputEventConfigurationDialog::InputType input_type = (InputEventConfigurationDialog::InputType)(int)selected->get_parent()->get_meta("__type");
-
- switch (input_type) {
- case InputEventConfigurationDialog::INPUT_KEY: {
- Key keycode = (Key)(int)selected->get_meta("__keycode");
- Ref<InputEventKey> k;
- k.instantiate();
-
- if (physical_key_checkbox->is_pressed()) {
- k->set_physical_keycode(keycode);
- k->set_keycode(Key::NONE);
- } else {
- k->set_physical_keycode(Key::NONE);
- k->set_keycode(keycode);
- }
-
- // Maintain modifier state from checkboxes
- k->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
- k->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
- if (autoremap_command_or_control_checkbox->is_pressed()) {
- k->set_command_or_control_autoremap(true);
- } else {
- k->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
- k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
- }
-
- _set_event(k, false);
- } break;
- case InputEventConfigurationDialog::INPUT_MOUSE_BUTTON: {
- MouseButton idx = (MouseButton)(int)selected->get_meta("__index");
- Ref<InputEventMouseButton> mb;
- mb.instantiate();
- mb->set_button_index(idx);
- // Maintain modifier state from checkboxes
- mb->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
- mb->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
- if (autoremap_command_or_control_checkbox->is_pressed()) {
- mb->set_command_or_control_autoremap(true);
- } else {
- mb->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
- mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
- }
-
- // Maintain selected device
- mb->set_device(_get_current_device());
-
- _set_event(mb, false);
- } break;
- case InputEventConfigurationDialog::INPUT_JOY_BUTTON: {
- JoyButton idx = (JoyButton)(int)selected->get_meta("__index");
- Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx);
-
- // Maintain selected device
- jb->set_device(_get_current_device());
-
- _set_event(jb, false);
- } break;
- case InputEventConfigurationDialog::INPUT_JOY_MOTION: {
- JoyAxis axis = (JoyAxis)(int)selected->get_meta("__axis");
- int value = selected->get_meta("__value");
-
- Ref<InputEventJoypadMotion> jm;
- jm.instantiate();
- jm->set_axis(axis);
- jm->set_axis_value(value);
-
- // Maintain selected device
- jm->set_device(_get_current_device());
-
- _set_event(jm, false);
- } break;
- }
-}
-
-void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) {
- // Subtract 1 as option index 0 corresponds to "All Devices" (value of -1)
- // and option index 1 corresponds to device 0, etc...
- event->set_device(p_option_button_index - 1);
- event_as_text->set_text(get_event_text(event, true));
-}
-
-void InputEventConfigurationDialog::_set_current_device(int p_device) {
- device_id_option->select(p_device + 1);
-}
-
-int InputEventConfigurationDialog::_get_current_device() const {
- return device_id_option->get_selected() - 1;
-}
-
-String InputEventConfigurationDialog::_get_device_string(int p_device) const {
- if (p_device == InputMap::ALL_DEVICES) {
- return TTR("All Devices");
- }
- return TTR("Device") + " " + itos(p_device);
-}
-
-void InputEventConfigurationDialog::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case NOTIFICATION_THEME_CHANGED: {
- input_list_search->set_right_icon(input_list_search->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
-
- physical_key_checkbox->set_icon(get_theme_icon(SNAME("KeyboardPhysical"), SNAME("EditorIcons")));
-
- icon_cache.keyboard = get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons"));
- icon_cache.mouse = get_theme_icon(SNAME("Mouse"), SNAME("EditorIcons"));
- icon_cache.joypad_button = get_theme_icon(SNAME("JoyButton"), SNAME("EditorIcons"));
- icon_cache.joypad_axis = get_theme_icon(SNAME("JoyAxis"), SNAME("EditorIcons"));
-
- _update_input_list();
- } break;
- }
-}
-
-void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p_event) {
- if (p_event.is_valid()) {
- _set_event(p_event);
- } else {
- // Clear Event
- _set_event(p_event);
-
- // Clear Checkbox Values
- for (int i = 0; i < MOD_MAX; i++) {
- mod_checkboxes[i]->set_pressed(false);
- }
-
- // Enable the Physical Key checkbox by default to encourage its use.
- // Physical Key should be used for most game inputs as it allows keys to work
- // on non-QWERTY layouts out of the box.
- // This is especially important for WASD movement layouts.
- physical_key_checkbox->set_pressed(true);
-
- autoremap_command_or_control_checkbox->set_pressed(false);
- _set_current_device(0);
-
- // Switch to "Listen" tab
- tab_container->set_current_tab(0);
-
- // Select "All Devices" by default.
- device_id_option->select(0);
- }
-
- popup_centered(Size2(0, 400) * EDSCALE);
-}
-
-Ref<InputEvent> InputEventConfigurationDialog::get_event() const {
- return event;
-}
-
-void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) {
- allowed_input_types = p_type_masks;
-}
-
-InputEventConfigurationDialog::InputEventConfigurationDialog() {
- allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION | INPUT_MOUSE_BUTTON;
-
- set_title(TTR("Event Configuration"));
- set_min_size(Size2i(550 * EDSCALE, 0)); // Min width
-
- VBoxContainer *main_vbox = memnew(VBoxContainer);
- add_child(main_vbox);
-
- tab_container = memnew(TabContainer);
- tab_container->set_use_hidden_tabs_for_min_size(true);
- tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- tab_container->set_theme_type_variation("TabContainerOdd");
- tab_container->connect("tab_selected", callable_mp(this, &InputEventConfigurationDialog::_tab_selected));
- main_vbox->add_child(tab_container);
-
- // Listen to input tab
- VBoxContainer *vb = memnew(VBoxContainer);
- vb->set_name(TTR("Listen for Input"));
- event_as_text = memnew(Label);
- event_as_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- vb->add_child(event_as_text);
- // Mouse button detection rect (Mouse button event outside this rect will be ignored)
- mouse_detection_rect = memnew(Panel);
- mouse_detection_rect->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- vb->add_child(mouse_detection_rect);
- tab_container->add_child(vb);
-
- // List of all input options to manually select from.
-
- VBoxContainer *manual_vbox = memnew(VBoxContainer);
- manual_vbox->set_name(TTR("Manual Selection"));
- manual_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- tab_container->add_child(manual_vbox);
-
- input_list_search = memnew(LineEdit);
- input_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- input_list_search->set_placeholder(TTR("Filter Inputs"));
- input_list_search->set_clear_button_enabled(true);
- input_list_search->connect("text_changed", callable_mp(this, &InputEventConfigurationDialog::_search_term_updated));
- manual_vbox->add_child(input_list_search);
-
- input_list_tree = memnew(Tree);
- input_list_tree->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); // Min height for tree
- input_list_tree->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_selected));
- input_list_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- manual_vbox->add_child(input_list_tree);
-
- input_list_tree->set_hide_root(true);
- input_list_tree->set_columns(1);
-
- _update_input_list();
-
- // Additional Options
- additional_options_container = memnew(VBoxContainer);
- additional_options_container->hide();
-
- Label *opts_label = memnew(Label);
- opts_label->set_theme_type_variation("HeaderSmall");
- opts_label->set_text(TTR("Additional Options"));
- additional_options_container->add_child(opts_label);
-
- // Device Selection
- device_container = memnew(HBoxContainer);
- device_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-
- Label *device_label = memnew(Label);
- device_label->set_theme_type_variation("HeaderSmall");
- device_label->set_text(TTR("Device:"));
- device_container->add_child(device_label);
-
- device_id_option = memnew(OptionButton);
- device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- for (int i = -1; i < 8; i++) {
- device_id_option->add_item(_get_device_string(i));
- }
- device_id_option->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed));
- _set_current_device(InputMap::ALL_DEVICES);
- device_container->add_child(device_id_option);
-
- device_container->hide();
- additional_options_container->add_child(device_container);
-
- // Modifier Selection
- mod_container = memnew(HBoxContainer);
- for (int i = 0; i < MOD_MAX; i++) {
- String name = mods[i];
- mod_checkboxes[i] = memnew(CheckBox);
- mod_checkboxes[i]->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_mod_toggled).bind(i));
- mod_checkboxes[i]->set_text(name);
- mod_checkboxes[i]->set_tooltip_text(TTR(mods_tip[i]));
- mod_container->add_child(mod_checkboxes[i]);
- }
-
- mod_container->add_child(memnew(VSeparator));
-
- autoremap_command_or_control_checkbox = memnew(CheckBox);
- autoremap_command_or_control_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_autoremap_command_or_control_toggled));
- autoremap_command_or_control_checkbox->set_pressed(false);
- autoremap_command_or_control_checkbox->set_text(TTR("Command / Control (auto)"));
- autoremap_command_or_control_checkbox->set_tooltip_text(TTR("Automatically remaps between 'Meta' ('Command') and 'Control' depending on current platform."));
- mod_container->add_child(autoremap_command_or_control_checkbox);
-
- mod_container->hide();
- additional_options_container->add_child(mod_container);
-
- // Physical Key Checkbox
-
- physical_key_checkbox = memnew(CheckBox);
- physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
- physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
- physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
- physical_key_checkbox->hide();
- additional_options_container->add_child(physical_key_checkbox);
-
- main_vbox->add_child(additional_options_container);
-
- // Default to first tab
- tab_container->set_current_tab(0);
-}
-
-/////////////////////////////////////////
+#include "editor/event_listener_line_edit.h"
+#include "editor/input_event_configuration_dialog.h"
+#include "scene/gui/check_button.h"
+#include "scene/gui/tree.h"
static bool _is_action_name_valid(const String &p_name) {
const char32_t *cstr = p_name.get_data();
@@ -944,6 +225,12 @@ void ActionMapEditor::_search_term_updated(const String &) {
update_action_list();
}
+void ActionMapEditor::_search_by_event(const Ref<InputEvent> &p_event) {
+ if (p_event.is_null() || (p_event->is_pressed() && !p_event->is_echo())) {
+ update_action_list();
+ }
+}
+
Variant ActionMapEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
TreeItem *selected = action_tree->get_selected();
if (!selected) {
@@ -1084,6 +371,22 @@ InputEventConfigurationDialog *ActionMapEditor::get_configuration_dialog() {
return event_config_dialog;
}
+bool ActionMapEditor::_should_display_action(const String &p_name, const Array &p_events) const {
+ const Ref<InputEvent> search_ev = action_list_search_by_event->get_event();
+ bool event_match = true;
+ if (search_ev.is_valid()) {
+ event_match = false;
+ for (int i = 0; i < p_events.size(); ++i) {
+ const Ref<InputEvent> ev = p_events[i];
+ if (ev.is_valid() && ev->is_match(search_ev, true)) {
+ event_match = true;
+ }
+ }
+ }
+
+ return event_match && action_list_search->get_text().is_subsequence_ofn(p_name);
+}
+
void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_infos) {
if (!p_action_infos.is_empty()) {
actions_cache = p_action_infos;
@@ -1101,8 +404,8 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
uneditable_count++;
}
- String search_term = action_list_search->get_text();
- if (!search_term.is_empty() && action_info.name.findn(search_term) == -1) {
+ const Array events = action_info.action["events"];
+ if (!_should_display_action(action_info.name, events)) {
continue;
}
@@ -1110,7 +413,6 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info
continue;
}
- const Array events = action_info.action["events"];
const Variant deadzone = action_info.action["deadzone"];
// Update Tree...
@@ -1206,16 +508,22 @@ ActionMapEditor::ActionMapEditor() {
action_list_search = memnew(LineEdit);
action_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- action_list_search->set_placeholder(TTR("Filter Actions"));
+ action_list_search->set_placeholder(TTR("Filter by name..."));
action_list_search->set_clear_button_enabled(true);
action_list_search->connect("text_changed", callable_mp(this, &ActionMapEditor::_search_term_updated));
top_hbox->add_child(action_list_search);
- show_builtin_actions_checkbutton = memnew(CheckButton);
- show_builtin_actions_checkbutton->set_pressed(false);
- show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions"));
- show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions));
- top_hbox->add_child(show_builtin_actions_checkbutton);
+ action_list_search_by_event = memnew(EventListenerLineEdit);
+ action_list_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_list_search_by_event->set_stretch_ratio(0.75);
+ action_list_search_by_event->connect("event_changed", callable_mp(this, &ActionMapEditor::_search_by_event));
+ top_hbox->add_child(action_list_search_by_event);
+
+ Button *clear_all_search = memnew(Button);
+ clear_all_search->set_text(TTR("Clear All"));
+ clear_all_search->connect("pressed", callable_mp(action_list_search_by_event, &EventListenerLineEdit::clear_event));
+ clear_all_search->connect("pressed", callable_mp(action_list_search, &LineEdit::clear));
+ top_hbox->add_child(clear_all_search);
// Adding Action line edit + button
add_hbox = memnew(HBoxContainer);
@@ -1236,6 +544,12 @@ ActionMapEditor::ActionMapEditor() {
// Disable the button and set its tooltip.
_add_edit_text_changed(add_edit->get_text());
+ show_builtin_actions_checkbutton = memnew(CheckButton);
+ show_builtin_actions_checkbutton->set_pressed(false);
+ show_builtin_actions_checkbutton->set_text(TTR("Show Built-in Actions"));
+ show_builtin_actions_checkbutton->connect("toggled", callable_mp(this, &ActionMapEditor::set_show_builtin_actions));
+ add_hbox->add_child(show_builtin_actions_checkbutton);
+
main_vbox->add_child(add_hbox);
// Action Editor Tree
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index 36d21fe258..d56ee6f9eb 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -31,109 +31,16 @@
#ifndef ACTION_MAP_EDITOR_H
#define ACTION_MAP_EDITOR_H
-#include "scene/gui/check_box.h"
-#include "scene/gui/check_button.h"
-#include "scene/gui/color_rect.h"
-#include "scene/gui/dialogs.h"
-#include "scene/gui/label.h"
-#include "scene/gui/option_button.h"
-#include "scene/gui/tab_container.h"
-#include "scene/gui/tree.h"
-
-// Confirmation Dialog used when configuring an input event.
-// Separate from ActionMapEditor for code cleanliness and separation of responsibilities.
-class InputEventConfigurationDialog : public ConfirmationDialog {
- GDCLASS(InputEventConfigurationDialog, ConfirmationDialog);
+#include "scene/gui/control.h"
-public:
- enum InputType {
- INPUT_KEY = 1,
- INPUT_MOUSE_BUTTON = 2,
- INPUT_JOY_BUTTON = 4,
- INPUT_JOY_MOTION = 8
- };
-
-private:
- struct IconCache {
- Ref<Texture2D> keyboard;
- Ref<Texture2D> mouse;
- Ref<Texture2D> joypad_button;
- Ref<Texture2D> joypad_axis;
- } icon_cache;
-
- Ref<InputEvent> event = Ref<InputEvent>();
-
- TabContainer *tab_container = nullptr;
-
- // Listening for input
- Label *event_as_text = nullptr;
- Panel *mouse_detection_rect = nullptr;
-
- // List of All Key/Mouse/Joypad input options.
- int allowed_input_types;
- Tree *input_list_tree = nullptr;
- LineEdit *input_list_search = nullptr;
-
- // Additional Options, shown depending on event selected
- VBoxContainer *additional_options_container = nullptr;
-
- HBoxContainer *device_container = nullptr;
- OptionButton *device_id_option = nullptr;
-
- HBoxContainer *mod_container = nullptr; // Contains the subcontainer and the store command checkbox.
-
- enum ModCheckbox {
- MOD_ALT,
- MOD_SHIFT,
- MOD_CTRL,
- MOD_META,
- MOD_MAX
- };
-#if defined(MACOS_ENABLED)
- String mods[MOD_MAX] = { "Option", "Shift", "Ctrl", "Command" };
-#elif defined(WINDOWS_ENABLED)
- String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Windows" };
-#else
- String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Meta" };
-#endif
- String mods_tip[MOD_MAX] = { "Alt or Option key", "Shift key", "Control key", "Meta/Windows or Command key" };
-
- CheckBox *mod_checkboxes[MOD_MAX];
- CheckBox *autoremap_command_or_control_checkbox = nullptr;
-
- CheckBox *physical_key_checkbox = nullptr;
-
- void _set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection = true);
-
- void _tab_selected(int p_tab);
- void _listen_window_input(const Ref<InputEvent> &p_event);
-
- void _search_term_updated(const String &p_term);
- void _update_input_list();
- void _input_list_item_selected();
-
- void _mod_toggled(bool p_checked, int p_index);
- void _autoremap_command_or_control_toggled(bool p_checked);
- void _physical_keycode_toggled(bool p_checked);
-
- void _device_selection_changed(int p_option_button_index);
- void _set_current_device(int p_device);
- int _get_current_device() const;
- String _get_device_string(int p_device) const;
-
-protected:
- void _notification(int p_what);
-
-public:
- // Pass an existing event to configure it. Alternatively, pass no event to start with a blank configuration.
- void popup_and_configure(const Ref<InputEvent> &p_event = Ref<InputEvent>());
- Ref<InputEvent> get_event() const;
- String get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const;
-
- void set_allowed_input_types(int p_type_masks);
-
- InputEventConfigurationDialog();
-};
+class Button;
+class HBoxContainer;
+class EventListenerLineEdit;
+class LineEdit;
+class CheckButton;
+class AcceptDialog;
+class InputEventConfigurationDialog;
+class Tree;
class ActionMapEditor : public Control {
GDCLASS(ActionMapEditor, Control);
@@ -174,6 +81,7 @@ private:
bool show_builtin_actions = false;
CheckButton *show_builtin_actions_checkbutton = nullptr;
LineEdit *action_list_search = nullptr;
+ EventListenerLineEdit *action_list_search_by_event = nullptr;
HBoxContainer *add_hbox = nullptr;
LineEdit *add_edit = nullptr;
@@ -191,6 +99,8 @@ private:
void _tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _tree_item_activated();
void _search_term_updated(const String &p_search_term);
+ void _search_by_event(const Ref<InputEvent> &p_event);
+ bool _should_display_action(const String &p_name, const Array &p_events) const;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 3b87b3e65e..4c7ebca299 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -211,11 +211,11 @@ void AnimationBezierTrackEdit::_draw_line_clipped(const Vector2 &p_from, const V
void AnimationBezierTrackEdit::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_ENTER_TREE: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -338,14 +338,14 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Ref<Texture2D> unlock = get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons"));
float lock_hpos = remove_hpos - hsep - lock->get_width();
- Ref<Texture2D> visible = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
- Ref<Texture2D> hidden = get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"));
- float visibility_hpos = lock_hpos - hsep - visible->get_width();
+ Ref<Texture2D> visibility_visible = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
+ Ref<Texture2D> visibility_hidden = get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"));
+ float visibility_hpos = lock_hpos - hsep - visibility_visible->get_width();
Ref<Texture2D> solo = get_theme_icon(SNAME("AudioBusSolo"), SNAME("EditorIcons"));
float solo_hpos = visibility_hpos - hsep - solo->get_width();
- float buttons_width = remove->get_width() + lock->get_width() + visible->get_width() + solo->get_width() + hsep * 3;
+ float buttons_width = remove->get_width() + lock->get_width() + visibility_visible->get_width() + solo->get_width() + hsep * 3;
for (int i = 0; i < tracks.size(); ++i) {
// RELATED TRACKS TITLES
@@ -418,11 +418,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
draw_texture(unlock, lock_rect.position);
}
- Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2.0, visible->get_width(), visible->get_height());
+ Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visibility_visible->get_height() / 2.0, visibility_visible->get_width(), visibility_visible->get_height());
if (hidden_tracks.has(current_track)) {
- draw_texture(hidden, visible_rect.position);
+ draw_texture(visibility_hidden, visible_rect.position);
} else {
- draw_texture(visible, visible_rect.position);
+ draw_texture(visibility_visible, visible_rect.position);
}
Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2.0, solo->get_width(), solo->get_height());
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 9529460ab1..44ecda103e 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1487,7 +1487,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
add_track->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
time_icon->set_texture(get_theme_icon(SNAME("Time"), SNAME("EditorIcons")));
@@ -1505,7 +1505,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_RESIZED: {
@@ -2029,14 +2029,14 @@ void AnimationTrackEdit::_notification(int p_what) {
draw_texture(check, check_rect.position);
ofs += check->get_width() + hsep;
- Ref<Texture2D> type_icon = _get_key_type_icon();
- draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2));
- ofs += type_icon->get_width() + hsep;
+ Ref<Texture2D> key_type_icon = _get_key_type_icon();
+ draw_texture(key_type_icon, Point2(ofs, int(get_size().height - key_type_icon->get_height()) / 2));
+ ofs += key_type_icon->get_width() + hsep;
- NodePath path = animation->track_get_path(track);
+ NodePath anim_path = animation->track_get_path(track);
Node *node = nullptr;
- if (root && root->has_node(path)) {
- node = root->get_node(path);
+ if (root && root->has_node(anim_path)) {
+ node = root->get_node(anim_path);
}
String text;
@@ -2053,7 +2053,7 @@ void AnimationTrackEdit::_notification(int p_what) {
} else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
text = TTR("Anim Clips:");
} else {
- text += path.get_concatenated_subnames();
+ text += anim_path.get_concatenated_subnames();
}
text_color.a *= 0.7;
} else if (node) {
@@ -2062,14 +2062,14 @@ void AnimationTrackEdit::_notification(int p_what) {
draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
icon_cache = icon;
- text = String() + node->get_name() + ":" + path.get_concatenated_subnames();
+ text = String() + node->get_name() + ":" + anim_path.get_concatenated_subnames();
ofs += hsep;
ofs += icon->get_width();
} else {
- icon_cache = type_icon;
+ icon_cache = key_type_icon;
- text = path;
+ text = anim_path;
}
path_cache = text;
@@ -2853,9 +2853,9 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (ape) {
AnimationPlayer *ap = ape->get_player();
if (ap) {
- NodePath path = animation->track_get_path(track);
- Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(path.get_concatenated_names()));
- StringName prop = path.get_concatenated_subnames();
+ NodePath npath = animation->track_get_path(track);
+ Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(npath.get_concatenated_names()));
+ StringName prop = npath.get_concatenated_subnames();
PropertyInfo prop_info;
ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
@@ -4463,24 +4463,24 @@ void AnimationTrackEditor::_update_tracks() {
return;
}
- bool read_only = false;
+ bool file_read_only = false;
if (!animation->get_path().is_resource_file()) {
int srpos = animation->get_path().find("::");
if (srpos != -1) {
String base = animation->get_path().substr(0, srpos);
if (ResourceLoader::get_resource_type(base) == "PackedScene") {
if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
- read_only = true;
+ file_read_only = true;
}
} else {
if (FileAccess::exists(base + ".import")) {
- read_only = true;
+ file_read_only = true;
}
}
}
} else {
if (FileAccess::exists(animation->get_path() + ".import")) {
- read_only = true;
+ file_read_only = true;
}
}
@@ -4612,7 +4612,7 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->set_undo_redo(undo_redo);
track_edit->set_timeline(timeline);
track_edit->set_root(root);
- track_edit->set_animation_and_track(animation, i, read_only);
+ track_edit->set_animation_and_track(animation, i, file_read_only);
track_edit->set_play_position(timeline->get_play_position());
track_edit->set_editor(this);
@@ -4753,11 +4753,11 @@ MenuButton *AnimationTrackEditor::get_edit_menu() {
void AnimationTrackEditor::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_ENTER_TREE: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
@@ -5072,10 +5072,8 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
return;
}
- Vector3 scale = base->get_scale();
-
undo_redo->create_action(TTR("Add Scale Key"));
- undo_redo->add_do_method(animation.ptr(), "scale_track_insert_key", p_track, p_ofs, scale);
+ undo_redo->add_do_method(animation.ptr(), "scale_track_insert_key", p_track, p_ofs, base->get_scale());
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
@@ -5671,18 +5669,18 @@ void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) {
if (animation.is_null()) {
return;
}
- float step = animation->get_step();
- if (step == 0) {
- step = 1;
+ float anim_step = animation->get_step();
+ if (anim_step == 0) {
+ anim_step = 1;
}
if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
// This is used when scrobbling the timeline using Alt + Mouse wheel.
- step *= 0.25;
+ anim_step *= 0.25;
}
float pos = timeline->get_play_position();
- pos = Math::snapped(pos - step, step);
+ pos = Math::snapped(pos - anim_step, anim_step);
if (pos < 0) {
pos = 0;
}
@@ -5694,21 +5692,21 @@ void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event, bool p_timeli
if (animation.is_null()) {
return;
}
- float step = animation->get_step();
- if (step == 0) {
- step = 1;
+ float anim_step = animation->get_step();
+ if (anim_step == 0) {
+ anim_step = 1;
}
if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
// This is used when scrobbling the timeline using Alt + Mouse wheel.
// Do not use precise snapping when using the menu action or keyboard shortcut,
// as the default keyboard shortcut requires pressing Shift.
- step *= 0.25;
+ anim_step *= 0.25;
}
float pos = timeline->get_play_position();
- pos = Math::snapped(pos + step, step);
+ pos = Math::snapped(pos + anim_step, anim_step);
if (pos > animation->get_length()) {
pos = animation->get_length();
}
@@ -5801,9 +5799,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_COPY_TRACKS_CONFIRM: {
track_clipboard.clear();
- TreeItem *root = track_copy_select->get_root();
- if (root) {
- TreeItem *it = root->get_first_child();
+ TreeItem *tree_root = track_copy_select->get_root();
+ if (tree_root) {
+ TreeItem *it = tree_root->get_first_child();
while (it) {
Dictionary md = it->get_metadata(0);
int idx = md["track_idx"];
@@ -6037,7 +6035,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
bool is_using_angle = animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_LINEAR_ANGLE || animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_CUBIC_ANGLE;
// Make insert queue.
- Vector<Pair<real_t, Variant>> insert_queue;
+ Vector<Pair<real_t, Variant>> insert_queue_new;
for (int i = 0; i < len; i++) {
// Check neighboring keys.
if (keys[i] + 1 == keys[i + 1]) {
@@ -6058,15 +6056,15 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
Pair<real_t, Variant> keydata;
keydata.first = from_t + delta_t;
keydata.second = Tween::interpolate_variant(from_v, delta_v, delta_t, duration, transition_type, ease_type);
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
}
}
// Do insertion.
- for (int i = 0; i < insert_queue.size(); i++) {
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, insert_queue[i].first, insert_queue[i].second);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, insert_queue[i].first);
+ for (int i = 0; i < insert_queue_new.size(); i++) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, insert_queue_new[i].first, insert_queue_new[i].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, insert_queue_new[i].first);
}
++E;
@@ -6206,14 +6204,14 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
if (do_bake && !animation->track_is_compressed(i)) {
Animation::InterpolationType it = animation->track_get_interpolation_type(i);
if (it == Animation::INTERPOLATION_NEAREST) {
- continue; // Nearest and Angle interpolation cannot be baked.
+ continue; // Nearest interpolation cannot be baked.
}
// Special case for angle interpolation.
bool is_using_angle = it == Animation::INTERPOLATION_LINEAR_ANGLE || it == Animation::INTERPOLATION_CUBIC_ANGLE;
// Make insert queue.
- Vector<Pair<real_t, Variant>> insert_queue;
+ Vector<Pair<real_t, Variant>> insert_queue_new;
switch (type) {
case Animation::TYPE_POSITION_3D: {
@@ -6223,7 +6221,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
Vector3 v;
animation->position_track_interpolate(i, delta_t, &v);
keydata.second = v;
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
} break;
case Animation::TYPE_ROTATION_3D: {
@@ -6233,7 +6231,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
Quaternion v;
animation->rotation_track_interpolate(i, delta_t, &v);
keydata.second = v;
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
} break;
case Animation::TYPE_SCALE_3D: {
@@ -6243,7 +6241,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
Vector3 v;
animation->scale_track_interpolate(i, delta_t, &v);
keydata.second = v;
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
} break;
case Animation::TYPE_BLEND_SHAPE: {
@@ -6253,7 +6251,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
float v;
animation->blend_shape_track_interpolate(i, delta_t, &v);
keydata.second = v;
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
} break;
case Animation::TYPE_VALUE: {
@@ -6261,7 +6259,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
Pair<real_t, Variant> keydata;
keydata.first = delta_t;
keydata.second = animation->value_track_interpolate(i, delta_t);
- insert_queue.append(keydata);
+ insert_queue_new.append(keydata);
}
} break;
default: {
@@ -6276,9 +6274,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
// Insert keys.
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, is_using_angle ? Animation::INTERPOLATION_LINEAR_ANGLE : Animation::INTERPOLATION_LINEAR);
- for (int j = insert_queue.size() - 1; j >= 0; j--) {
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue[j].first);
+ for (int j = insert_queue_new.size() - 1; j >= 0; j--) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue_new[j].first, insert_queue_new[j].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue_new[j].first);
}
// Undo methods.
@@ -6460,6 +6458,7 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
void AnimationTrackEditor::_bind_methods() {
ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
+ ClassDB::bind_method("_redraw_tracks", &AnimationTrackEditor::_redraw_tracks);
ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection);
@@ -6925,19 +6924,19 @@ AnimationTrackEditor::AnimationTrackEditor() {
track_copy_dialog->set_title(TTR("Select Tracks to Copy"));
track_copy_dialog->set_ok_button_text(TTR("Copy"));
- VBoxContainer *track_vbox = memnew(VBoxContainer);
- track_copy_dialog->add_child(track_vbox);
+ VBoxContainer *track_copy_vbox = memnew(VBoxContainer);
+ track_copy_dialog->add_child(track_copy_vbox);
Button *select_all_button = memnew(Button);
select_all_button->set_text(TTR("Select All/None"));
select_all_button->connect("pressed", callable_mp(this, &AnimationTrackEditor::_select_all_tracks_for_copy));
- track_vbox->add_child(select_all_button);
+ track_copy_vbox->add_child(select_all_button);
track_copy_select = memnew(Tree);
track_copy_select->set_h_size_flags(SIZE_EXPAND_FILL);
track_copy_select->set_v_size_flags(SIZE_EXPAND_FILL);
track_copy_select->set_hide_root(true);
- track_vbox->add_child(track_copy_select);
+ track_copy_vbox->add_child(track_copy_select);
track_copy_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_COPY_TRACKS_CONFIRM));
}
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 6499cf8df2..971b671a0c 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -412,9 +412,9 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se
sf->get_animation_list(&animations);
int frame = get_animation()->track_get_key_value(get_track(), p_index);
- String animation;
+ String animation_name;
if (animations.size() == 1) {
- animation = animations.front()->get();
+ animation_name = animations.front()->get();
} else {
// Go through other track to find if animation is set
String animation_path = get_animation()->track_get_path(get_track());
@@ -422,10 +422,10 @@ Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_se
int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));
float track_time = get_animation()->track_get_key_time(get_track(), p_index);
int animaiton_index = get_animation()->track_find_key(animation_track, track_time);
- animation = get_animation()->track_get_key_value(animation_track, animaiton_index);
+ animation_name = get_animation()->track_get_key_value(animation_track, animaiton_index);
}
- Ref<Texture2D> texture = sf->get_frame(animation, frame);
+ Ref<Texture2D> texture = sf->get_frame(animation_name, frame);
if (!texture.is_valid()) {
return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);
}
@@ -504,9 +504,9 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
sf->get_animation_list(&animations);
int frame = get_animation()->track_get_key_value(get_track(), p_index);
- String animation;
+ String animation_name;
if (animations.size() == 1) {
- animation = animations.front()->get();
+ animation_name = animations.front()->get();
} else {
// Go through other track to find if animation is set
String animation_path = get_animation()->track_get_path(get_track());
@@ -514,10 +514,10 @@ void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, in
int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));
float track_time = get_animation()->track_get_key_time(get_track(), p_index);
int animaiton_index = get_animation()->track_find_key(animation_track, track_time);
- animation = get_animation()->track_get_key_value(animation_track, animaiton_index);
+ animation_name = get_animation()->track_get_key_value(animation_track, animaiton_index);
}
- texture = sf->get_frame(animation, frame);
+ texture = sf->get_frame(animation_name, frame);
if (!texture.is_valid()) {
AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);
return;
@@ -670,15 +670,15 @@ void AnimationTrackEditSubAnim::draw_key(int p_index, float p_pixels_sec, int p_
Vector<Vector2> lines;
Vector<Color> colorv;
{
- Ref<Animation> animation = ap->get_animation(anim);
+ Ref<Animation> ap_anim = ap->get_animation(anim);
- for (int i = 0; i < animation->get_track_count(); i++) {
- float h = (rect.size.height - 2) / animation->get_track_count();
+ for (int i = 0; i < ap_anim->get_track_count(); i++) {
+ float h = (rect.size.height - 2) / ap_anim->get_track_count();
int y = 2 + h * i + h / 2;
- for (int j = 0; j < animation->track_get_key_count(i); j++) {
- float ofs = animation->track_get_key_time(i, j);
+ for (int j = 0; j < ap_anim->track_get_key_count(i); j++) {
+ float ofs = ap_anim->track_get_key_time(i, j);
int x = p_x + ofs * p_pixels_sec + 2;
if (x < from_x || x >= (to_x - 4)) {
@@ -1244,15 +1244,15 @@ void AnimationTrackEditTypeAnimation::draw_key(int p_index, float p_pixels_sec,
Vector<Vector2> lines;
Vector<Color> colorv;
{
- Ref<Animation> animation = ap->get_animation(anim);
+ Ref<Animation> ap_anim = ap->get_animation(anim);
- for (int i = 0; i < animation->get_track_count(); i++) {
- float h = (rect.size.height - 2) / animation->get_track_count();
+ for (int i = 0; i < ap_anim->get_track_count(); i++) {
+ float h = (rect.size.height - 2) / ap_anim->get_track_count();
int y = 2 + h * i + h / 2;
- for (int j = 0; j < animation->track_get_key_count(i); j++) {
- float ofs = animation->track_get_key_time(i, j);
+ for (int j = 0; j < ap_anim->track_get_key_count(i); j++) {
+ float ofs = ap_anim->track_get_key_time(i, j);
int x = p_x + ofs * p_pixels_sec + 2;
if (x < from_x || x >= (to_x - 4)) {
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 11a6912aa5..212a46cb62 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -55,6 +55,7 @@ void GotoLineDialog::ok_pressed() {
if (get_line() < 1 || get_line() > text_editor->get_line_count()) {
return;
}
+ text_editor->remove_secondary_carets();
text_editor->unfold_line(get_line() - 1);
text_editor->set_caret_line(get_line() - 1);
hide();
@@ -149,7 +150,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
text_editor->unfold_line(pos.y);
text_editor->set_caret_line(pos.y, false);
text_editor->set_caret_column(pos.x + text.length(), false);
- text_editor->center_viewport_to_caret();
+ text_editor->center_viewport_to_caret(0);
text_editor->select(pos.y, pos.x, pos.y, pos.x + text.length());
line_col_changed_for_result = true;
@@ -176,37 +177,37 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
}
void FindReplaceBar::_replace() {
- bool selection_enabled = text_editor->has_selection();
+ bool selection_enabled = text_editor->has_selection(0);
Point2i selection_begin, selection_end;
if (selection_enabled) {
- selection_begin = Point2i(text_editor->get_selection_from_line(), text_editor->get_selection_from_column());
- selection_end = Point2i(text_editor->get_selection_to_line(), text_editor->get_selection_to_column());
+ selection_begin = Point2i(text_editor->get_selection_from_line(0), text_editor->get_selection_from_column(0));
+ selection_end = Point2i(text_editor->get_selection_to_line(0), text_editor->get_selection_to_column(0));
}
- String replace_text = get_replace_text();
+ String repl_text = get_replace_text();
int search_text_len = get_search_text().length();
text_editor->begin_complex_operation();
if (selection_enabled && is_selection_only()) { // To restrict search_current() to selected region
- text_editor->set_caret_line(selection_begin.width);
- text_editor->set_caret_column(selection_begin.height);
+ text_editor->set_caret_line(selection_begin.width, false, true, 0, 0);
+ text_editor->set_caret_column(selection_begin.height, true, 0);
}
if (search_current()) {
text_editor->unfold_line(result_line);
- text_editor->select(result_line, result_col, result_line, result_col + search_text_len);
+ text_editor->select(result_line, result_col, result_line, result_col + search_text_len, 0);
if (selection_enabled && is_selection_only()) {
Point2i match_from(result_line, result_col);
Point2i match_to(result_line, result_col + search_text_len);
if (!(match_from < selection_begin || match_to > selection_end)) {
- text_editor->insert_text_at_caret(replace_text);
+ text_editor->insert_text_at_caret(repl_text, 0);
if (match_to.x == selection_end.x) { // Adjust selection bounds if necessary
- selection_end.y += replace_text.length() - search_text_len;
+ selection_end.y += repl_text.length() - search_text_len;
}
}
} else {
- text_editor->insert_text_at_caret(replace_text);
+ text_editor->insert_text_at_caret(repl_text, 0);
}
}
text_editor->end_complex_operation();
@@ -216,31 +217,36 @@ void FindReplaceBar::_replace() {
if (selection_enabled && is_selection_only()) {
// Reselect in order to keep 'Replace' restricted to selection
- text_editor->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y);
+ text_editor->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y, 0);
} else {
- text_editor->deselect();
+ text_editor->deselect(0);
}
}
void FindReplaceBar::_replace_all() {
text_editor->disconnect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
// Line as x so it gets priority in comparison, column as y.
- Point2i orig_cursor(text_editor->get_caret_line(), text_editor->get_caret_column());
+ Point2i orig_cursor(text_editor->get_caret_line(0), text_editor->get_caret_column(0));
Point2i prev_match = Point2(-1, -1);
- bool selection_enabled = text_editor->has_selection();
+ bool selection_enabled = text_editor->has_selection(0);
+ if (!is_selection_only()) {
+ text_editor->deselect();
+ selection_enabled = false;
+ } else {
+ result_line = -1;
+ result_col = -1;
+ }
+
Point2i selection_begin, selection_end;
if (selection_enabled) {
- selection_begin = Point2i(text_editor->get_selection_from_line(), text_editor->get_selection_from_column());
- selection_end = Point2i(text_editor->get_selection_to_line(), text_editor->get_selection_to_column());
+ selection_begin = Point2i(text_editor->get_selection_from_line(0), text_editor->get_selection_from_column(0));
+ selection_end = Point2i(text_editor->get_selection_to_line(0), text_editor->get_selection_to_column(0));
}
int vsval = text_editor->get_v_scroll();
- text_editor->set_caret_line(0);
- text_editor->set_caret_column(0);
-
- String replace_text = get_replace_text();
+ String repl_text = get_replace_text();
int search_text_len = get_search_text().length();
int rc = 0;
@@ -250,9 +256,13 @@ void FindReplaceBar::_replace_all() {
text_editor->begin_complex_operation();
if (selection_enabled && is_selection_only()) {
- text_editor->set_caret_line(selection_begin.width);
- text_editor->set_caret_column(selection_begin.height);
+ text_editor->set_caret_line(selection_begin.width, false, true, 0, 0);
+ text_editor->set_caret_column(selection_begin.height, true, 0);
+ } else {
+ text_editor->set_caret_line(0, false, true, 0, 0);
+ text_editor->set_caret_column(0, true, 0);
}
+
if (search_current()) {
do {
// replace area
@@ -263,25 +273,25 @@ void FindReplaceBar::_replace_all() {
break; // Done.
}
- prev_match = Point2i(result_line, result_col + replace_text.length());
+ prev_match = Point2i(result_line, result_col + repl_text.length());
text_editor->unfold_line(result_line);
- text_editor->select(result_line, result_col, result_line, match_to.y);
+ text_editor->select(result_line, result_col, result_line, match_to.y, 0);
- if (selection_enabled && is_selection_only()) {
+ if (selection_enabled) {
if (match_from < selection_begin || match_to > selection_end) {
break; // Done.
}
// Replace but adjust selection bounds.
- text_editor->insert_text_at_caret(replace_text);
+ text_editor->insert_text_at_caret(repl_text, 0);
if (match_to.x == selection_end.x) {
- selection_end.y += replace_text.length() - search_text_len;
+ selection_end.y += repl_text.length() - search_text_len;
}
} else {
// Just replace.
- text_editor->insert_text_at_caret(replace_text);
+ text_editor->insert_text_at_caret(repl_text, 0);
}
rc++;
@@ -293,14 +303,12 @@ void FindReplaceBar::_replace_all() {
replace_all_mode = false;
// Restore editor state (selection, cursor, scroll).
- text_editor->set_caret_line(orig_cursor.x);
- text_editor->set_caret_column(orig_cursor.y);
+ text_editor->set_caret_line(orig_cursor.x, false, true, 0, 0);
+ text_editor->set_caret_column(orig_cursor.y, true, 0);
- if (selection_enabled && is_selection_only()) {
+ if (selection_enabled) {
// Reselect.
- text_editor->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y);
- } else {
- text_editor->deselect();
+ text_editor->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y, 0);
}
text_editor->set_v_scroll(vsval);
@@ -313,21 +321,28 @@ void FindReplaceBar::_replace_all() {
needs_to_count_results = true;
}
-void FindReplaceBar::_get_search_from(int &r_line, int &r_col) {
- r_line = text_editor->get_caret_line();
- r_col = text_editor->get_caret_column();
+void FindReplaceBar::_get_search_from(int &r_line, int &r_col, bool p_is_searching_next) {
+ if (!text_editor->has_selection(0) || is_selection_only()) {
+ r_line = text_editor->get_caret_line(0);
+ r_col = text_editor->get_caret_column(0);
- if (text_editor->has_selection() && is_selection_only()) {
+ if (!p_is_searching_next && r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) {
+ r_col = result_col;
+ }
return;
}
- if (r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) {
- r_col = result_col;
+ if (p_is_searching_next) {
+ r_line = text_editor->get_selection_to_line();
+ r_col = text_editor->get_selection_to_column();
+ } else {
+ r_line = text_editor->get_selection_from_line();
+ r_col = text_editor->get_selection_from_column();
}
}
void FindReplaceBar::_update_results_count() {
- if (!needs_to_count_results && (result_line != -1)) {
+ if (!needs_to_count_results && (result_line != -1) && results_count_to_current > 0) {
results_count_to_current += (flags & TextEdit::SEARCH_BACKWARDS) ? -1 : 1;
if (results_count_to_current > results_count) {
@@ -339,9 +354,6 @@ void FindReplaceBar::_update_results_count() {
return;
}
- results_count = 0;
- results_count_to_current = 0;
-
String searched = get_search_text();
if (searched.is_empty()) {
return;
@@ -349,6 +361,8 @@ void FindReplaceBar::_update_results_count() {
needs_to_count_results = false;
+ results_count = 0;
+
for (int i = 0; i < text_editor->get_line_count(); i++) {
String line_text = text_editor->get_line(i);
@@ -372,8 +386,13 @@ void FindReplaceBar::_update_results_count() {
results_count++;
- if (i == result_line && col_pos == result_col) {
- results_count_to_current = results_count;
+ if (i == result_line) {
+ if (col_pos == result_col) {
+ results_count_to_current = results_count;
+ } else if (col_pos < result_col && col_pos + searched.length() > result_col) {
+ col_pos = result_col;
+ results_count_to_current = results_count;
+ }
}
col_pos += searched.length();
@@ -391,10 +410,10 @@ void FindReplaceBar::_update_matches_label() {
if (results_count == 0) {
matches_label->set_text("No match");
- } else if (results_count == 1) {
- matches_label->set_text(vformat(TTR("%d match"), results_count));
+ } else if (results_count_to_current == -1) {
+ matches_label->set_text(vformat(TTRN("%d match", "%d matches", results_count), results_count));
} else {
- matches_label->set_text(vformat(TTR("%d of %d matches"), results_count_to_current, results_count));
+ matches_label->set_text(vformat(TTRN("%d of %d match", "%d of %d matches", results_count), results_count_to_current, results_count));
}
}
}
@@ -416,6 +435,10 @@ bool FindReplaceBar::search_current() {
}
bool FindReplaceBar::search_prev() {
+ if (is_selection_only() && !replace_all_mode) {
+ return false;
+ }
+
if (!is_visible()) {
popup_search(true);
}
@@ -434,9 +457,6 @@ bool FindReplaceBar::search_prev() {
int line, col;
_get_search_from(line, col);
- if (text_editor->has_selection()) {
- col--; // Skip currently selected word.
- }
col -= text.length();
if (col < 0) {
@@ -451,17 +471,15 @@ bool FindReplaceBar::search_prev() {
}
bool FindReplaceBar::search_next() {
+ if (is_selection_only() && !replace_all_mode) {
+ return false;
+ }
+
if (!is_visible()) {
popup_search(true);
}
flags = 0;
- String text;
- if (replace_all_mode) {
- text = get_replace_text();
- } else {
- text = get_search_text();
- }
if (is_whole_words()) {
flags |= TextEdit::SEARCH_WHOLE_WORDS;
@@ -471,18 +489,7 @@ bool FindReplaceBar::search_next() {
}
int line, col;
- _get_search_from(line, col);
-
- if (line == result_line && col == result_col) {
- col += text.length();
- if (col > text_editor->get_line(line).length()) {
- line += 1;
- if (line >= text_editor->get_line_count()) {
- line = 0;
- }
- col = 0;
- }
- }
+ _get_search_from(line, col, true);
return _search(flags, line, col);
}
@@ -512,8 +519,10 @@ void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) {
search_text->call_deferred(SNAME("grab_focus"));
}
- if (text_editor->has_selection() && !selection_only->is_pressed()) {
- search_text->set_text(text_editor->get_selected_text());
+ if (text_editor->has_selection(0) && !is_selection_only()) {
+ search_text->set_text(text_editor->get_selected_text(0));
+ result_line = text_editor->get_selection_from_line();
+ result_col = text_editor->get_selection_from_column();
}
if (!get_search_text().is_empty()) {
@@ -537,6 +546,7 @@ void FindReplaceBar::popup_search(bool p_show_only) {
replace_text->hide();
hbc_button_replace->hide();
hbc_option_replace->hide();
+ selection_only->set_pressed(false);
_show_search(false, p_show_only);
}
@@ -548,9 +558,9 @@ void FindReplaceBar::popup_replace() {
hbc_option_replace->show();
}
- selection_only->set_pressed((text_editor->has_selection() && text_editor->get_selection_from_line() < text_editor->get_selection_to_line()));
+ selection_only->set_pressed((text_editor->has_selection(0) && text_editor->get_selection_from_line(0) < text_editor->get_selection_to_line(0)));
- _show_search(is_visible() || text_editor->has_selection());
+ _show_search(is_visible() || text_editor->has_selection(0));
}
void FindReplaceBar::_search_options_changed(bool p_pressed) {
@@ -587,7 +597,7 @@ void FindReplaceBar::_search_text_submitted(const String &p_text) {
}
void FindReplaceBar::_replace_text_submitted(const String &p_text) {
- if (selection_only->is_pressed() && text_editor->has_selection()) {
+ if (selection_only->is_pressed() && text_editor->has_selection(0)) {
_replace_all();
_hide_bar();
} else if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
@@ -999,50 +1009,50 @@ void CodeTextEditor::update_editor_settings() {
completion_comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
// Appearance: Caret
- text_editor->set_caret_type((TextEdit::CaretType)EditorSettings::get_singleton()->get("text_editor/appearance/caret/type").operator int());
- text_editor->set_caret_blink_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink"));
- text_editor->set_caret_blink_interval(EditorSettings::get_singleton()->get("text_editor/appearance/caret/caret_blink_interval"));
- text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_current_line"));
- text_editor->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/appearance/caret/highlight_all_occurrences"));
+ text_editor->set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int());
+ text_editor->set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink"));
+ text_editor->set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval"));
+ text_editor->set_highlight_current_line(EDITOR_GET("text_editor/appearance/caret/highlight_current_line"));
+ text_editor->set_highlight_all_occurrences(EDITOR_GET("text_editor/appearance/caret/highlight_all_occurrences"));
// Appearance: Gutters
- text_editor->set_draw_line_numbers(EditorSettings::get_singleton()->get("text_editor/appearance/gutters/show_line_numbers"));
- text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/appearance/gutters/line_numbers_zero_padded"));
- text_editor->set_draw_bookmarks_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/gutters/show_bookmark_gutter"));
+ text_editor->set_draw_line_numbers(EDITOR_GET("text_editor/appearance/gutters/show_line_numbers"));
+ text_editor->set_line_numbers_zero_padded(EDITOR_GET("text_editor/appearance/gutters/line_numbers_zero_padded"));
+ text_editor->set_draw_bookmarks_gutter(EDITOR_GET("text_editor/appearance/gutters/show_bookmark_gutter"));
// Appearance: Minimap
- text_editor->set_draw_minimap(EditorSettings::get_singleton()->get("text_editor/appearance/minimap/show_minimap"));
- text_editor->set_minimap_width((int)EditorSettings::get_singleton()->get("text_editor/appearance/minimap/minimap_width") * EDSCALE);
+ text_editor->set_draw_minimap(EDITOR_GET("text_editor/appearance/minimap/show_minimap"));
+ text_editor->set_minimap_width((int)EDITOR_GET("text_editor/appearance/minimap/minimap_width") * EDSCALE);
// Appearance: Lines
- text_editor->set_line_folding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/lines/code_folding"));
- text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/lines/code_folding"));
- text_editor->set_line_wrapping_mode((TextEdit::LineWrappingMode)EditorSettings::get_singleton()->get("text_editor/appearance/lines/word_wrap").operator int());
+ text_editor->set_line_folding_enabled(EDITOR_GET("text_editor/appearance/lines/code_folding"));
+ text_editor->set_draw_fold_gutter(EDITOR_GET("text_editor/appearance/lines/code_folding"));
+ text_editor->set_line_wrapping_mode((TextEdit::LineWrappingMode)EDITOR_GET("text_editor/appearance/lines/word_wrap").operator int());
// Appearance: Whitespace
- text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/appearance/whitespace/draw_tabs"));
- text_editor->set_draw_spaces(EditorSettings::get_singleton()->get("text_editor/appearance/whitespace/draw_spaces"));
+ text_editor->set_draw_tabs(EDITOR_GET("text_editor/appearance/whitespace/draw_tabs"));
+ text_editor->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces"));
// Behavior: Navigation
- text_editor->set_scroll_past_end_of_file_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/scroll_past_end_of_file"));
- text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/smooth_scrolling"));
- text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/v_scroll_speed"));
- text_editor->set_drag_and_drop_selection_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/drag_and_drop_selection"));
+ text_editor->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file"));
+ text_editor->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling"));
+ text_editor->set_v_scroll_speed(EDITOR_GET("text_editor/behavior/navigation/v_scroll_speed"));
+ text_editor->set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection"));
// Behavior: indent
- text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/behavior/indent/type"));
- text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/behavior/indent/size"));
- text_editor->set_auto_indent_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/indent/auto_indent"));
+ text_editor->set_indent_using_spaces(EDITOR_GET("text_editor/behavior/indent/type"));
+ text_editor->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size"));
+ text_editor->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent"));
// Completion
- text_editor->set_auto_brace_completion_enabled(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
+ text_editor->set_auto_brace_completion_enabled(EDITOR_GET("text_editor/completion/auto_brace_complete"));
// Appearance: Guidelines
- if (EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/show_line_length_guidelines")) {
+ if (EDITOR_GET("text_editor/appearance/guidelines/show_line_length_guidelines")) {
TypedArray<int> guideline_cols;
- guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/line_length_guideline_hard_column"));
- if (EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/line_length_guideline_soft_column") != guideline_cols[0]) {
- guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/line_length_guideline_soft_column"));
+ guideline_cols.append(EDITOR_GET("text_editor/appearance/guidelines/line_length_guideline_hard_column"));
+ if (EDITOR_GET("text_editor/appearance/guidelines/line_length_guideline_soft_column") != guideline_cols[0]) {
+ guideline_cols.append(EDITOR_GET("text_editor/appearance/guidelines/line_length_guideline_soft_column"));
}
text_editor->set_line_length_guidelines(guideline_cols);
} else {
@@ -1091,6 +1101,7 @@ void CodeTextEditor::trim_trailing_whitespace() {
}
if (trimed_whitespace) {
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
@@ -1115,15 +1126,18 @@ void CodeTextEditor::insert_final_newline() {
}
void CodeTextEditor::convert_indent_to_spaces() {
- int indent_size = EditorSettings::get_singleton()->get("text_editor/behavior/indent/size");
+ int indent_size = EDITOR_GET("text_editor/behavior/indent/size");
String indent = "";
for (int i = 0; i < indent_size; i++) {
indent += " ";
}
- int cursor_line = text_editor->get_caret_line();
- int cursor_column = text_editor->get_caret_column();
+ Vector<int> cursor_columns;
+ cursor_columns.resize(text_editor->get_caret_count());
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ cursor_columns.write[c] = text_editor->get_caret_column(c);
+ }
bool changed_indentation = false;
for (int i = 0; i < text_editor->get_line_count(); i++) {
@@ -1140,8 +1154,10 @@ void CodeTextEditor::convert_indent_to_spaces() {
text_editor->begin_complex_operation();
changed_indentation = true;
}
- if (cursor_line == i && cursor_column > j) {
- cursor_column += indent_size - 1;
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ if (text_editor->get_caret_line(c) == i && text_editor->get_caret_column(c) > j) {
+ cursor_columns.write[c] += indent_size - 1;
+ }
}
line = line.left(j) + indent + line.substr(j + 1);
}
@@ -1152,18 +1168,24 @@ void CodeTextEditor::convert_indent_to_spaces() {
}
}
if (changed_indentation) {
- text_editor->set_caret_column(cursor_column);
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ text_editor->set_caret_column(cursor_columns[c], c == 0, c);
+ }
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
}
void CodeTextEditor::convert_indent_to_tabs() {
- int indent_size = EditorSettings::get_singleton()->get("text_editor/behavior/indent/size");
+ int indent_size = EDITOR_GET("text_editor/behavior/indent/size");
indent_size -= 1;
- int cursor_line = text_editor->get_caret_line();
- int cursor_column = text_editor->get_caret_column();
+ Vector<int> cursor_columns;
+ cursor_columns.resize(text_editor->get_caret_count());
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ cursor_columns.write[c] = text_editor->get_caret_column(c);
+ }
bool changed_indentation = false;
for (int i = 0; i < text_editor->get_line_count(); i++) {
@@ -1184,8 +1206,10 @@ void CodeTextEditor::convert_indent_to_tabs() {
text_editor->begin_complex_operation();
changed_indentation = true;
}
- if (cursor_line == i && cursor_column > j) {
- cursor_column -= indent_size;
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ if (text_editor->get_caret_line(c) == i && text_editor->get_caret_column(c) > j) {
+ cursor_columns.write[c] -= indent_size;
+ }
}
line = line.left(j - indent_size) + "\t" + line.substr(j + 1);
j = 0;
@@ -1201,7 +1225,10 @@ void CodeTextEditor::convert_indent_to_tabs() {
}
}
if (changed_indentation) {
- text_editor->set_caret_column(cursor_column);
+ for (int c = 0; c < text_editor->get_caret_count(); c++) {
+ text_editor->set_caret_column(cursor_columns[c], c == 0, c);
+ }
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
@@ -1211,59 +1238,128 @@ void CodeTextEditor::convert_case(CaseStyle p_case) {
if (!text_editor->has_selection()) {
return;
}
-
text_editor->begin_complex_operation();
- int begin = text_editor->get_selection_from_line();
- int end = text_editor->get_selection_to_line();
- int begin_col = text_editor->get_selection_from_column();
- int end_col = text_editor->get_selection_to_column();
-
- for (int i = begin; i <= end; i++) {
- int len = text_editor->get_line(i).length();
- if (i == end) {
- len = end_col;
- }
- if (i == begin) {
- len -= begin_col;
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ if (!text_editor->has_selection(c)) {
+ continue;
}
- String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len);
- switch (p_case) {
- case UPPER: {
- new_line = new_line.to_upper();
- } break;
- case LOWER: {
- new_line = new_line.to_lower();
- } break;
- case CAPITALIZE: {
- new_line = new_line.capitalize();
- } break;
- }
+ int begin = text_editor->get_selection_from_line(c);
+ int end = text_editor->get_selection_to_line(c);
+ int begin_col = text_editor->get_selection_from_column(c);
+ int end_col = text_editor->get_selection_to_column(c);
- if (i == begin) {
- new_line = text_editor->get_line(i).left(begin_col) + new_line;
- }
- if (i == end) {
- new_line = new_line + text_editor->get_line(i).substr(end_col);
+ for (int i = begin; i <= end; i++) {
+ int len = text_editor->get_line(i).length();
+ if (i == end) {
+ len = end_col;
+ }
+ if (i == begin) {
+ len -= begin_col;
+ }
+ String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len);
+
+ switch (p_case) {
+ case UPPER: {
+ new_line = new_line.to_upper();
+ } break;
+ case LOWER: {
+ new_line = new_line.to_lower();
+ } break;
+ case CAPITALIZE: {
+ new_line = new_line.capitalize();
+ } break;
+ }
+
+ if (i == begin) {
+ new_line = text_editor->get_line(i).left(begin_col) + new_line;
+ }
+ if (i == end) {
+ new_line = new_line + text_editor->get_line(i).substr(end_col);
+ }
+ text_editor->set_line(i, new_line);
}
- text_editor->set_line(i, new_line);
}
text_editor->end_complex_operation();
}
void CodeTextEditor::move_lines_up() {
text_editor->begin_complex_operation();
- if (text_editor->has_selection()) {
- int from_line = text_editor->get_selection_from_line();
- int from_col = text_editor->get_selection_from_column();
- int to_line = text_editor->get_selection_to_line();
- int to_column = text_editor->get_selection_to_column();
- int cursor_line = text_editor->get_caret_line();
- for (int i = from_line; i <= to_line; i++) {
- int line_id = i;
- int next_id = i - 1;
+ Vector<int> carets_to_remove;
+
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size(); i++) {
+ int c = caret_edit_order[i];
+ int cl = text_editor->get_caret_line(c);
+
+ bool swaped_caret = false;
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ if (text_editor->has_selection(caret_edit_order[j])) {
+ if (text_editor->get_selection_from_line() == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ continue;
+ }
+
+ if (text_editor->get_selection_to_line() == cl) {
+ if (text_editor->has_selection(c)) {
+ if (text_editor->get_selection_to_line(c) != cl) {
+ text_editor->select(cl + 1, 0, text_editor->get_selection_to_line(c), text_editor->get_selection_to_column(c), c);
+ break;
+ }
+ }
+
+ carets_to_remove.push_back(c);
+ i = j - 1;
+ swaped_caret = true;
+ break;
+ }
+ break;
+ }
+
+ if (text_editor->get_caret_line(caret_edit_order[j]) == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ i = j;
+ continue;
+ }
+ break;
+ }
+
+ if (swaped_caret) {
+ continue;
+ }
+
+ if (text_editor->has_selection(c)) {
+ int from_line = text_editor->get_selection_from_line(c);
+ int from_col = text_editor->get_selection_from_column(c);
+ int to_line = text_editor->get_selection_to_line(c);
+ int to_column = text_editor->get_selection_to_column(c);
+ int cursor_line = text_editor->get_caret_line(c);
+
+ for (int j = from_line; j <= to_line; j++) {
+ int line_id = j;
+ int next_id = j - 1;
+
+ if (line_id == 0 || next_id < 0) {
+ return;
+ }
+
+ text_editor->unfold_line(line_id);
+ text_editor->unfold_line(next_id);
+
+ text_editor->swap_lines(line_id, next_id);
+ text_editor->set_caret_line(next_id, c == 0, true, 0, c);
+ }
+ int from_line_up = from_line > 0 ? from_line - 1 : from_line;
+ int to_line_up = to_line > 0 ? to_line - 1 : to_line;
+ int cursor_line_up = cursor_line > 0 ? cursor_line - 1 : cursor_line;
+ text_editor->select(from_line_up, from_col, to_line_up, to_column, c);
+ text_editor->set_caret_line(cursor_line_up, c == 0, true, 0, c);
+ } else {
+ int line_id = text_editor->get_caret_line(c);
+ int next_id = line_id - 1;
if (line_id == 0 || next_id < 0) {
return;
@@ -1273,238 +1369,336 @@ void CodeTextEditor::move_lines_up() {
text_editor->unfold_line(next_id);
text_editor->swap_lines(line_id, next_id);
- text_editor->set_caret_line(next_id);
- }
- int from_line_up = from_line > 0 ? from_line - 1 : from_line;
- int to_line_up = to_line > 0 ? to_line - 1 : to_line;
- int cursor_line_up = cursor_line > 0 ? cursor_line - 1 : cursor_line;
- text_editor->select(from_line_up, from_col, to_line_up, to_column);
- text_editor->set_caret_line(cursor_line_up);
- } else {
- int line_id = text_editor->get_caret_line();
- int next_id = line_id - 1;
-
- if (line_id == 0 || next_id < 0) {
- return;
+ text_editor->set_caret_line(next_id, c == 0, true, 0, c);
}
-
- text_editor->unfold_line(line_id);
- text_editor->unfold_line(next_id);
-
- text_editor->swap_lines(line_id, next_id);
- text_editor->set_caret_line(next_id);
}
text_editor->end_complex_operation();
+ text_editor->merge_overlapping_carets();
text_editor->queue_redraw();
}
void CodeTextEditor::move_lines_down() {
text_editor->begin_complex_operation();
- if (text_editor->has_selection()) {
- int from_line = text_editor->get_selection_from_line();
- int from_col = text_editor->get_selection_from_column();
- int to_line = text_editor->get_selection_to_line();
- int to_column = text_editor->get_selection_to_column();
- int cursor_line = text_editor->get_caret_line();
- for (int i = to_line; i >= from_line; i--) {
- int line_id = i;
- int next_id = i + 1;
+ Vector<int> carets_to_remove;
+
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size(); i++) {
+ int c = caret_edit_order[i];
+ int cl = text_editor->get_caret_line(c);
+
+ bool swaped_caret = false;
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ if (text_editor->has_selection(caret_edit_order[j])) {
+ if (text_editor->get_selection_from_line() == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ continue;
+ }
+
+ if (text_editor->get_selection_to_line() == cl) {
+ if (text_editor->has_selection(c)) {
+ if (text_editor->get_selection_to_line(c) != cl) {
+ text_editor->select(cl + 1, 0, text_editor->get_selection_to_line(c), text_editor->get_selection_to_column(c), c);
+ break;
+ }
+ }
+
+ carets_to_remove.push_back(c);
+ i = j - 1;
+ swaped_caret = true;
+ break;
+ }
+ break;
+ }
+
+ if (text_editor->get_caret_line(caret_edit_order[j]) == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ i = j;
+ continue;
+ }
+ break;
+ }
+
+ if (swaped_caret) {
+ continue;
+ }
+
+ if (text_editor->has_selection(c)) {
+ int from_line = text_editor->get_selection_from_line(c);
+ int from_col = text_editor->get_selection_from_column(c);
+ int to_line = text_editor->get_selection_to_line(c);
+ int to_column = text_editor->get_selection_to_column(c);
+ int cursor_line = text_editor->get_caret_line(c);
+
+ for (int l = to_line; l >= from_line; l--) {
+ int line_id = l;
+ int next_id = l + 1;
+
+ if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) {
+ continue;
+ }
+
+ text_editor->unfold_line(line_id);
+ text_editor->unfold_line(next_id);
+
+ text_editor->swap_lines(line_id, next_id);
+ text_editor->set_caret_line(next_id, c == 0, true, 0, c);
+ }
+ int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line;
+ int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line;
+ int cursor_line_down = cursor_line < text_editor->get_line_count() ? cursor_line + 1 : cursor_line;
+ text_editor->select(from_line_down, from_col, to_line_down, to_column, c);
+ text_editor->set_caret_line(cursor_line_down, c == 0, true, 0, c);
+ } else {
+ int line_id = text_editor->get_caret_line(c);
+ int next_id = line_id + 1;
if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) {
- return;
+ continue;
}
text_editor->unfold_line(line_id);
text_editor->unfold_line(next_id);
text_editor->swap_lines(line_id, next_id);
- text_editor->set_caret_line(next_id);
- }
- int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line;
- int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line;
- int cursor_line_down = cursor_line < text_editor->get_line_count() ? cursor_line + 1 : cursor_line;
- text_editor->select(from_line_down, from_col, to_line_down, to_column);
- text_editor->set_caret_line(cursor_line_down);
- } else {
- int line_id = text_editor->get_caret_line();
- int next_id = line_id + 1;
-
- if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) {
- return;
+ text_editor->set_caret_line(next_id, c == 0, true, 0, c);
}
+ }
- text_editor->unfold_line(line_id);
- text_editor->unfold_line(next_id);
-
- text_editor->swap_lines(line_id, next_id);
- text_editor->set_caret_line(next_id);
+ // Sort and remove backwards to preserve indexes.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ text_editor->remove_caret(carets_to_remove[i]);
}
+
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
-void CodeTextEditor::_delete_line(int p_line) {
+void CodeTextEditor::_delete_line(int p_line, int p_caret) {
// this is currently intended to be called within delete_lines()
// so `begin_complex_operation` is omitted here
text_editor->set_line(p_line, "");
if (p_line == 0 && text_editor->get_line_count() > 1) {
- text_editor->set_caret_line(1);
- text_editor->set_caret_column(0);
+ text_editor->set_caret_line(1, p_caret == 0, true, 0, p_caret);
+ text_editor->set_caret_column(0, p_caret == 0, p_caret);
}
- text_editor->backspace();
+ text_editor->backspace(p_caret);
if (p_line < text_editor->get_line_count()) {
text_editor->unfold_line(p_line);
}
- text_editor->set_caret_line(p_line);
+ text_editor->set_caret_line(p_line, p_caret == 0, true, 0, p_caret);
}
void CodeTextEditor::delete_lines() {
text_editor->begin_complex_operation();
- if (text_editor->has_selection()) {
- int to_line = text_editor->get_selection_to_line();
- int from_line = text_editor->get_selection_from_line();
- int count = Math::abs(to_line - from_line) + 1;
- text_editor->set_caret_line(from_line, false);
- text_editor->deselect();
- for (int i = 0; i < count; i++) {
- _delete_line(from_line);
+ Vector<int> carets_to_remove;
+
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size(); i++) {
+ int c = caret_edit_order[i];
+ int cl = text_editor->get_caret_line(c);
+
+ bool swaped_caret = false;
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ if (text_editor->has_selection(caret_edit_order[j])) {
+ if (text_editor->get_selection_from_line() == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ continue;
+ }
+
+ if (text_editor->get_selection_to_line() == cl) {
+ if (text_editor->has_selection(c)) {
+ if (text_editor->get_selection_to_line(c) != cl) {
+ text_editor->select(cl + 1, 0, text_editor->get_selection_to_line(c), text_editor->get_selection_to_column(c), c);
+ break;
+ }
+ }
+
+ carets_to_remove.push_back(c);
+ i = j - 1;
+ swaped_caret = true;
+ break;
+ }
+ break;
+ }
+
+ if (text_editor->get_caret_line(caret_edit_order[j]) == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ i = j;
+ continue;
+ }
+ break;
}
- } else {
- _delete_line(text_editor->get_caret_line());
+
+ if (swaped_caret) {
+ continue;
+ }
+
+ if (text_editor->has_selection(c)) {
+ int to_line = text_editor->get_selection_to_line(c);
+ int from_line = text_editor->get_selection_from_line(c);
+ int count = Math::abs(to_line - from_line) + 1;
+
+ text_editor->set_caret_line(from_line, false, true, 0, c);
+ text_editor->deselect(c);
+ for (int j = 0; j < count; j++) {
+ _delete_line(from_line, c);
+ }
+ } else {
+ _delete_line(text_editor->get_caret_line(c), c);
+ }
+ }
+
+ // Sort and remove backwards to preserve indexes.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ text_editor->remove_caret(carets_to_remove[i]);
}
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
}
void CodeTextEditor::duplicate_selection() {
- const int cursor_column = text_editor->get_caret_column();
- int from_line = text_editor->get_caret_line();
- int to_line = text_editor->get_caret_line();
- int from_column = 0;
- int to_column = 0;
- int cursor_new_line = to_line + 1;
- int cursor_new_column = text_editor->get_caret_column();
- String new_text = "\n" + text_editor->get_line(from_line);
- bool selection_active = false;
-
- text_editor->set_caret_column(text_editor->get_line(from_line).length());
- if (text_editor->has_selection()) {
- from_column = text_editor->get_selection_from_column();
- to_column = text_editor->get_selection_to_column();
-
- from_line = text_editor->get_selection_from_line();
- to_line = text_editor->get_selection_to_line();
- cursor_new_line = to_line + text_editor->get_caret_line() - from_line;
- cursor_new_column = to_column == cursor_column ? 2 * to_column - from_column : to_column;
- new_text = text_editor->get_selected_text();
- selection_active = true;
-
- text_editor->set_caret_line(to_line);
- text_editor->set_caret_column(to_column);
- }
-
text_editor->begin_complex_operation();
- for (int i = from_line; i <= to_line; i++) {
- text_editor->unfold_line(i);
- }
- text_editor->deselect();
- text_editor->insert_text_at_caret(new_text);
- text_editor->set_caret_line(cursor_new_line);
- text_editor->set_caret_column(cursor_new_column);
- if (selection_active) {
- text_editor->select(to_line, to_column, 2 * to_line - from_line, to_line == from_line ? 2 * to_column - from_column : to_column);
- }
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ const int cursor_column = text_editor->get_caret_column(c);
+ int from_line = text_editor->get_caret_line(c);
+ int to_line = text_editor->get_caret_line(c);
+ int from_column = 0;
+ int to_column = 0;
+ int cursor_new_line = to_line + 1;
+ int cursor_new_column = text_editor->get_caret_column(c);
+ String new_text = "\n" + text_editor->get_line(from_line);
+ bool selection_active = false;
+
+ text_editor->set_caret_column(text_editor->get_line(from_line).length(), c == 0, c);
+ if (text_editor->has_selection(c)) {
+ from_column = text_editor->get_selection_from_column(c);
+ to_column = text_editor->get_selection_to_column(c);
+
+ from_line = text_editor->get_selection_from_line(c);
+ to_line = text_editor->get_selection_to_line(c);
+ cursor_new_line = to_line + text_editor->get_caret_line(c) - from_line;
+ cursor_new_column = to_column == cursor_column ? 2 * to_column - from_column : to_column;
+ new_text = text_editor->get_selected_text(c);
+ selection_active = true;
+
+ text_editor->set_caret_line(to_line, c == 0, true, 0, c);
+ text_editor->set_caret_column(to_column, c == 0, c);
+ }
+ for (int i = from_line; i <= to_line; i++) {
+ text_editor->unfold_line(i);
+ }
+ text_editor->deselect(c);
+ text_editor->insert_text_at_caret(new_text, c);
+ text_editor->set_caret_line(cursor_new_line, c == 0, true, 0, c);
+ text_editor->set_caret_column(cursor_new_column, c == 0, c);
+ if (selection_active) {
+ text_editor->select(to_line, to_column, 2 * to_line - from_line, to_line == from_line ? 2 * to_column - from_column : to_column, c);
+ }
+ }
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
text_editor->begin_complex_operation();
- if (text_editor->has_selection()) {
- int begin = text_editor->get_selection_from_line();
- int end = text_editor->get_selection_to_line();
- // End of selection ends on the first column of the last line, ignore it.
- if (text_editor->get_selection_to_column() == 0) {
- end -= 1;
- }
+ Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ if (text_editor->has_selection(c)) {
+ int begin = text_editor->get_selection_from_line(c);
+ int end = text_editor->get_selection_to_line(c);
- int col_to = text_editor->get_selection_to_column();
- int cursor_pos = text_editor->get_caret_column();
+ // End of selection ends on the first column of the last line, ignore it.
+ if (text_editor->get_selection_to_column(c) == 0) {
+ end -= 1;
+ }
- // Check if all lines in the selected block are commented.
- bool is_commented = true;
- for (int i = begin; i <= end; i++) {
- if (!text_editor->get_line(i).begins_with(delimiter)) {
- is_commented = false;
- break;
+ int col_to = text_editor->get_selection_to_column(c);
+ int cursor_pos = text_editor->get_caret_column(c);
+
+ // Check if all lines in the selected block are commented.
+ bool is_commented = true;
+ for (int i = begin; i <= end; i++) {
+ if (!text_editor->get_line(i).begins_with(delimiter)) {
+ is_commented = false;
+ break;
+ }
}
- }
- for (int i = begin; i <= end; i++) {
- String line_text = text_editor->get_line(i);
+ for (int i = begin; i <= end; i++) {
+ String line_text = text_editor->get_line(i);
- if (line_text.strip_edges().is_empty()) {
- line_text = delimiter;
- } else {
- if (is_commented) {
- line_text = line_text.substr(delimiter.length(), line_text.length());
+ if (line_text.strip_edges().is_empty()) {
+ line_text = delimiter;
} else {
- line_text = delimiter + line_text;
+ if (is_commented) {
+ line_text = line_text.substr(delimiter.length(), line_text.length());
+ } else {
+ line_text = delimiter + line_text;
+ }
}
+ text_editor->set_line(i, line_text);
}
- text_editor->set_line(i, line_text);
- }
- // Adjust selection & cursor position.
- int offset = (is_commented ? -1 : 1) * delimiter.length();
- int col_from = text_editor->get_selection_from_column() > 0 ? text_editor->get_selection_from_column() + offset : 0;
+ // Adjust selection & cursor position.
+ int offset = (is_commented ? -1 : 1) * delimiter.length();
+ int col_from = text_editor->get_selection_from_column(c) > 0 ? text_editor->get_selection_from_column(c) + offset : 0;
- if (is_commented && text_editor->get_caret_column() == text_editor->get_line(text_editor->get_caret_line()).length() + 1) {
- cursor_pos += 1;
- }
+ if (is_commented && text_editor->get_caret_column(c) == text_editor->get_line(text_editor->get_caret_line(c)).length() + 1) {
+ cursor_pos += 1;
+ }
- if (text_editor->get_selection_to_column() != 0 && col_to != text_editor->get_line(text_editor->get_selection_to_line()).length() + 1) {
- col_to += offset;
- }
+ if (text_editor->get_selection_to_column(c) != 0 && col_to != text_editor->get_line(text_editor->get_selection_to_line(c)).length() + 1) {
+ col_to += offset;
+ }
- if (text_editor->get_caret_column() != 0) {
- cursor_pos += offset;
- }
+ if (text_editor->get_caret_column(c) != 0) {
+ cursor_pos += offset;
+ }
- text_editor->select(begin, col_from, text_editor->get_selection_to_line(), col_to);
- text_editor->set_caret_column(cursor_pos);
+ text_editor->select(begin, col_from, text_editor->get_selection_to_line(c), col_to, c);
+ text_editor->set_caret_column(cursor_pos, c == 0, c);
- } else {
- int begin = text_editor->get_caret_line();
- String line_text = text_editor->get_line(begin);
- int delimiter_length = delimiter.length();
-
- int col = text_editor->get_caret_column();
- if (line_text.begins_with(delimiter)) {
- line_text = line_text.substr(delimiter_length, line_text.length());
- col -= delimiter_length;
} else {
- line_text = delimiter + line_text;
- col += delimiter_length;
- }
+ int begin = text_editor->get_caret_line(c);
+ String line_text = text_editor->get_line(begin);
+ int delimiter_length = delimiter.length();
+
+ int col = text_editor->get_caret_column(c);
+ if (line_text.begins_with(delimiter)) {
+ line_text = line_text.substr(delimiter_length, line_text.length());
+ col -= delimiter_length;
+ } else {
+ line_text = delimiter + line_text;
+ col += delimiter_length;
+ }
- text_editor->set_line(begin, line_text);
- text_editor->set_caret_column(col);
+ text_editor->set_line(begin, line_text);
+ text_editor->set_caret_column(col, c == 0, c);
+ }
}
+ text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
}
void CodeTextEditor::goto_line(int p_line) {
+ text_editor->remove_secondary_carets();
text_editor->deselect();
text_editor->unfold_line(p_line);
text_editor->call_deferred(SNAME("set_caret_line"), p_line);
}
void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
+ text_editor->remove_secondary_carets();
text_editor->unfold_line(p_line);
text_editor->call_deferred(SNAME("set_caret_line"), p_line);
text_editor->call_deferred(SNAME("set_caret_column"), p_begin);
@@ -1526,19 +1720,7 @@ void CodeTextEditor::clear_executing_line() {
Variant CodeTextEditor::get_edit_state() {
Dictionary state;
-
- state["scroll_position"] = text_editor->get_v_scroll();
- state["h_scroll_position"] = text_editor->get_h_scroll();
- state["column"] = text_editor->get_caret_column();
- state["row"] = text_editor->get_caret_line();
-
- state["selection"] = get_text_editor()->has_selection();
- if (get_text_editor()->has_selection()) {
- state["selection_from_line"] = text_editor->get_selection_from_line();
- state["selection_from_column"] = text_editor->get_selection_from_column();
- state["selection_to_line"] = text_editor->get_selection_to_line();
- state["selection_to_column"] = text_editor->get_selection_to_column();
- }
+ state.merge(get_navigation_state());
state["folded_lines"] = text_editor->get_folded_lines();
state["breakpoints"] = text_editor->get_breakpointed_lines();
@@ -1559,8 +1741,10 @@ void CodeTextEditor::set_edit_state(const Variant &p_state) {
text_editor->set_v_scroll(state["scroll_position"]);
text_editor->set_h_scroll(state["h_scroll_position"]);
- if (state.has("selection")) {
+ if (state.get("selection", false)) {
text_editor->select(state["selection_from_line"], state["selection_from_column"], state["selection_to_line"], state["selection_to_column"]);
+ } else {
+ text_editor->deselect();
}
if (state.has("folded_lines")) {
@@ -1585,6 +1769,25 @@ void CodeTextEditor::set_edit_state(const Variant &p_state) {
}
}
+Variant CodeTextEditor::get_navigation_state() {
+ Dictionary state;
+
+ state["scroll_position"] = text_editor->get_v_scroll();
+ state["h_scroll_position"] = text_editor->get_h_scroll();
+ state["column"] = text_editor->get_caret_column();
+ state["row"] = text_editor->get_caret_line();
+
+ state["selection"] = get_text_editor()->has_selection();
+ if (get_text_editor()->has_selection()) {
+ state["selection_from_line"] = text_editor->get_selection_from_line();
+ state["selection_from_column"] = text_editor->get_selection_from_column();
+ state["selection_to_line"] = text_editor->get_selection_to_line();
+ state["selection_to_column"] = text_editor->get_selection_to_column();
+ }
+
+ return state;
+}
+
void CodeTextEditor::set_error(const String &p_error) {
error->set_text(p_error);
if (!p_error.is_empty()) {
@@ -1608,6 +1811,7 @@ void CodeTextEditor::goto_error() {
if (text_editor->get_line_count() != error_line) {
text_editor->unfold_line(error_line);
}
+ text_editor->remove_secondary_carets();
text_editor->set_caret_line(error_line);
text_editor->set_caret_column(error_column);
text_editor->center_viewport_to_caret();
@@ -1644,8 +1848,8 @@ void CodeTextEditor::_on_settings_change() {
void CodeTextEditor::_apply_settings_change() {
_update_text_editor_theme();
- font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
- int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures");
+ font_size = EDITOR_GET("interface/editor/code_font_size");
+ int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
if (fc.is_valid()) {
@@ -1656,7 +1860,7 @@ void CodeTextEditor::_apply_settings_change() {
fc->set_opentype_features(ftrs);
} break;
case 2: { // Custom.
- Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(",");
+ Vector<String> subtag = String(EDITOR_GET("interface/editor/code_font_custom_opentype_features")).split(",");
Dictionary ftrs;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
@@ -1784,8 +1988,10 @@ void CodeTextEditor::set_warning_count(int p_warning_count) {
}
void CodeTextEditor::toggle_bookmark() {
- int line = text_editor->get_caret_line();
- text_editor->set_line_as_bookmarked(line, !text_editor->is_line_bookmarked(line));
+ for (int i = 0; i < text_editor->get_caret_count(); i++) {
+ int line = text_editor->get_caret_line(i);
+ text_editor->set_line_as_bookmarked(line, !text_editor->is_line_bookmarked(line));
+ }
}
void CodeTextEditor::goto_next_bookmark() {
@@ -1794,6 +2000,7 @@ void CodeTextEditor::goto_next_bookmark() {
return;
}
+ text_editor->remove_secondary_carets();
int line = text_editor->get_caret_line();
if (line >= (int)bmarks[bmarks.size() - 1]) {
text_editor->unfold_line(bmarks[0]);
@@ -1818,6 +2025,7 @@ void CodeTextEditor::goto_prev_bookmark() {
return;
}
+ text_editor->remove_secondary_carets();
int line = text_editor->get_caret_line();
if (line <= (int)bmarks[0]) {
text_editor->unfold_line(bmarks[bmarks.size() - 1]);
@@ -1876,7 +2084,7 @@ CodeTextEditor::CodeTextEditor() {
add_child(text_editor);
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures");
+ int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
if (fc.is_valid()) {
switch (ot_mode) {
@@ -1886,7 +2094,7 @@ CodeTextEditor::CodeTextEditor() {
fc->set_opentype_features(ftrs);
} break;
case 2: { // Custom.
- Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(",");
+ Vector<String> subtag = String(EDITOR_GET("interface/editor/code_font_custom_opentype_features")).split(",");
Dictionary ftrs;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
@@ -1994,7 +2202,7 @@ CodeTextEditor::CodeTextEditor() {
code_complete_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_code_complete_timer_timeout));
font_resize_val = 0;
- font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
+ font_size = EDITOR_GET("interface/editor/code_font_size");
font_resize_timer = memnew(Timer);
add_child(font_resize_timer);
font_resize_timer->set_one_shot(true);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index 49679cc700..ded7518287 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -92,7 +92,7 @@ class FindReplaceBar : public HBoxContainer {
bool replace_all_mode = false;
bool preserve_cursor = false;
- void _get_search_from(int &r_line, int &r_col);
+ void _get_search_from(int &r_line, int &r_col, bool p_is_searching_next = false);
void _update_results_count();
void _update_matches_label();
@@ -197,7 +197,7 @@ class CodeTextEditor : public VBoxContainer {
void _update_status_bar_theme();
- void _delete_line(int p_line);
+ void _delete_line(int p_line, int p_caret);
void _toggle_scripts_pressed();
protected:
@@ -246,6 +246,7 @@ public:
Variant get_edit_state();
void set_edit_state(const Variant &p_state);
+ Variant get_navigation_state();
void set_error_count(int p_error_count);
void set_warning_count(int p_warning_count);
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index ddeb8643b8..de7f5c8b88 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "plugins/script_editor_plugin.h"
+#include "scene/resources/packed_scene.h"
static Node *_find_first_script(Node *p_root, Node *p_node) {
if (p_node != p_root && p_node->get_owner() != p_root) {
@@ -160,6 +161,9 @@ void ConnectDialog::_tree_node_selected() {
}
dst_path = source->get_path_to(current);
+ if (!edit_mode) {
+ set_dst_method(generate_method_callback_name(source, signal, current));
+ }
_update_ok_enabled();
}
@@ -184,8 +188,8 @@ void ConnectDialog::_add_bind() {
Variant::Type type = (Variant::Type)type_list->get_item_id(type_list->get_selected());
Variant value;
- Callable::CallError error;
- Variant::construct(type, value, nullptr, 0, error);
+ Callable::CallError err;
+ Variant::construct(type, value, nullptr, 0, err);
cdbinds->params.push_back(value);
cdbinds->notify_changed();
@@ -205,6 +209,45 @@ void ConnectDialog::_remove_bind() {
cdbinds->params.remove_at(idx);
cdbinds->notify_changed();
}
+/*
+ * Automatically generates a name for the callback method.
+ */
+StringName ConnectDialog::generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target) {
+ String node_name = p_source->get_name();
+ for (int i = 0; i < node_name.length(); i++) { // TODO: Regex filter may be cleaner.
+ char32_t c = node_name[i];
+ if (!is_ascii_identifier_char(c)) {
+ if (c == ' ') {
+ // Replace spaces with underlines.
+ c = '_';
+ } else {
+ // Remove any other characters.
+ node_name.remove_at(i);
+ i--;
+ continue;
+ }
+ }
+ node_name[i] = c;
+ }
+
+ Dictionary subst;
+ subst["NodeName"] = node_name.to_pascal_case();
+ subst["nodeName"] = node_name.to_camel_case();
+ subst["node_name"] = node_name.to_snake_case();
+
+ subst["SignalName"] = p_signal_name.to_pascal_case();
+ subst["signalName"] = p_signal_name.to_camel_case();
+ subst["signal_name"] = p_signal_name.to_snake_case();
+
+ String dst_method;
+ if (p_source == p_target) {
+ dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_to_self_name")).format(subst);
+ } else {
+ dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst);
+ }
+
+ return dst_method;
+}
/*
* Enables or disables the connect button. The connect button is enabled if a
@@ -371,6 +414,7 @@ void ConnectDialog::popup_dialog(const String &p_for_signal) {
first_popup = false;
_advanced_pressed();
}
+
popup_centered();
}
@@ -583,19 +627,19 @@ void ConnectionsDock::_make_or_edit_connection() {
// Conditions to add function: must have a script and must not have the method already
// (in the class, the script itself, or inherited).
bool add_script_function = false;
- Ref<Script> script = target->get_script();
- if (!target->get_script().is_null() && !ClassDB::has_method(target->get_class(), cd.method)) {
+ Ref<Script> scr = target->get_script();
+ if (!scr.is_null() && !ClassDB::has_method(target->get_class(), cd.method)) {
// There is a chance that the method is inherited from another script.
bool found_inherited_function = false;
- Ref<Script> inherited_script = script->get_base_script();
- while (!inherited_script.is_null()) {
- int line = inherited_script->get_language()->find_function(cd.method, inherited_script->get_source_code());
+ Ref<Script> inherited_scr = scr->get_base_script();
+ while (!inherited_scr.is_null()) {
+ int line = inherited_scr->get_language()->find_function(cd.method, inherited_scr->get_source_code());
if (line != -1) {
found_inherited_function = true;
break;
}
- inherited_script = inherited_script->get_base_script();
+ inherited_scr = inherited_scr->get_base_script();
}
add_script_function = !found_inherited_function;
@@ -690,9 +734,11 @@ void ConnectionsDock::_disconnect_all() {
while (child) {
Connection connection = child->get_metadata(0);
- ConnectDialog::ConnectionData cd = connection;
- undo_redo->add_do_method(selected_node, "disconnect", cd.signal, cd.get_callable());
- undo_redo->add_undo_method(selected_node, "connect", cd.signal, cd.get_callable(), cd.binds, cd.flags);
+ if (!_is_connection_inherited(connection)) {
+ ConnectDialog::ConnectionData cd = connection;
+ undo_redo->add_do_method(selected_node, "disconnect", cd.signal, cd.get_callable());
+ undo_redo->add_undo_method(selected_node, "connect", cd.signal, cd.get_callable(), cd.binds, cd.flags);
+ }
child = child->get_next();
}
@@ -737,49 +783,43 @@ bool ConnectionsDock::_is_item_signal(TreeItem &p_item) {
return (p_item.get_parent() == tree->get_root() || p_item.get_parent()->get_parent() == tree->get_root());
}
+bool ConnectionsDock::_is_connection_inherited(Connection &p_connection) {
+ Node *scene_root = EditorNode::get_singleton()->get_edited_scene();
+ Ref<PackedScene> scn = ResourceLoader::load(scene_root->get_scene_file_path());
+ ERR_FAIL_NULL_V(scn, false);
+
+ Ref<SceneState> state = scn->get_state();
+ ERR_FAIL_NULL_V(state, false);
+
+ Node *source = Object::cast_to<Node>(p_connection.signal.get_object());
+ Node *target = Object::cast_to<Node>(p_connection.callable.get_object());
+
+ const NodePath source_path = scene_root->get_path_to(source);
+ const NodePath target_path = scene_root->get_path_to(target);
+ const StringName signal_name = p_connection.signal.get_name();
+ const StringName method_name = p_connection.callable.get_method();
+
+ // If it cannot be found in PackedScene, this connection was inherited.
+ return !state->has_connection(source_path, signal_name, target_path, method_name, true);
+}
+
/*
* Open connection dialog with TreeItem data to CREATE a brand-new connection.
*/
void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) {
String signal_name = p_item.get_metadata(0).operator Dictionary()["name"];
const String &signal_name_ref = signal_name;
- String node_name = selected_node->get_name();
- for (int i = 0; i < node_name.length(); i++) { // TODO: Regex filter may be cleaner.
- char32_t c = node_name[i];
- if (!is_ascii_identifier_char(c)) {
- if (c == ' ') {
- // Replace spaces with underlines.
- c = '_';
- } else {
- // Remove any other characters.
- node_name.remove_at(i);
- i--;
- continue;
- }
- }
- node_name[i] = c;
- }
Node *dst_node = selected_node->get_owner() ? selected_node->get_owner() : selected_node;
if (!dst_node || dst_node->get_script().is_null()) {
dst_node = _find_first_script(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root());
}
- Dictionary subst;
- subst["NodeName"] = node_name.to_pascal_case();
- subst["nodeName"] = node_name.to_camel_case();
- subst["node_name"] = node_name.to_snake_case();
- subst["SignalName"] = signal_name.to_pascal_case();
- subst["signalName"] = signal_name.to_camel_case();
- subst["signal_name"] = signal_name.to_snake_case();
-
- String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst);
-
ConnectDialog::ConnectionData cd;
cd.source = selected_node;
cd.signal = StringName(signal_name_ref);
cd.target = dst_node;
- cd.method = StringName(dst_method);
+ cd.method = ConnectDialog::generate_method_callback_name(cd.source, signal_name, cd.target);
connect_dialog->popup_dialog(signal_name_ref);
connect_dialog->init(cd);
connect_dialog->set_title(TTR("Connect a Signal to a Method"));
@@ -816,13 +856,13 @@ void ConnectionsDock::_go_to_script(TreeItem &p_item) {
return;
}
- Ref<Script> script = cd.target->get_script();
+ Ref<Script> scr = cd.target->get_script();
- if (script.is_null()) {
+ if (scr.is_null()) {
return;
}
- if (script.is_valid() && ScriptEditor::get_singleton()->script_goto_method(script, cd.method)) {
+ if (scr.is_valid() && ScriptEditor::get_singleton()->script_goto_method(scr, cd.method)) {
EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
}
}
@@ -849,6 +889,19 @@ void ConnectionsDock::_handle_signal_menu_option(int p_option) {
}
}
+void ConnectionsDock::_signal_menu_about_to_popup() {
+ TreeItem *signal_item = tree->get_selected();
+
+ bool disable_disconnect_all = true;
+ for (int i = 0; i < signal_item->get_child_count(); i++) {
+ if (!signal_item->get_child(i)->has_meta("_inherited_connection")) {
+ disable_disconnect_all = false;
+ }
+ }
+
+ signal_menu->set_item_disabled(slot_menu->get_item_index(DISCONNECT_ALL), disable_disconnect_all);
+}
+
void ConnectionsDock::_handle_slot_menu_option(int p_option) {
TreeItem *item = tree->get_selected();
@@ -871,6 +924,13 @@ void ConnectionsDock::_handle_slot_menu_option(int p_option) {
}
}
+void ConnectionsDock::_slot_menu_about_to_popup() {
+ bool connection_is_inherited = tree->get_selected()->has_meta("_inherited_connection");
+
+ slot_menu->set_item_disabled(slot_menu->get_item_index(EDIT), connection_is_inherited);
+ slot_menu->set_item_disabled(slot_menu->get_item_index(DISCONNECT), connection_is_inherited);
+}
+
void ConnectionsDock::_rmb_pressed(Vector2 p_position, MouseButton p_button) {
if (p_button != MouseButton::RIGHT) {
return;
@@ -984,7 +1044,7 @@ void ConnectionsDock::update_tree() {
name = base;
}
- if (!icon.is_valid()) {
+ if (icon.is_null()) {
icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
}
@@ -1077,10 +1137,10 @@ void ConnectionsDock::update_tree() {
}
// List existing connections.
- List<Object::Connection> connections;
- selected_node->get_signal_connection_list(signal_name, &connections);
+ List<Object::Connection> existing_connections;
+ selected_node->get_signal_connection_list(signal_name, &existing_connections);
- for (const Object::Connection &F : connections) {
+ for (const Object::Connection &F : existing_connections) {
Connection connection = F;
if (!(connection.flags & CONNECT_PERSIST)) {
continue;
@@ -1116,6 +1176,12 @@ void ConnectionsDock::update_tree() {
connection_item->set_text(0, path);
connection_item->set_metadata(0, connection);
connection_item->set_icon(0, get_theme_icon(SNAME("Slot"), SNAME("EditorIcons")));
+
+ if (_is_connection_inherited(connection)) {
+ // The scene inherits this connection.
+ connection_item->set_custom_color(0, get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ connection_item->set_meta("_inherited_connection", true);
+ }
}
}
@@ -1168,6 +1234,7 @@ ConnectionsDock::ConnectionsDock() {
signal_menu = memnew(PopupMenu);
add_child(signal_menu);
signal_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_signal_menu_option));
+ signal_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_signal_menu_about_to_popup));
signal_menu->add_item(TTR("Connect..."), CONNECT);
signal_menu->add_item(TTR("Disconnect All"), DISCONNECT_ALL);
signal_menu->add_item(TTR("Copy Name"), COPY_NAME);
@@ -1175,6 +1242,7 @@ ConnectionsDock::ConnectionsDock() {
slot_menu = memnew(PopupMenu);
add_child(slot_menu);
slot_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_slot_menu_option));
+ slot_menu->connect("about_to_popup", callable_mp(this, &ConnectionsDock::_slot_menu_about_to_popup));
slot_menu->add_item(TTR("Edit..."), EDIT);
slot_menu->add_item(TTR("Go to Method"), GO_TO_SCRIPT);
slot_menu->add_item(TTR("Disconnect"), DISCONNECT);
@@ -1187,6 +1255,7 @@ ConnectionsDock::ConnectionsDock() {
add_theme_constant_override("separation", 3 * EDSCALE);
EDITOR_DEF("interface/editors/default_signal_callback_name", "_on_{node_name}_{signal_name}");
+ EDITOR_DEF("interface/editors/default_signal_callback_to_self_name", "_on_{signal_name}");
}
ConnectionsDock::~ConnectionsDock() {
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index db2f855617..126a0ca828 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -144,6 +144,7 @@ protected:
static void _bind_methods();
public:
+ static StringName generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target);
Node *get_source() const;
StringName get_signal_name() const;
NodePath get_dst_path() const;
@@ -211,13 +212,16 @@ class ConnectionsDock : public VBoxContainer {
void _tree_item_selected();
void _tree_item_activated();
bool _is_item_signal(TreeItem &p_item);
+ bool _is_connection_inherited(Connection &p_connection);
void _open_connection_dialog(TreeItem &p_item);
void _open_connection_dialog(ConnectDialog::ConnectionData p_cd);
void _go_to_script(TreeItem &p_item);
void _handle_signal_menu_option(int p_option);
+ void _signal_menu_about_to_popup();
void _handle_slot_menu_option(int p_option);
+ void _slot_menu_about_to_popup();
void _rmb_pressed(Vector2 p_position, MouseButton p_button);
void _close();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 3e72c6211d..6142856f75 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -126,10 +126,6 @@ bool CreateDialog::_should_hide_type(const String &p_type) const {
return true; // Do not show editor nodes.
}
- if (p_type == base_type && !EditorNode::get_editor_data().get_custom_types().has(p_type)) {
- return true; // Root is already added.
- }
-
if (ClassDB::class_exists(p_type)) {
if (!ClassDB::can_instantiate(p_type) || ClassDB::is_virtual(p_type)) {
return true; // Can't create abstract or virtual class.
@@ -217,18 +213,18 @@ void CreateDialog::_add_type(const String &p_type, const TypeCategory p_type_cat
inherited_type = TypeCategory::CPP_TYPE;
} else if (p_type_category == TypeCategory::PATH_TYPE) {
ERR_FAIL_COND(!ResourceLoader::exists(p_type, "Script"));
- Ref<Script> script = ResourceLoader::load(p_type, "Script");
- ERR_FAIL_COND(script.is_null());
+ Ref<Script> scr = ResourceLoader::load(p_type, "Script");
+ ERR_FAIL_COND(scr.is_null());
- Ref<Script> base = script->get_base_script();
+ Ref<Script> base = scr->get_base_script();
if (base.is_null()) {
String extends;
- script->get_language()->get_global_class_name(script->get_path(), &extends);
+ scr->get_language()->get_global_class_name(scr->get_path(), &extends);
inherits = extends;
inherited_type = TypeCategory::CPP_TYPE;
} else {
- inherits = script->get_language()->get_global_class_name(base->get_path());
+ inherits = scr->get_language()->get_global_class_name(base->get_path());
if (inherits.is_empty()) {
inherits = base->get_path();
inherited_type = TypeCategory::PATH_TYPE;
@@ -236,18 +232,18 @@ void CreateDialog::_add_type(const String &p_type, const TypeCategory p_type_cat
}
} else {
if (ScriptServer::is_global_class(p_type)) {
- Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_type);
- ERR_FAIL_COND(script.is_null());
+ Ref<Script> scr = EditorNode::get_editor_data().script_class_load_script(p_type);
+ ERR_FAIL_COND(scr.is_null());
- Ref<Script> base = script->get_base_script();
+ Ref<Script> base = scr->get_base_script();
if (base.is_null()) {
String extends;
- script->get_language()->get_global_class_name(script->get_path(), &extends);
+ scr->get_language()->get_global_class_name(scr->get_path(), &extends);
inherits = extends;
inherited_type = TypeCategory::CPP_TYPE;
} else {
- inherits = script->get_language()->get_global_class_name(base->get_path());
+ inherits = scr->get_language()->get_global_class_name(base->get_path());
if (inherits.is_empty()) {
inherits = base->get_path();
inherited_type = TypeCategory::PATH_TYPE;
@@ -311,7 +307,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String
// Don't collapse the root node or an abstract node on the first tree level.
bool should_collapse = p_type != base_type && (r_item->get_parent()->get_text(0) != base_type || can_instantiate);
- if (should_collapse && bool(EditorSettings::get_singleton()->get("docks/scene_tree/start_create_dialog_fully_expanded"))) {
+ if (should_collapse && bool(EDITOR_GET("docks/scene_tree/start_create_dialog_fully_expanded"))) {
should_collapse = false; // Collapse all nodes anyway.
}
r_item->set_collapsed(should_collapse);
@@ -343,6 +339,11 @@ String CreateDialog::_top_result(const Vector<String> p_candidates, const String
}
float CreateDialog::_score_type(const String &p_type, const String &p_search) const {
+ if (p_type == p_search) {
+ // Always favor an exact match (case-sensitive), since clicking a favorite will set the search text to the type.
+ return 1.0f;
+ }
+
float inverse_length = 1.f / float(p_type.length());
// Favor types where search term is a substring close to the start of the type.
@@ -351,13 +352,13 @@ float CreateDialog::_score_type(const String &p_type, const String &p_search) co
float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w);
// Favor shorter items: they resemble the search term more.
- w = 0.1f;
- score *= (1 - w) + w * (p_search.length() * inverse_length);
+ w = 0.9f;
+ score *= (1 - w) + w * MIN(1.0f, p_search.length() * inverse_length);
- score *= _is_type_preferred(p_type) ? 1.0f : 0.8f;
+ score *= _is_type_preferred(p_type) ? 1.0f : 0.9f;
// Add score for being a favorite type.
- score *= (favorite_list.find(p_type) > -1) ? 1.0f : 0.7f;
+ score *= (favorite_list.find(p_type) > -1) ? 1.0f : 0.8f;
// Look through at most 5 recent items
bool in_recent = false;
@@ -367,7 +368,7 @@ float CreateDialog::_score_type(const String &p_type, const String &p_search) co
break;
}
}
- score *= in_recent ? 1.0f : 0.8f;
+ score *= in_recent ? 1.0f : 0.9f;
return score;
}
@@ -751,9 +752,7 @@ CreateDialog::CreateDialog() {
favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
favorites->add_theme_constant_override("draw_guides", 1);
-#ifndef _MSC_VER
-#warning cannot forward drag data to a non control, must be fixed
-#endif
+ // Cannot forward drag data to a non control, must be fixed.
//favorites->set_drag_forwarding(this);
fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
diff --git a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
index 4c445eb766..ae8752eb6d 100644
--- a/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_protocol.cpp
@@ -656,7 +656,7 @@ int DebugAdapterProtocol::parse_variant(const Variant &p_var) {
bool DebugAdapterProtocol::process_message(const String &p_text) {
JSON json;
- ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Mal-formed message!");
+ ERR_FAIL_COND_V_MSG(json.parse(p_text) != OK, true, "Malformed message!");
Dictionary params = json.get_data();
bool completed = true;
@@ -921,11 +921,11 @@ void DebugAdapterProtocol::on_debug_stack_frame_vars(const int &p_size) {
ERR_FAIL_COND(!stackframe_list.has(frame));
List<int> scope_ids = stackframe_list.find(frame)->value;
for (List<int>::Element *E = scope_ids.front(); E; E = E->next()) {
- int variable_id = E->get();
- if (variable_list.has(variable_id)) {
- variable_list.find(variable_id)->value.clear();
+ int var_id = E->get();
+ if (variable_list.has(var_id)) {
+ variable_list.find(var_id)->value.clear();
} else {
- variable_list.insert(variable_id, Array());
+ variable_list.insert(var_id, Array());
}
}
}
@@ -941,7 +941,7 @@ void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
List<int> scope_ids = stackframe_list.find(frame)->value;
ERR_FAIL_COND(scope_ids.size() != 3);
ERR_FAIL_INDEX(stack_var.type, 3);
- int variable_id = scope_ids[stack_var.type];
+ int var_id = scope_ids[stack_var.type];
DAP::Variable variable;
@@ -950,7 +950,7 @@ void DebugAdapterProtocol::on_debug_stack_frame_var(const Array &p_data) {
variable.type = Variant::get_type_name(stack_var.value.get_type());
variable.variablesReference = parse_variant(stack_var.value);
- variable_list.find(variable_id)->value.push_back(variable.to_json());
+ variable_list.find(var_id)->value.push_back(variable.to_json());
_remaining_vars--;
}
diff --git a/editor/debugger/debug_adapter/debug_adapter_server.cpp b/editor/debugger/debug_adapter/debug_adapter_server.cpp
index 41e6b1f308..2e2361889d 100644
--- a/editor/debugger/debug_adapter/debug_adapter_server.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_server.cpp
@@ -62,12 +62,12 @@ void DebugAdapterServer::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- protocol._request_timeout = EditorSettings::get_singleton()->get("network/debug_adapter/request_timeout");
- protocol._sync_breakpoints = EditorSettings::get_singleton()->get("network/debug_adapter/sync_breakpoints");
- int remote_port = (int)_EDITOR_GET("network/debug_adapter/remote_port");
- if (remote_port != this->remote_port) {
- this->stop();
- this->start();
+ protocol._request_timeout = EDITOR_GET("network/debug_adapter/request_timeout");
+ protocol._sync_breakpoints = EDITOR_GET("network/debug_adapter/sync_breakpoints");
+ int port = (int)_EDITOR_GET("network/debug_adapter/remote_port");
+ if (port != remote_port) {
+ stop();
+ start();
}
} break;
}
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index 7ea6cedd2b..371aaf8617 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -166,11 +166,11 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
if (pinfo.hint_string == "Script") {
if (debug_obj->get_script() != var) {
debug_obj->set_script(Ref<RefCounted>());
- Ref<Script> script(var);
- if (!script.is_null()) {
- ScriptInstance *script_instance = script->placeholder_instance_create(debug_obj);
- if (script_instance) {
- debug_obj->set_script_and_instance(var, script_instance);
+ Ref<Script> scr(var);
+ if (!scr.is_null()) {
+ ScriptInstance *scr_instance = scr->placeholder_instance_create(debug_obj);
+ if (scr_instance) {
+ debug_obj->set_script_and_instance(var, scr_instance);
}
}
}
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 9fd7fa578f..68aff328ed 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -77,6 +77,7 @@ EditorDebuggerNode::EditorDebuggerNode() {
remote_scene_tree = memnew(EditorDebuggerTree);
remote_scene_tree->connect("object_selected", callable_mp(this, &EditorDebuggerNode::_remote_object_requested));
remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested));
+ remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed));
SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree);
SceneTreeDock::get_singleton()->connect("remote_tree_selected", callable_mp(this, &EditorDebuggerNode::request_remote_tree));
@@ -228,6 +229,12 @@ void EditorDebuggerNode::stop() {
if (server.is_valid()) {
server->stop();
EditorNode::get_log()->add_message("--- Debugging process stopped ---", EditorLog::MSG_TYPE_EDITOR);
+
+ if (EditorNode::get_singleton()->is_movie_maker_enabled()) {
+ // Request attention in case the user was doing something else when movie recording is finished.
+ DisplayServer::get_singleton()->window_request_attention();
+ }
+
server.unref();
}
// Also close all debugging sessions.
@@ -277,7 +284,7 @@ void EditorDebuggerNode::_notification(int p_what) {
// Remote scene tree update
remote_scene_tree_timeout -= get_process_delta_time();
if (remote_scene_tree_timeout < 0) {
- remote_scene_tree_timeout = EditorSettings::get_singleton()->get("debugger/remote_scene_tree_refresh_interval");
+ remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
if (remote_scene_tree->is_visible_in_tree()) {
get_current_debugger()->request_remote_tree();
}
@@ -286,7 +293,7 @@ void EditorDebuggerNode::_notification(int p_what) {
// Remote inspector update
inspect_edited_object_timeout -= get_process_delta_time();
if (inspect_edited_object_timeout < 0) {
- inspect_edited_object_timeout = EditorSettings::get_singleton()->get("debugger/remote_inspect_refresh_interval");
+ inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
get_current_debugger()->request_remote_object(obj->remote_object_id);
}
@@ -313,7 +320,7 @@ void EditorDebuggerNode::_notification(int p_what) {
EditorNode::get_singleton()->get_pause_button()->set_disabled(false);
// Switch to remote tree view if so desired.
- auto_switch_remote_scene_tree = (bool)EditorSettings::get_singleton()->get("debugger/auto_switch_to_remote_scene_tree");
+ auto_switch_remote_scene_tree = (bool)EDITOR_GET("debugger/auto_switch_to_remote_scene_tree");
if (auto_switch_remote_scene_tree) {
SceneTreeDock::get_singleton()->show_remote_tree();
}
@@ -477,13 +484,10 @@ void EditorDebuggerNode::_menu_option(int p_id) {
}
void EditorDebuggerNode::_update_debug_options() {
- bool keep_debugger_open = EditorSettings::get_singleton()->get_project_metadata("debug_options", "keep_debugger_open", false);
- bool debug_with_external_editor = EditorSettings::get_singleton()->get_project_metadata("debug_options", "debug_with_external_editor", false);
-
- if (keep_debugger_open) {
+ if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "keep_debugger_open", false).operator bool()) {
_menu_option(DEBUG_KEEP_DEBUGGER_OPEN);
}
- if (debug_with_external_editor) {
+ if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "debug_with_external_editor", false).operator bool()) {
_menu_option(DEBUG_WITH_EXTERNAL_EDITOR);
}
}
@@ -576,6 +580,24 @@ void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
remote_scene_tree->update_scene_tree(get_current_debugger()->get_remote_tree(), p_debugger);
}
+void EditorDebuggerNode::_remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {
+ if (p_button != MouseButton::LEFT) {
+ return;
+ }
+
+ TreeItem *item = Object::cast_to<TreeItem>(p_item);
+ ERR_FAIL_COND(!item);
+
+ if (p_id == EditorDebuggerTree::BUTTON_SUBSCENE) {
+ remote_scene_tree->emit_signal(SNAME("open"), item->get_meta("scene_file_path"));
+ } else if (p_id == EditorDebuggerTree::BUTTON_VISIBILITY) {
+ ObjectID obj_id = item->get_metadata(0);
+ ERR_FAIL_COND(obj_id.is_null());
+ get_current_debugger()->update_remote_object(obj_id, "visible", !item->get_meta("visible"));
+ get_current_debugger()->request_remote_tree();
+ }
+}
+
void EditorDebuggerNode::_remote_object_updated(ObjectID p_id, int p_debugger) {
if (p_debugger != tabs->get_current_tab()) {
return;
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index e79e60b180..305f18a652 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -129,6 +129,7 @@ protected:
void _debugger_wants_stop(int p_id);
void _debugger_changed(int p_tab);
void _remote_tree_updated(int p_debugger);
+ void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _remote_object_updated(ObjectID p_id, int p_debugger);
void _remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger);
void _remote_object_requested(ObjectID p_id, int p_debugger);
diff --git a/editor/debugger/editor_debugger_server.cpp b/editor/debugger/editor_debugger_server.cpp
index 63390825c6..dba0491cfc 100644
--- a/editor/debugger/editor_debugger_server.cpp
+++ b/editor/debugger/editor_debugger_server.cpp
@@ -72,8 +72,8 @@ String EditorDebuggerServerTCP::get_uri() const {
Error EditorDebuggerServerTCP::start(const String &p_uri) {
// Default host and port
- String bind_host = (String)EditorSettings::get_singleton()->get("network/debug/remote_host");
- int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ String bind_host = (String)EDITOR_GET("network/debug/remote_host");
+ int bind_port = (int)EDITOR_GET("network/debug/remote_port");
// Optionally override
if (!p_uri.is_empty() && p_uri != "tcp://") {
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 76efcd7190..4168efda26 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -65,6 +65,7 @@ void EditorDebuggerTree::_notification(int p_what) {
void EditorDebuggerTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::INT, "debugger")));
ADD_SIGNAL(MethodInfo("save_node", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "filename"), PropertyInfo(Variant::INT, "debugger")));
+ ADD_SIGNAL(MethodInfo("open"));
}
void EditorDebuggerTree::_scene_tree_selected() {
@@ -162,7 +163,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
}
item->set_metadata(0, node.id);
- // Set current item as collapsed if necessary (root is never collapsed)
+ // Set current item as collapsed if necessary (root is never collapsed).
if (parent) {
if (!unfold_cache.has(node.id)) {
item->set_collapsed(true);
@@ -178,7 +179,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
}
} else { // Must use path
if (last_path == _get_path(item)) {
- updating_scene_tree = false; // Force emission of new selection
+ updating_scene_tree = false; // Force emission of new selection.
item->select(0);
if (filter_changed) {
scroll_item = item;
@@ -187,6 +188,33 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
}
}
+ // Add buttons.
+ const Color remote_button_color = Color(1, 1, 1, 0.8);
+ if (!node.scene_file_path.is_empty()) {
+ String node_scene_file_path = node.scene_file_path;
+ Ref<Texture2D> button_icon = get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons"));
+ String tooltip = vformat(TTR("This node has been instantiated from a PackedScene file:\n%s\nClick to open the original file in the Editor."), node_scene_file_path);
+
+ item->set_meta("scene_file_path", node_scene_file_path);
+ item->add_button(0, button_icon, BUTTON_SUBSCENE, false, tooltip);
+ item->set_button_color(0, item->get_button_count(0) - 1, remote_button_color);
+ }
+
+ if (node.view_flags & SceneDebuggerTree::RemoteNode::VIEW_HAS_VISIBLE_METHOD) {
+ bool node_visible = node.view_flags & SceneDebuggerTree::RemoteNode::VIEW_VISIBLE;
+ bool node_visible_in_tree = node.view_flags & SceneDebuggerTree::RemoteNode::VIEW_VISIBLE_IN_TREE;
+ Ref<Texture2D> button_icon = get_theme_icon(node_visible ? SNAME("GuiVisibilityVisible") : SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"));
+ String tooltip = TTR("Toggle Visibility");
+
+ item->set_meta("visible", node_visible);
+ item->add_button(0, button_icon, BUTTON_VISIBILITY, false, tooltip);
+ if (ClassDB::is_parent_class(node.type_name, "CanvasItem") || ClassDB::is_parent_class(node.type_name, "Node3D")) {
+ item->set_button_color(0, item->get_button_count(0) - 1, node_visible_in_tree ? remote_button_color : Color(1, 1, 1, 0.6));
+ } else {
+ item->set_button_color(0, item->get_button_count(0) - 1, remote_button_color);
+ }
+ }
+
// Add in front of the parents stack if children are expected.
if (node.child_count) {
parents.push_front(Pair<TreeItem *, int>(item, node.child_count));
diff --git a/editor/debugger/editor_debugger_tree.h b/editor/debugger/editor_debugger_tree.h
index 5af3a0d84a..6d590cdb7a 100644
--- a/editor/debugger/editor_debugger_tree.h
+++ b/editor/debugger/editor_debugger_tree.h
@@ -65,6 +65,11 @@ protected:
void _notification(int p_what);
public:
+ enum Button {
+ BUTTON_SUBSCENE = 0,
+ BUTTON_VISIBILITY = 1,
+ };
+
virtual Variant get_drag_data(const Point2 &p_point) override;
String get_selected_path();
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 10b50a81e4..e2fd462f3a 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -349,12 +349,12 @@ void EditorPerformanceProfiler::update_monitors(const Vector<StringName> &p_name
void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values) {
for (KeyValue<StringName, Monitor> &E : monitors) {
- float data = 0.0f;
+ float value = 0.0f;
if (E.value.frame_index >= 0 && E.value.frame_index < p_values.size()) {
- data = p_values[E.value.frame_index];
+ value = p_values[E.value.frame_index];
}
- E.value.history.push_front(data);
- E.value.update_value(data);
+ E.value.history.push_front(value);
+ E.value.update_value(value);
}
marker_frame++;
monitor_draw->queue_redraw();
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index a882275375..35666a5566 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -85,7 +85,7 @@ void EditorProfiler::add_frame_metric(const Metric &p_metric, bool p_final) {
}
void EditorProfiler::clear() {
- int metric_size = EditorSettings::get_singleton()->get("debugger/profiler_frame_history_size");
+ int metric_size = EDITOR_GET("debugger/profiler_frame_history_size");
metric_size = CLAMP(metric_size, 60, 10000);
frame_metrics.clear();
frame_metrics.resize(metric_size);
@@ -308,9 +308,7 @@ void EditorProfiler::_update_plot() {
}
}
- Ref<Image> img;
- img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGBA8, graph_image);
+ Ref<Image> img = Image::create_from_data(w, h, false, Image::FORMAT_RGBA8, graph_image);
if (reset_texture) {
if (graph_texture.is_null()) {
diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp
index 8e7135f1c5..b8bc712ba6 100644
--- a/editor/debugger/editor_visual_profiler.cpp
+++ b/editor/debugger/editor_visual_profiler.cpp
@@ -92,7 +92,7 @@ void EditorVisualProfiler::add_frame_metric(const Metric &p_metric) {
}
void EditorVisualProfiler::clear() {
- int metric_size = EditorSettings::get_singleton()->get("debugger/profiler_frame_history_size");
+ int metric_size = EDITOR_GET("debugger/profiler_frame_history_size");
metric_size = CLAMP(metric_size, 60, 10000);
frame_metrics.clear();
frame_metrics.resize(metric_size);
@@ -298,9 +298,7 @@ void EditorVisualProfiler::_update_plot() {
}
}
- Ref<Image> img;
- img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGBA8, graph_image);
+ Ref<Image> img = Image::create_from_data(w, h, false, Image::FORMAT_RGBA8, graph_image);
if (reset_texture) {
if (graph_texture.is_null()) {
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 6bc1536cb9..f1f34b8ebb 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -747,8 +747,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
if (element) {
Callable &c = element->value;
ERR_FAIL_COND_MSG(c.is_null(), "Invalid callable registered: " + cap);
- Variant cmd = p_msg.substr(colon_index + 1), data = p_data;
- const Variant *args[2] = { &cmd, &data };
+ Variant cmd = p_msg.substr(colon_index + 1), cmd_data = p_data;
+ const Variant *args[2] = { &cmd, &cmd_data };
Variant retval;
Callable::CallError err;
c.callp(args, 2, retval, err);
@@ -895,9 +895,9 @@ void ScriptEditorDebugger::_clear_execution() {
}
void ScriptEditorDebugger::_set_breakpoint(const String &p_file, const int &p_line, const bool &p_enabled) {
- Ref<Script> script = ResourceLoader::load(p_file);
- emit_signal(SNAME("set_breakpoint"), script, p_line - 1, p_enabled);
- script.unref();
+ Ref<Script> scr = ResourceLoader::load(p_file);
+ emit_signal(SNAME("set_breakpoint"), scr, p_line - 1, p_enabled);
+ scr.unref();
}
void ScriptEditorDebugger::_clear_breakpoints() {
@@ -979,15 +979,15 @@ void ScriptEditorDebugger::stop() {
}
void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
- Array data;
- data.push_back(p_enable);
+ Array msg_data;
+ msg_data.push_back(p_enable);
switch (p_type) {
case PROFILER_NETWORK:
- _put_msg("profiler:multiplayer", data);
- _put_msg("profiler:rpc", data);
+ _put_msg("profiler:multiplayer", msg_data);
+ _put_msg("profiler:rpc", msg_data);
break;
case PROFILER_VISUAL:
- _put_msg("profiler:visual", data);
+ _put_msg("profiler:visual", msg_data);
break;
case PROFILER_SCRIPTS_SERVERS:
if (p_enable) {
@@ -995,11 +995,11 @@ void ScriptEditorDebugger::_profiler_activate(bool p_enable, int p_type) {
profiler_signature.clear();
// Add max funcs options to request.
Array opts;
- int max_funcs = EditorSettings::get_singleton()->get("debugger/profiler_frame_max_functions");
+ int max_funcs = EDITOR_GET("debugger/profiler_frame_max_functions");
opts.push_back(CLAMP(max_funcs, 16, 512));
- data.push_back(opts);
+ msg_data.push_back(opts);
}
- _put_msg("profiler:servers", data);
+ _put_msg("profiler:servers", msg_data);
break;
default:
ERR_FAIL_MSG("Invalid profiler type");
@@ -1563,8 +1563,22 @@ void ScriptEditorDebugger::_item_menu_id_pressed(int p_option) {
ti = ti->get_parent();
}
- // We only need the first child here (C++ source stack trace).
+ // Find the child with the "C++ Source".
+ // It's not at a fixed position as "C++ Error" may come first.
TreeItem *ci = ti->get_first_child();
+ const String cpp_source = "<" + TTR("C++ Source") + ">";
+ while (ci) {
+ if (ci->get_text(0) == cpp_source) {
+ break;
+ }
+ ci = ci->get_next();
+ }
+
+ if (!ci) {
+ WARN_PRINT_ED("No C++ source reference is available for this error.");
+ return;
+ }
+
// Parse back the `file:line @ method()` string.
const Vector<String> file_line_number = ci->get_text(1).split("@")[0].strip_edges().split(":");
ERR_FAIL_COND_MSG(file_line_number.size() < 2, "Incorrect C++ source stack trace file:line format (please report).");
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index b0ea289bbe..959c4ab92c 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -430,7 +430,7 @@ void DependencyRemoveDialog::_find_localization_remaps_of_removed_files(Vector<R
// Look for dependencies in the translation remaps.
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
if (remaps.has(path)) {
RemovedDependency dep;
@@ -544,28 +544,28 @@ void DependencyRemoveDialog::ok_pressed() {
// If the file we are deleting for e.g. the main scene, default environment,
// or audio bus layout, we must clear its definition in Project Settings.
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/config/icon"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("application/config/icon"))) {
ProjectSettings::get_singleton()->set("application/config/icon", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/run/main_scene"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("application/run/main_scene"))) {
ProjectSettings::get_singleton()->set("application/run/main_scene", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("application/boot_splash/image"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("application/boot_splash/image"))) {
ProjectSettings::get_singleton()->set("application/boot_splash/image", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("rendering/environment/defaults/default_environment"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("rendering/environment/defaults/default_environment"))) {
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("display/mouse_cursor/custom_image"))) {
ProjectSettings::get_singleton()->set("display/mouse_cursor/custom_image", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("gui/theme/custom"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom"))) {
ProjectSettings::get_singleton()->set("gui/theme/custom", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("gui/theme/custom_font"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("gui/theme/custom_font"))) {
ProjectSettings::get_singleton()->set("gui/theme/custom_font", "");
}
- if (files_to_delete[i] == String(ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout"))) {
+ if (files_to_delete[i] == String(GLOBAL_GET("audio/buses/default_bus_layout"))) {
ProjectSettings::get_singleton()->set("audio/buses/default_bus_layout", "");
}
@@ -792,14 +792,14 @@ void OrphanResourcesDialog::show() {
popup_centered_ratio(0.4);
}
-void OrphanResourcesDialog::_find_to_delete(TreeItem *p_item, List<String> &paths) {
+void OrphanResourcesDialog::_find_to_delete(TreeItem *p_item, List<String> &r_paths) {
while (p_item) {
if (p_item->get_cell_mode(0) == TreeItem::CELL_MODE_CHECK && p_item->is_checked(0)) {
- paths.push_back(p_item->get_metadata(0));
+ r_paths.push_back(p_item->get_metadata(0));
}
if (p_item->get_first_child()) {
- _find_to_delete(p_item->get_first_child(), paths);
+ _find_to_delete(p_item->get_first_child(), r_paths);
}
p_item = p_item->get_next();
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 6e39015ec3..7a523457ef 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -165,7 +165,7 @@ class OrphanResourcesDialog : public ConfirmationDialog {
bool _fill_owners(EditorFileSystemDirectory *efsd, HashMap<String, int> &refs, TreeItem *p_parent);
List<String> paths;
- void _find_to_delete(TreeItem *p_item, List<String> &paths);
+ void _find_to_delete(TreeItem *p_item, List<String> &r_paths);
void _delete_confirm();
void _button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index aaa5956c17..77697f4de1 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -183,16 +183,16 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
int pp = path.rfind("/");
- TreeItem *parent;
+ TreeItem *parent_item;
if (pp == -1) {
- parent = root;
+ parent_item = root;
} else {
String ppath = path.substr(0, pp);
ERR_CONTINUE(!dir_map.has(ppath));
- parent = dir_map[ppath];
+ parent_item = dir_map[ppath];
}
- TreeItem *ti = tree->create_item(parent);
+ TreeItem *ti = tree->create_item(parent_item);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_checked(0, true);
ti->set_editable(0, true);
@@ -284,17 +284,17 @@ void EditorAssetInstaller::ok_pressed() {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
da->make_dir(dirpath);
} else {
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
+ Vector<uint8_t> uncomp_data;
+ uncomp_data.resize(info.uncompressed_size);
//read
unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
unzCloseCurrentFile(pkg);
Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
if (f.is_valid()) {
- f->store_buffer(data.ptr(), data.size());
+ f->store_buffer(uncomp_data.ptr(), uncomp_data.size());
} else {
failed_files.push_back(path);
}
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 09dce869c9..46df618d57 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -919,10 +919,10 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
effect_options = memnew(PopupMenu);
effect_options->connect("index_pressed", callable_mp(this, &EditorAudioBus::_effect_add));
add_child(effect_options);
- List<StringName> effects;
- ClassDB::get_inheriters_from_class("AudioEffect", &effects);
- effects.sort_custom<StringName::AlphCompare>();
- for (const StringName &E : effects) {
+ List<StringName> effect_list;
+ ClassDB::get_inheriters_from_class("AudioEffect", &effect_list);
+ effect_list.sort_custom<StringName::AlphCompare>();
+ for (const StringName &E : effect_list) {
if (!ClassDB::can_instantiate(E) || ClassDB::is_virtual(E)) {
continue;
}
@@ -1036,7 +1036,7 @@ void EditorAudioBuses::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (drop_end) {
- drop_end->queue_delete();
+ drop_end->queue_free();
drop_end = nullptr;
}
} break;
@@ -1208,7 +1208,7 @@ void EditorAudioBuses::_load_layout() {
}
void EditorAudioBuses::_load_default_layout() {
- String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
+ String layout_path = GLOBAL_GET("audio/buses/default_bus_layout");
Ref<AudioBusLayout> state = ResourceLoader::load(layout_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
if (state.is_null()) {
@@ -1273,7 +1273,7 @@ EditorAudioBuses::EditorAudioBuses() {
add_child(top_hb);
file = memnew(Label);
- String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
+ String layout_path = GLOBAL_GET("audio/buses/default_bus_layout");
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
file->set_clip_text(true);
file->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1328,7 +1328,7 @@ EditorAudioBuses::EditorAudioBuses() {
set_v_size_flags(SIZE_EXPAND_FILL);
- edited_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
+ edited_path = GLOBAL_GET("audio/buses/default_bus_layout");
file_dialog = memnew(EditorFileDialog);
List<String> ext;
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 544b6c7141..90310bb43c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -222,15 +222,15 @@ void EditorAutoloadSettings::_autoload_edited() {
name = "autoload/" + name;
int order = ProjectSettings::get_singleton()->get_order(selected_autoload);
- String path = ProjectSettings::get_singleton()->get(selected_autoload);
+ String scr_path = GLOBAL_GET(selected_autoload);
undo_redo->create_action(TTR("Rename Autoload"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), name, path);
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), name, scr_path);
undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", name, order);
undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", selected_autoload);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), selected_autoload, path);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), selected_autoload, scr_path);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", selected_autoload, order);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name);
@@ -250,21 +250,21 @@ void EditorAutoloadSettings::_autoload_edited() {
String base = "autoload/" + ti->get_text(0);
int order = ProjectSettings::get_singleton()->get_order(base);
- String path = ProjectSettings::get_singleton()->get(base);
+ String scr_path = GLOBAL_GET(base);
- if (path.begins_with("*")) {
- path = path.substr(1, path.length());
+ if (scr_path.begins_with("*")) {
+ scr_path = scr_path.substr(1, scr_path.length());
}
// Singleton autoloads are represented with a leading "*" in their path.
if (checked) {
- path = "*" + path;
+ scr_path = "*" + scr_path;
}
undo_redo->create_action(TTR("Toggle Autoload Globals"));
- undo_redo->add_do_property(ProjectSettings::get_singleton(), base, path);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), base, ProjectSettings::get_singleton()->get(base));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), base, scr_path);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), base, GLOBAL_GET(base));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", base, order);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", base, order);
@@ -337,7 +337,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, Variant());
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, GLOBAL_GET(name));
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_persisting", name, true);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", order);
@@ -404,11 +404,11 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, "Can't autoload: " + p_path + ".");
Node *n = nullptr;
Ref<PackedScene> scn = res;
- Ref<Script> script = res;
+ Ref<Script> scr = res;
if (scn.is_valid()) {
n = scn->instantiate();
- } else if (script.is_valid()) {
- StringName ibt = script->get_instance_base_type();
+ } else if (scr.is_valid()) {
+ StringName ibt = scr->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
ERR_FAIL_COND_V_MSG(!valid_type, nullptr, "Script does not inherit from Node: " + p_path + ".");
@@ -417,7 +417,7 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
ERR_FAIL_COND_V_MSG(!obj, nullptr, "Cannot instance script for Autoload, expected 'Node' inheritance, got: " + String(ibt) + ".");
n = Object::cast_to<Node>(obj);
- n->set_script(script);
+ n->set_script(scr);
}
ERR_FAIL_COND_V_MSG(!n, nullptr, "Path in Autoload not a node or script: " + p_path + ".");
@@ -453,21 +453,21 @@ void EditorAutoloadSettings::update_autoload() {
}
String name = pi.name.get_slice("/", 1);
- String path = ProjectSettings::get_singleton()->get(pi.name);
+ String scr_path = GLOBAL_GET(pi.name);
if (name.is_empty()) {
continue;
}
AutoloadInfo info;
- info.is_singleton = path.begins_with("*");
+ info.is_singleton = scr_path.begins_with("*");
if (info.is_singleton) {
- path = path.substr(1, path.length());
+ scr_path = scr_path.substr(1, scr_path.length());
}
info.name = name;
- info.path = path;
+ info.path = scr_path;
info.order = ProjectSettings::get_singleton()->get_order(pi.name);
bool need_to_add = true;
@@ -499,7 +499,7 @@ void EditorAutoloadSettings::update_autoload() {
item->set_text(0, name);
item->set_editable(0, true);
- item->set_text(1, path);
+ item->set_text(1, scr_path);
item->set_selectable(1, true);
item->set_cell_mode(2, TreeItem::CELL_MODE_CHECK);
@@ -527,7 +527,7 @@ void EditorAutoloadSettings::update_autoload() {
}
if (info.node) {
- info.node->queue_delete();
+ info.node->queue_free();
info.node = nullptr;
}
@@ -745,13 +745,12 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
return false;
}
- const String &path = p_path;
- if (!FileAccess::exists(path)) {
+ if (!FileAccess::exists(p_path)) {
EditorNode::get_singleton()->show_warning(TTR("Can't add Autoload:") + "\n" + vformat(TTR("%s is an invalid path. File does not exist."), path));
return false;
}
- if (!path.begins_with("res://")) {
+ if (!p_path.begins_with("res://")) {
EditorNode::get_singleton()->show_warning(TTR("Can't add Autoload:") + "\n" + vformat(TTR("%s is an invalid path. Not in resource path (res://)."), path));
return false;
}
@@ -762,10 +761,10 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
undo_redo->create_action(TTR("Add Autoload"));
// Singleton autoloads are represented with a leading "*" in their path.
- undo_redo->add_do_property(ProjectSettings::get_singleton(), name, "*" + path);
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), name, "*" + p_path);
if (ProjectSettings::get_singleton()->has_setting(name)) {
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, GLOBAL_GET(name));
} else {
undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, Variant());
}
@@ -792,7 +791,7 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) {
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, Variant());
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, GLOBAL_GET(name));
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_persisting", name, true);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", order);
@@ -829,21 +828,21 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
}
String name = pi.name.get_slice("/", 1);
- String path = ProjectSettings::get_singleton()->get(pi.name);
+ String scr_path = GLOBAL_GET(pi.name);
if (name.is_empty()) {
continue;
}
AutoloadInfo info;
- info.is_singleton = path.begins_with("*");
+ info.is_singleton = scr_path.begins_with("*");
if (info.is_singleton) {
- path = path.substr(1, path.length());
+ scr_path = scr_path.substr(1, scr_path.length());
}
info.name = name;
- info.path = path;
+ info.path = scr_path;
info.order = ProjectSettings::get_singleton()->get_order(pi.name);
if (info.is_singleton) {
diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp
index 0f0ab4a339..96c69c0bd1 100644
--- a/editor/editor_build_profile.cpp
+++ b/editor/editor_build_profile.cpp
@@ -255,8 +255,7 @@ Error EditorBuildProfile::save_to_file(const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'.");
- JSON json;
- String text = json.stringify(data, "\t");
+ String text = JSON::stringify(data, "\t");
f->store_string(text);
return OK;
}
@@ -876,7 +875,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
import_profile = memnew(EditorFileDialog);
add_child(import_profile);
import_profile->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- import_profile->add_filter("*.build", TTR("Egine Build Profile"));
+ import_profile->add_filter("*.build", TTR("Engine Build Profile"));
import_profile->connect("files_selected", callable_mp(this, &EditorBuildProfileManager::_import_profile));
import_profile->set_title(TTR("Load Profile"));
import_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
@@ -884,7 +883,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
export_profile = memnew(EditorFileDialog);
add_child(export_profile);
export_profile->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
- export_profile->add_filter("*.build", TTR("Egine Build Profile"));
+ export_profile->add_filter("*.build", TTR("Engine Build Profile"));
export_profile->connect("file_selected", callable_mp(this, &EditorBuildProfileManager::_export_profile));
export_profile->set_title(TTR("Export Profile"));
export_profile->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
index b3e84771d0..15200552b4 100644
--- a/editor/editor_command_palette.h
+++ b/editor/editor_command_palette.h
@@ -66,7 +66,11 @@ class EditorCommandPalette : public ConfirmationDialog {
struct CommandHistoryComparator {
_FORCE_INLINE_ bool operator()(const CommandEntry &A, const CommandEntry &B) const {
- return A.last_used > B.last_used;
+ if (A.last_used == B.last_used) {
+ return A.display_name < B.display_name;
+ } else {
+ return A.last_used > B.last_used;
+ }
}
};
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index d1ea0f2814..6d8f0df452 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -1008,7 +1008,7 @@ void EditorData::script_class_save_icon_paths() {
Dictionary old;
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- old = ProjectSettings::get_singleton()->get("_global_script_class_icons");
+ old = GLOBAL_GET("_global_script_class_icons");
}
if ((!old.is_empty() || d.is_empty()) && d.hash() == old.hash()) {
return;
@@ -1028,7 +1028,7 @@ void EditorData::script_class_load_icon_paths() {
script_class_clear_icon_paths();
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- Dictionary d = ProjectSettings::get_singleton()->get("_global_script_class_icons");
+ Dictionary d = GLOBAL_GET("_global_script_class_icons");
List<Variant> keys;
d.get_key_list(&keys);
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index f464ca3b3c..0c5c15a0ed 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -57,7 +57,7 @@ void EditorDirDialog::_update_dir(TreeItem *p_item, EditorFileSystemDirectory *p
}
//this should be handled by EditorFileSystem already
- //bool show_hidden = EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files");
+ //bool show_hidden = EDITOR_GET("filesystem/file_dialog/show_hidden_files");
updating = false;
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
TreeItem *ti = tree->create_item(p_item);
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 9fa08a0adb..ee02916a5f 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -131,11 +131,11 @@ void EditorFileDialog::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- bool is_showing_hidden = EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files");
+ bool is_showing_hidden = EDITOR_GET("filesystem/file_dialog/show_hidden_files");
if (show_hidden_files != is_showing_hidden) {
set_show_hidden_files(is_showing_hidden);
}
- set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
+ set_display_mode((DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
// DO NOT CALL UPDATE FILE LIST HERE, ALL HUNDREDS OF HIDDEN DIALOGS WILL RESPOND, CALL INVALIDATE INSTEAD
invalidate();
@@ -740,7 +740,7 @@ void EditorFileDialog::update_file_name() {
// DO NOT USE THIS FUNCTION UNLESS NEEDED, CALL INVALIDATE() INSTEAD.
void EditorFileDialog::update_file_list() {
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
Ref<Texture2D> folder_thumbnail;
Ref<Texture2D> file_thumbnail;
@@ -1023,10 +1023,10 @@ void EditorFileDialog::set_current_path(const String &p_path) {
if (pos == -1) {
set_current_file(p_path);
} else {
- String dir = p_path.substr(0, pos);
- String file = p_path.substr(pos + 1, p_path.length());
- set_current_dir(dir);
- set_current_file(file);
+ String path_dir = p_path.substr(0, pos);
+ String path_file = p_path.substr(pos + 1, p_path.length());
+ set_current_dir(path_dir);
+ set_current_file(path_file);
}
}
@@ -1614,26 +1614,26 @@ void EditorFileDialog::set_default_display_mode(DisplayMode p_mode) {
}
void EditorFileDialog::_save_to_recent() {
- String dir = get_current_dir();
- Vector<String> recent = EditorSettings::get_singleton()->get_recent_dirs();
+ String cur_dir = get_current_dir();
+ Vector<String> recent_new = EditorSettings::get_singleton()->get_recent_dirs();
const int max = 20;
int count = 0;
- bool res = dir.begins_with("res://");
+ bool res = cur_dir.begins_with("res://");
- for (int i = 0; i < recent.size(); i++) {
- bool cres = recent[i].begins_with("res://");
- if (recent[i] == dir || (res == cres && count > max)) {
- recent.remove_at(i);
+ for (int i = 0; i < recent_new.size(); i++) {
+ bool cres = recent_new[i].begins_with("res://");
+ if (recent_new[i] == cur_dir || (res == cres && count > max)) {
+ recent_new.remove_at(i);
i--;
} else {
count++;
}
}
- recent.insert(0, dir);
+ recent_new.insert(0, cur_dir);
- EditorSettings::get_singleton()->set_recent_dirs(recent);
+ EditorSettings::get_singleton()->set_recent_dirs(recent_new);
}
void EditorFileDialog::set_disable_overwrite_warning(bool p_disable) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 9153640115..ce06631fdd 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -919,11 +919,11 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *lang = ScriptServer::get_language(i);
if (lang->supports_documentation() && fi->type == lang->get_type()) {
- Ref<Script> script = ResourceLoader::load(path);
- if (script == nullptr) {
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr == nullptr) {
continue;
}
- Vector<DocData::ClassDoc> docs = script->get_documentation();
+ Vector<DocData::ClassDoc> docs = scr->get_documentation();
for (int j = 0; j < docs.size(); j++) {
EditorHelp::get_doc_data()->add_doc(docs[j]);
}
@@ -1888,7 +1888,7 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String
if (load_default && ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) {
//use defaults if exist
- Dictionary d = ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name());
+ Dictionary d = GLOBAL_GET("importer_defaults/" + importer->get_importer_name());
List<Variant> v;
d.get_key_list(&v);
@@ -1902,8 +1902,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String
List<String> import_variants;
List<String> gen_files;
- Variant metadata;
- Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files, &metadata);
+ Variant meta;
+ Error err = importer->import(p_file, base_path, params, &import_variants, &gen_files, &meta);
if (err != OK) {
ERR_PRINT("Error importing '" + p_file + "'.");
@@ -1955,8 +1955,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String
f->store_line("valid=false");
}
- if (metadata != Variant()) {
- f->store_line("metadata=" + metadata.get_construct_string());
+ if (meta != Variant()) {
+ f->store_line("metadata=" + meta.get_construct_string());
}
f->store_line("");
@@ -2108,11 +2108,11 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
reimport_files.sort();
- bool use_threads = GLOBAL_GET("editor/import/use_multiple_threads");
+ bool use_multiple_threads = GLOBAL_GET("editor/import/use_multiple_threads");
int from = 0;
for (int i = 0; i < reimport_files.size(); i++) {
- if (use_threads && reimport_files[i].threaded) {
+ if (use_multiple_threads && reimport_files[i].threaded) {
if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) {
if (from - i == 0) {
//single file, do not use threads
@@ -2124,16 +2124,16 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
importer->import_threaded_begin();
- ImportThreadData data;
- data.max_index = from;
- data.reimport_from = from;
- data.reimport_files = reimport_files.ptr();
+ ImportThreadData tdata;
+ tdata.max_index = from;
+ tdata.reimport_from = from;
+ tdata.reimport_files = reimport_files.ptr();
- WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &EditorFileSystem::_reimport_thread, &data, i - from + 1, -1, false, vformat(TTR("Import resources of type: %s"), reimport_files[from].importer));
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &EditorFileSystem::_reimport_thread, &tdata, i - from + 1, -1, false, vformat(TTR("Import resources of type: %s"), reimport_files[from].importer));
int current_index = from - 1;
do {
- if (current_index < data.max_index) {
- current_index = data.max_index;
+ if (current_index < tdata.max_index) {
+ current_index = tdata.max_index;
pr.step(reimport_files[current_index].path.get_file(), current_index);
}
OS::get_singleton()->delay_usec(1);
@@ -2259,7 +2259,7 @@ void EditorFileSystem::move_group_file(const String &p_path, const String &p_new
ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const String &p_path, bool p_generate) {
if (!p_path.is_resource_file() || p_path.begins_with(ProjectSettings::get_singleton()->get_project_data_path())) {
- //saved externally (configuration file) or internal file, do not assign an ID.
+ // Saved externally (configuration file) or internal file, do not assign an ID.
return ResourceUID::INVALID_ID;
}
@@ -2267,15 +2267,21 @@ ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const
int cpos = -1;
if (!singleton->_find_file(p_path, &fs, cpos)) {
+ // Fallback to ResourceLoader if filesystem cache fails (can happen during scanning etc.).
+ ResourceUID::ID fallback = ResourceLoader::get_resource_uid(p_path);
+ if (fallback != ResourceUID::INVALID_ID) {
+ return fallback;
+ }
+
if (p_generate) {
- return ResourceUID::get_singleton()->create_id(); //just create a new one, we will be notified of save anyway and fetch the right UUID at that time, to keep things simple.
+ return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UUID at that time, to keep things simple.
} else {
return ResourceUID::INVALID_ID;
}
} else if (fs->files[cpos]->uid != ResourceUID::INVALID_ID) {
return fs->files[cpos]->uid;
} else if (p_generate) {
- return ResourceUID::get_singleton()->create_id(); //just create a new one, we will be notified of save anyway and fetch the right UUID at that time, to keep things simple.
+ return ResourceUID::get_singleton()->create_id(); // Just create a new one, we will be notified of save anyway and fetch the right UUID at that time, to keep things simple.
} else {
return ResourceUID::INVALID_ID;
}
@@ -2382,7 +2388,7 @@ void EditorFileSystem::_update_extensions() {
valid_extensions.insert(E);
}
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
if (valid_extensions.has(E)) {
continue;
@@ -2422,7 +2428,7 @@ EditorFileSystem::EditorFileSystem() {
scan_total = 0;
update_script_classes_queued.clear();
- ResourceUID::get_singleton()->clear(); //will be updated on scan
+ MessageQueue::get_singleton()->push_callable(callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear)); // Will be updated on scan.
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
}
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index c31d13d122..51ebc31df3 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -57,6 +57,24 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin
return font;
}
+Ref<SystemFont> load_system_font(const PackedStringArray &p_names, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
+ Ref<SystemFont> font;
+ font.instantiate();
+
+ font->set_font_names(p_names);
+ font->set_multichannel_signed_distance_field(p_msdf);
+ font->set_antialiasing(p_aa);
+ font->set_hinting(p_hinting);
+ font->set_force_autohinter(p_autohint);
+ font->set_subpixel_positioning(p_font_subpixel_positioning);
+
+ if (r_fallbacks != nullptr) {
+ r_fallbacks->push_back(font);
+ }
+
+ return font;
+}
+
Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
Ref<FontFile> font;
font.instantiate();
@@ -91,9 +109,9 @@ Ref<FontVariation> make_bold_font(const Ref<Font> &p_font, double p_embolden, Ty
void editor_register_fonts(Ref<Theme> p_theme) {
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)EditorSettings::get_singleton()->get("interface/editor/font_antialiasing");
- int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting");
- TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
+ TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)EDITOR_GET("interface/editor/font_antialiasing");
+ int font_hinting_setting = (int)EDITOR_GET("interface/editor/font_hinting");
+ TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EDITOR_GET("interface/editor/font_subpixel_positioning");
TextServer::Hinting font_hinting;
TextServer::Hinting font_mono_hinting;
@@ -166,6 +184,20 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
Ref<FontVariation> fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold);
Ref<FontVariation> japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold);
+
+ if (OS::get_singleton()->has_feature("system_fonts")) {
+ PackedStringArray emoji_font_names;
+ emoji_font_names.push_back("Apple Color Emoji");
+ emoji_font_names.push_back("Segoe UI Emoji");
+ emoji_font_names.push_back("Noto Color Emoji");
+ emoji_font_names.push_back("Twitter Color Emoji");
+ emoji_font_names.push_back("OpenMoji");
+ emoji_font_names.push_back("EmojiOne Color");
+ Ref<SystemFont> emoji_font = load_system_font(emoji_font_names, font_hinting, font_antialiasing, true, font_subpixel_positioning, false);
+ fallbacks.push_back(emoji_font);
+ fallbacks_bold.push_back(emoji_font);
+ }
+
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
@@ -173,9 +205,9 @@ void editor_register_fonts(Ref<Theme> p_theme) {
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
- String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font");
- String custom_font_path_bold = EditorSettings::get_singleton()->get("interface/editor/main_font_bold");
- String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font");
+ String custom_font_path = EDITOR_GET("interface/editor/main_font");
+ String custom_font_path_bold = EDITOR_GET("interface/editor/main_font_bold");
+ String custom_font_path_source = EDITOR_GET("interface/editor/code_font");
Ref<FontVariation> default_fc;
default_fc.instantiate();
@@ -283,7 +315,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_other_fc = mono_fc->duplicate();
// Enable contextual alternates (coding ligatures) and custom features for the source editor font.
- int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures");
+ int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
switch (ot_mode) {
case 1: { // Disable ligatures.
Dictionary ftrs;
@@ -291,7 +323,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
mono_fc->set_opentype_features(ftrs);
} break;
case 2: { // Custom.
- Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(",");
+ Vector<String> subtag = String(EDITOR_GET("interface/editor/code_font_custom_opentype_features")).split(",");
Dictionary ftrs;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
@@ -317,6 +349,24 @@ void editor_register_fonts(Ref<Theme> p_theme) {
mono_other_fc->set_opentype_features(ftrs);
}
+ // Use fake bold/italics to style the editor log's `print_rich()` output.
+ // Use stronger embolden strength to make bold easier to distinguish from regular text.
+ Ref<FontVariation> mono_other_fc_bold = mono_other_fc->duplicate();
+ mono_other_fc_bold->set_variation_embolden(0.8);
+
+ Ref<FontVariation> mono_other_fc_italic = mono_other_fc->duplicate();
+ mono_other_fc_italic->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
+
+ Ref<FontVariation> mono_other_fc_bold_italic = mono_other_fc->duplicate();
+ mono_other_fc_bold_italic->set_variation_embolden(0.8);
+ mono_other_fc_bold_italic->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
+
+ Ref<FontVariation> mono_other_fc_mono = mono_other_fc->duplicate();
+ // Use a different font style to distinguish `[code]` in rich prints.
+ // This emulates the "faint" styling used in ANSI escape codes by using a slightly thinner font.
+ mono_other_fc_mono->set_variation_embolden(-0.25);
+ mono_other_fc_mono->set_variation_transform(Transform2D(1.0, 0.1, 0.0, 1.0, 0.0, 0.0));
+
Ref<FontVariation> italic_fc = default_fc->duplicate();
italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
@@ -386,6 +436,10 @@ void editor_register_fonts(Ref<Theme> p_theme) {
p_theme->set_font_size("output_source_size", "EditorFonts", int(EDITOR_GET("run/output/font_size")) * EDSCALE);
p_theme->set_font("output_source", "EditorFonts", mono_other_fc);
+ p_theme->set_font("output_source_bold", "EditorFonts", mono_other_fc_bold);
+ p_theme->set_font("output_source_italic", "EditorFonts", mono_other_fc_italic);
+ p_theme->set_font("output_source_bold_italic", "EditorFonts", mono_other_fc_bold_italic);
+ p_theme->set_font("output_source_mono", "EditorFonts", mono_other_fc_mono);
p_theme->set_font_size("status_source_size", "EditorFonts", default_font_size);
p_theme->set_font("status_source", "EditorFonts", mono_other_fc);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 745dcdd04c..ddb9bb30f1 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -184,9 +184,9 @@ void EditorHelp::_class_desc_input(const Ref<InputEvent> &p_input) {
void EditorHelp::_class_desc_resized(bool p_force_update_theme) {
// Add extra horizontal margins for better readability.
// The margins increase as the width of the editor help container increases.
- Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ Ref<Font> font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
int font_size = get_theme_font_size(SNAME("doc_source_size"), SNAME("EditorFonts"));
- real_t char_width = doc_code_font->get_char_size('x', font_size).width;
+ real_t char_width = font->get_char_size('x', font_size).width;
const int new_display_margin = MAX(30 * EDSCALE, get_parent_anchorable_rect().size.width - char_width * 120 * EDSCALE) * 0.5;
if (display_margin != new_display_margin || p_force_update_theme) {
display_margin = new_display_margin;
@@ -368,8 +368,29 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
class_desc->pop();
if (!p_method.qualifiers.is_empty()) {
class_desc->push_color(qualifier_color);
- class_desc->add_text(" ");
- _add_text(p_method.qualifiers);
+
+ PackedStringArray qualifiers = p_method.qualifiers.split_spaces();
+ for (const String &qualifier : qualifiers) {
+ String hint;
+ if (qualifier == "vararg") {
+ hint = TTR("This method supports a variable number of arguments.");
+ } else if (qualifier == "virtual") {
+ hint = TTR("This method is called by the engine.\nIt can be overriden to customise built-in behavior.");
+ } else if (qualifier == "const") {
+ hint = TTR("This method has no side effects.\nIt does not modify the object in any way.");
+ } else if (qualifier == "static") {
+ hint = TTR("This method does not need an instance to be called.\nIt can be called directly using the class name.");
+ }
+
+ class_desc->add_text(" ");
+ if (!hint.is_empty()) {
+ class_desc->push_hint(hint);
+ class_desc->add_text(qualifier);
+ class_desc->pop();
+ } else {
+ class_desc->add_text(qualifier);
+ }
+ }
class_desc->pop();
}
@@ -412,13 +433,13 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
}
void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons) {
- Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ Ref<Font> font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
class_desc->pop(); // title font size
class_desc->pop(); // title font
class_desc->pop(); // title color
class_desc->add_newline();
- class_desc->push_font(doc_code_font);
+ class_desc->push_font(font);
class_desc->push_indent(1);
class_desc->push_table(2);
class_desc->set_table_column_expand(1, true);
@@ -479,9 +500,8 @@ void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods,
}
void EditorHelp::_update_method_descriptions(const DocData::ClassDoc p_classdoc, const Vector<DocData::MethodDoc> p_methods, const String &p_method_type) {
- Ref<Font> doc_font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
- Ref<Font> doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts"));
- Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
+ Ref<Font> font = get_theme_font(SNAME("doc"), SNAME("EditorFonts"));
+ Ref<Font> code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts"));
String link_color_text = title_color.to_html(false);
class_desc->pop(); // title font size
class_desc->pop(); // title font
@@ -501,7 +521,7 @@ void EditorHelp::_update_method_descriptions(const DocData::ClassDoc p_classdoc,
}
for (int i = 0; i < methods_filtered.size(); i++) {
- class_desc->push_font(doc_code_font);
+ class_desc->push_font(code_font);
_add_method(methods_filtered[i], false);
class_desc->pop();
@@ -509,7 +529,7 @@ void EditorHelp::_update_method_descriptions(const DocData::ClassDoc p_classdoc,
class_desc->add_newline();
class_desc->push_color(text_color);
- class_desc->push_font(doc_font);
+ class_desc->push_font(font);
class_desc->push_indent(1);
if (methods_filtered[i].errors_returned.size()) {
class_desc->append_text(TTR("Error codes returned:"));
@@ -928,7 +948,7 @@ void EditorHelp::_update_doc() {
bool constructor_descriptions = false;
bool method_descriptions = false;
bool operator_descriptions = false;
- bool sort_methods = EditorSettings::get_singleton()->get("text_editor/help/sort_functions_alphabetically");
+ bool sort_methods = EDITOR_GET("text_editor/help/sort_functions_alphabetically");
Vector<DocData::MethodDoc> methods;
@@ -2305,7 +2325,6 @@ EditorHelpBit::EditorHelpBit() {
rich_text = memnew(RichTextLabel);
add_child(rich_text);
rich_text->connect("meta_clicked", callable_mp(this, &EditorHelpBit::_meta_clicked));
- rich_text->set_override_selected_font_color(false);
rich_text->set_fit_content_height(true);
set_custom_minimum_size(Size2(0, 50 * EDSCALE));
}
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 1b8146a0f0..286dcf4b8e 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -320,6 +320,11 @@ bool EditorHelpSearch::Runner::_phase_match_classes_init() {
matched_item = nullptr;
match_highest_score = 0;
+ terms = term.split_spaces();
+ if (terms.is_empty()) {
+ terms.append(term);
+ }
+
return true;
}
@@ -350,62 +355,38 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
// Make an exception for annotations, since there are not that many of them.
if (term.length() > 1 || term == "@") {
if (search_flags & SEARCH_CONSTRUCTORS) {
- for (int i = 0; i < class_doc.constructors.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.constructors.push_back(const_cast<DocData::MethodDoc *>(&class_doc.constructors[i]));
- }
- }
+ _match_method_name_and_push_back(class_doc.constructors, &match.constructors);
}
if (search_flags & SEARCH_METHODS) {
- for (int i = 0; i < class_doc.methods.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i]));
- }
- }
+ _match_method_name_and_push_back(class_doc.methods, &match.methods);
}
if (search_flags & SEARCH_OPERATORS) {
- for (int i = 0; i < class_doc.operators.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.operators[i].name : class_doc.operators[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.operators.push_back(const_cast<DocData::MethodDoc *>(&class_doc.operators[i]));
- }
- }
+ _match_method_name_and_push_back(class_doc.operators, &match.operators);
}
if (search_flags & SEARCH_SIGNALS) {
for (int i = 0; i < class_doc.signals.size(); i++) {
- if (_match_string(term, class_doc.signals[i].name)) {
+ if (_all_terms_in_name(class_doc.signals[i].name)) {
match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i]));
}
}
}
if (search_flags & SEARCH_CONSTANTS) {
for (int i = 0; i < class_doc.constants.size(); i++) {
- if (_match_string(term, class_doc.constants[i].name)) {
+ if (_all_terms_in_name(class_doc.constants[i].name)) {
match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i]));
}
}
}
if (search_flags & SEARCH_PROPERTIES) {
for (int i = 0; i < class_doc.properties.size(); i++) {
- if (_match_string(term, class_doc.properties[i].name) || _match_string(term, class_doc.properties[i].getter) || _match_string(term, class_doc.properties[i].setter)) {
+ if (_all_terms_in_name(class_doc.properties[i].name)) {
match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i]));
}
}
}
if (search_flags & SEARCH_THEME_ITEMS) {
for (int i = 0; i < class_doc.theme_properties.size(); i++) {
- if (_match_string(term, class_doc.theme_properties[i].name)) {
+ if (_all_terms_in_name(class_doc.theme_properties[i].name)) {
match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i]));
}
}
@@ -417,7 +398,6 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
}
}
}
- matches[class_doc.name] = match;
}
matches[class_doc.name] = match;
}
@@ -470,7 +450,7 @@ bool EditorHelpSearch::Runner::_phase_member_items() {
return false;
}
- TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item;
+ TreeItem *parent_item = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item;
bool constructor_created = false;
for (int i = 0; i < match.methods.size(); i++) {
String text = match.methods[i]->name;
@@ -484,23 +464,23 @@ bool EditorHelpSearch::Runner::_phase_member_items() {
continue;
}
}
- _create_method_item(parent, match.doc, text, match.methods[i]);
+ _create_method_item(parent_item, match.doc, text, match.methods[i]);
}
for (int i = 0; i < match.signals.size(); i++) {
- _create_signal_item(parent, match.doc, match.signals[i]);
+ _create_signal_item(parent_item, match.doc, match.signals[i]);
}
for (int i = 0; i < match.constants.size(); i++) {
- _create_constant_item(parent, match.doc, match.constants[i]);
+ _create_constant_item(parent_item, match.doc, match.constants[i]);
}
for (int i = 0; i < match.properties.size(); i++) {
- _create_property_item(parent, match.doc, match.properties[i]);
+ _create_property_item(parent_item, match.doc, match.properties[i]);
}
for (int i = 0; i < match.theme_properties.size(); i++) {
- _create_theme_property_item(parent, match.doc, match.theme_properties[i]);
+ _create_theme_property_item(parent_item, match.doc, match.theme_properties[i]);
}
for (int i = 0; i < match.annotations.size(); i++) {
// Hide the redundant leading @ symbol.
- _create_annotation_item(parent, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]);
+ _create_annotation_item(parent_item, match.doc, match.annotations[i]->name.substr(1), match.annotations[i]);
}
++iterator_match;
@@ -514,6 +494,28 @@ bool EditorHelpSearch::Runner::_phase_select_match() {
return true;
}
+void EditorHelpSearch::Runner::_match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<DocData::MethodDoc *> *r_match_methods) {
+ // Constructors, Methods, Operators...
+ for (int i = 0; i < p_methods.size(); i++) {
+ String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? p_methods[i].name : p_methods[i].name.to_lower();
+ if (_all_terms_in_name(method_name) ||
+ (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
+ (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
+ (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
+ r_match_methods->push_back(const_cast<DocData::MethodDoc *>(&p_methods[i]));
+ }
+ }
+}
+
+bool EditorHelpSearch::Runner::_all_terms_in_name(String name) {
+ for (int i = 0; i < terms.size(); i++) {
+ if (!_match_string(terms[i], name)) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const {
if (search_flags & SEARCH_CASE_SENSITIVE) {
return p_string.find(p_term) > -1;
@@ -565,19 +567,19 @@ TreeItem *EditorHelpSearch::Runner::_create_class_hierarchy(const ClassMatch &p_
}
// Ensure parent nodes are created first.
- TreeItem *parent = root_item;
+ TreeItem *parent_item = root_item;
if (!p_match.doc->inherits.is_empty()) {
if (class_items.has(p_match.doc->inherits)) {
- parent = class_items[p_match.doc->inherits];
+ parent_item = class_items[p_match.doc->inherits];
} else {
ClassMatch &base_match = matches[p_match.doc->inherits];
if (base_match.doc) {
- parent = _create_class_hierarchy(base_match);
+ parent_item = _create_class_hierarchy(base_match);
}
}
}
- TreeItem *class_item = _create_class_item(parent, p_match.doc, !p_match.name);
+ TreeItem *class_item = _create_class_item(parent_item, p_match.doc, !p_match.name);
class_items[p_match.doc->name] = class_item;
return class_item;
}
diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h
index efd8645cd7..a8bd219b89 100644
--- a/editor/editor_help_search.h
+++ b/editor/editor_help_search.h
@@ -119,6 +119,7 @@ class EditorHelpSearch::Runner : public RefCounted {
Control *ui_service = nullptr;
Tree *results_tree = nullptr;
String term;
+ Vector<String> terms;
int search_flags;
Ref<Texture2D> empty_icon;
@@ -145,6 +146,8 @@ class EditorHelpSearch::Runner : public RefCounted {
String _build_method_tooltip(const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) const;
+ void _match_method_name_and_push_back(Vector<DocData::MethodDoc> &p_methods, Vector<DocData::MethodDoc *> *r_match_methods);
+ bool _all_terms_in_name(String name);
bool _match_string(const String &p_term, const String &p_string) const;
void _match_item(TreeItem *p_item, const String &p_text);
TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 65c65a517f..94dd4d0606 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -783,9 +783,9 @@ Variant EditorProperty::get_drag_data(const Point2 &p_point) {
dp["property"] = property;
dp["value"] = object->get(property);
- Label *label = memnew(Label);
- label->set_text(property);
- set_drag_preview(label);
+ Label *drag_label = memnew(Label);
+ drag_label->set_text(property);
+ set_drag_preview(drag_label);
return dp;
}
@@ -1061,11 +1061,9 @@ void EditorInspectorPlugin::add_property_editor_for_multiple_properties(const St
}
bool EditorInspectorPlugin::can_handle(Object *p_object) {
- bool success;
- if (GDVIRTUAL_CALL(_can_handle, p_object, success)) {
- return success;
- }
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_can_handle, p_object, success);
+ return success;
}
void EditorInspectorPlugin::parse_begin(Object *p_object) {
@@ -1081,11 +1079,9 @@ void EditorInspectorPlugin::parse_group(Object *p_object, const String &p_group)
}
bool EditorInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
- bool ret;
- if (GDVIRTUAL_CALL(_parse_property, p_object, p_type, p_path, p_hint, p_hint_text, p_usage, p_wide, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_parse_property, p_object, p_type, p_path, p_hint, p_hint_text, p_usage, p_wide, ret);
+ return ret;
}
void EditorInspectorPlugin::parse_end(Object *p_object) {
@@ -1575,9 +1571,9 @@ int EditorInspectorArray::_get_array_count() {
return _extract_properties_as_array(object_property_list).size();
} else if (mode == MODE_USE_COUNT_PROPERTY) {
bool valid;
- int count = object->get(count_property, &valid);
+ int count_val = object->get(count_property, &valid);
ERR_FAIL_COND_V_MSG(!valid, 0, vformat("%s is not a valid property to be used as array count.", count_property));
- return count;
+ return count_val;
}
return 0;
}
@@ -2527,7 +2523,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
if (ep) {
ep->object = object;
- ep->connect("property_changed", callable_mp(this, &EditorInspector::_property_changed));
+ ep->connect("property_changed", callable_mp(this, &EditorInspector::_property_changed).bind(false));
ep->connect("property_keyed", callable_mp(this, &EditorInspector::_property_keyed));
ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), CONNECT_DEFERRED);
ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value));
@@ -2768,13 +2764,13 @@ void EditorInspector::update_tree() {
// Set the category icon.
if (!EditorNode::get_editor_data().is_type_recognized(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
// If we have a category inside a script, search for the first script with a valid icon.
- Ref<Script> script = ResourceLoader::load(p.hint_string, "Script");
+ Ref<Script> scr = ResourceLoader::load(p.hint_string, "Script");
StringName base_type;
StringName name;
- if (script.is_valid()) {
- base_type = script->get_instance_base_type();
- name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
- Vector<DocData::ClassDoc> docs = script->get_documentation();
+ if (scr.is_valid()) {
+ base_type = scr->get_instance_base_type();
+ name = EditorNode::get_editor_data().script_class_get_name(scr->get_path());
+ Vector<DocData::ClassDoc> docs = scr->get_documentation();
if (!docs.is_empty()) {
doc_name = docs[0].name;
}
@@ -2782,20 +2778,20 @@ void EditorInspector::update_tree() {
label = name;
}
}
- while (script.is_valid()) {
- name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ while (scr.is_valid()) {
+ name = EditorNode::get_editor_data().script_class_get_name(scr->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
if (name != StringName() && !icon_path.is_empty()) {
category->icon = ResourceLoader::load(icon_path, "Texture");
break;
}
- const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_path(script->get_path());
+ const EditorData::CustomType *ctype = EditorNode::get_editor_data().get_custom_type_by_path(scr->get_path());
if (ctype) {
category->icon = ctype->icon;
break;
}
- script = script->get_base_script();
+ scr = scr->get_base_script();
}
if (category->icon.is_null() && has_theme_icon(base_type, SNAME("EditorIcons"))) {
category->icon = get_theme_icon(base_type, SNAME("EditorIcons"));
@@ -3876,7 +3872,7 @@ void EditorInspector::_notification(int p_what) {
update_scroll_request = -1;
}
if (update_tree_pending) {
- refresh_countdown = float(EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"));
+ refresh_countdown = float(EDITOR_GET("docks/property_editor/auto_refresh_interval"));
} else if (refresh_countdown > 0) {
refresh_countdown -= get_process_delta_time();
if (refresh_countdown <= 0) {
@@ -3889,7 +3885,7 @@ void EditorInspector::_notification(int p_what) {
}
}
}
- refresh_countdown = float(EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"));
+ refresh_countdown = float(EDITOR_GET("docks/property_editor/auto_refresh_interval"));
}
}
@@ -4095,7 +4091,7 @@ EditorInspector::EditorInspector() {
get_v_scroll_bar()->connect("value_changed", callable_mp(this, &EditorInspector::_vscroll_changed));
update_scroll_request = -1;
if (EditorSettings::get_singleton()) {
- refresh_countdown = float(EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"));
+ refresh_countdown = float(EDITOR_GET("docks/property_editor/auto_refresh_interval"));
} else {
//used when class is created by the docgen to dump default values of everything bindable, editorsettings may not be created
refresh_countdown = 0.33;
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index 87da67fb05..106cc61947 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -123,7 +123,7 @@ void EditorLocaleDialog::_filter_lang_option_changed() {
Array f_lang_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/language_filter")) {
- f_lang_all = ProjectSettings::get_singleton()->get("internationalization/locale/language_filter");
+ f_lang_all = GLOBAL_GET("internationalization/locale/language_filter");
prev = f_lang_all;
}
@@ -149,22 +149,22 @@ void EditorLocaleDialog::_filter_lang_option_changed() {
void EditorLocaleDialog::_filter_script_option_changed() {
TreeItem *t = script_list->get_edited();
- String script = t->get_metadata(0);
+ String scr_code = t->get_metadata(0);
bool checked = t->is_checked(0);
Variant prev;
Array f_script_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/script_filter")) {
- f_script_all = ProjectSettings::get_singleton()->get("internationalization/locale/script_filter");
+ f_script_all = GLOBAL_GET("internationalization/locale/script_filter");
prev = f_script_all;
}
- int l_idx = f_script_all.find(script);
+ int l_idx = f_script_all.find(scr_code);
if (checked) {
if (l_idx == -1) {
- f_script_all.append(script);
+ f_script_all.append(scr_code);
}
} else {
if (l_idx != -1) {
@@ -189,7 +189,7 @@ void EditorLocaleDialog::_filter_cnt_option_changed() {
Array f_cnt_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/country_filter")) {
- f_cnt_all = ProjectSettings::get_singleton()->get("internationalization/locale/country_filter");
+ f_cnt_all = GLOBAL_GET("internationalization/locale/country_filter");
prev = f_cnt_all;
}
@@ -218,7 +218,7 @@ void EditorLocaleDialog::_filter_mode_changed(int p_mode) {
Variant prev;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter_mode")) {
- prev = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter_mode");
+ prev = GLOBAL_GET("internationalization/locale/locale_filter_mode");
}
undo_redo->create_action(TTR("Changed Locale Filter Mode"));
@@ -238,19 +238,19 @@ void EditorLocaleDialog::_update_tree() {
int filter = SHOW_ALL_LOCALES;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/locale_filter_mode")) {
- filter = ProjectSettings::get_singleton()->get("internationalization/locale/locale_filter_mode");
+ filter = GLOBAL_GET("internationalization/locale/locale_filter_mode");
}
Array f_lang_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/language_filter")) {
- f_lang_all = ProjectSettings::get_singleton()->get("internationalization/locale/language_filter");
+ f_lang_all = GLOBAL_GET("internationalization/locale/language_filter");
}
Array f_cnt_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/country_filter")) {
- f_cnt_all = ProjectSettings::get_singleton()->get("internationalization/locale/country_filter");
+ f_cnt_all = GLOBAL_GET("internationalization/locale/country_filter");
}
Array f_script_all;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/script_filter")) {
- f_script_all = ProjectSettings::get_singleton()->get("internationalization/locale/script_filter");
+ f_script_all = GLOBAL_GET("internationalization/locale/script_filter");
}
bool is_edit_mode = edit_filters->is_pressed();
@@ -298,7 +298,7 @@ void EditorLocaleDialog::_update_tree() {
Vector<String> scripts = TranslationServer::get_singleton()->get_all_scripts();
for (const String &E : scripts) {
if (is_edit_mode || (filter == SHOW_ALL_LOCALES) || f_script_all.has(E) || f_script_all.is_empty()) {
- const String &script = TranslationServer::get_singleton()->get_script_name(E);
+ const String &scr_code = TranslationServer::get_singleton()->get_script_name(E);
TreeItem *t = script_list->create_item(s_root);
if (is_edit_mode) {
t->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
@@ -307,7 +307,7 @@ void EditorLocaleDialog::_update_tree() {
} else if (script_code->get_text() == E) {
t->select(0);
}
- t->set_text(0, vformat("%s [%s]", script, E));
+ t->set_text(0, vformat("%s [%s]", scr_code, E));
t->set_metadata(0, E);
}
}
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 6e6a898757..0f2543f708 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -65,19 +65,34 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f
}
void EditorLog::_update_theme() {
- Ref<Font> normal_font = get_theme_font(SNAME("output_source"), SNAME("EditorFonts"));
+ const Ref<Font> normal_font = get_theme_font(SNAME("output_source"), SNAME("EditorFonts"));
if (normal_font.is_valid()) {
log->add_theme_font_override("normal_font", normal_font);
}
- log->add_theme_font_size_override("normal_font_size", get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts")));
- log->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
-
- Ref<Font> bold_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ const Ref<Font> bold_font = get_theme_font(SNAME("output_source_bold"), SNAME("EditorFonts"));
if (bold_font.is_valid()) {
log->add_theme_font_override("bold_font", bold_font);
}
+ const Ref<Font> italics_font = get_theme_font(SNAME("output_source_italic"), SNAME("EditorFonts"));
+ if (italics_font.is_valid()) {
+ log->add_theme_font_override("italics_font", italics_font);
+ }
+
+ const Ref<Font> bold_italics_font = get_theme_font(SNAME("output_source_bold_italic"), SNAME("EditorFonts"));
+ if (bold_italics_font.is_valid()) {
+ log->add_theme_font_override("bold_italics_font", bold_italics_font);
+ }
+
+ const Ref<Font> mono_font = get_theme_font(SNAME("output_source_mono"), SNAME("EditorFonts"));
+ if (mono_font.is_valid()) {
+ log->add_theme_font_override("mono_font", mono_font);
+ }
+
+ log->add_theme_font_size_override("normal_font_size", get_theme_font_size(SNAME("output_source_size"), SNAME("EditorFonts")));
+ log->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), SNAME("Editor")) * Color(1, 1, 1, 0.4));
+
type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon(SNAME("Popup"), SNAME("EditorIcons")));
type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons")));
type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons")));
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6bc281c7e4..716e0b454f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -110,6 +110,7 @@
#include "editor/export/export_template_manager.h"
#include "editor/export/project_export.h"
#include "editor/filesystem_dock.h"
+#include "editor/history_dock.h"
#include "editor/import/audio_stream_import_settings.h"
#include "editor/import/dynamic_font_import_settings.h"
#include "editor/import/editor_import_collada.h"
@@ -335,7 +336,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// TODO: This REALLY should be done in a better way than replacing all tabs after almost EVERY action.
void EditorNode::_update_scene_tabs() {
- bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
+ bool show_rb = EDITOR_GET("interface/scene_tabs/show_script_button");
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
DisplayServer::get_singleton()->global_menu_clear("_dock");
@@ -428,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");
+ const String appname = GLOBAL_GET("application/config/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()) {
@@ -635,7 +636,7 @@ void EditorNode::_notification(int p_what) {
update_spinner_step_frame = frame + 1;
// Update the icon itself only when the spinner is visible.
- if (EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")) {
+ if (EDITOR_GET("interface/editor/show_update_spinner")) {
update_spinner->set_icon(gui_base->get_theme_icon("Progress" + itos(update_spinner_step + 1), SNAME("EditorIcons")));
}
}
@@ -700,7 +701,7 @@ void EditorNode::_notification(int p_what) {
_initializing_plugins = true;
Vector<String> addons;
if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) {
- addons = ProjectSettings::get_singleton()->get("editor_plugins/enabled");
+ addons = GLOBAL_GET("editor_plugins/enabled");
}
for (int i = 0; i < addons.size(); i++) {
@@ -847,7 +848,7 @@ void EditorNode::_notification(int p_what) {
HashSet<String> updated_textfile_extensions;
bool extensions_match = true;
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
updated_textfile_extensions.insert(E);
if (extensions_match && !textfile_extensions.has(E)) {
@@ -866,9 +867,9 @@ void EditorNode::_notification(int p_what) {
}
void EditorNode::_update_update_spinner() {
- update_spinner->set_visible(EditorSettings::get_singleton()->get("interface/editor/show_update_spinner"));
+ update_spinner->set_visible(EDITOR_GET("interface/editor/show_update_spinner"));
- const bool update_continuously = EditorSettings::get_singleton()->get("interface/editor/update_continuously");
+ const bool update_continuously = EDITOR_GET("interface/editor/update_continuously");
PopupMenu *update_popup = update_spinner->get_popup();
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_CONTINUOUSLY), update_continuously);
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously);
@@ -892,8 +893,8 @@ void EditorNode::_update_update_spinner() {
}
void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_name) {
- Ref<Script> script = Object::cast_to<Script>(p_script);
- if (script.is_null()) {
+ Ref<Script> scr = Object::cast_to<Script>(p_script);
+ if (scr.is_null()) {
return;
}
if (p_activate_name.length()) {
@@ -901,7 +902,7 @@ void EditorNode::_on_plugin_ready(Object *p_script, const String &p_activate_nam
}
project_settings_editor->update_plugins();
project_settings_editor->hide();
- push_item(script.operator->());
+ push_item(scr.operator->());
}
void EditorNode::_remove_plugin_from_enabled(const String &p_name) {
@@ -1181,7 +1182,8 @@ void EditorNode::_vp_resized() {
}
void EditorNode::_titlebar_resized() {
- const Size2 &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID);
+ DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_global_position().y + menu_hb->get_size().y / 2, menu_hb->get_global_position().y + menu_hb->get_size().y / 2), DisplayServer::MAIN_WINDOW_ID);
+ const Vector3i &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));
@@ -1190,6 +1192,9 @@ void EditorNode::_titlebar_resized() {
int w = (gui_base->is_layout_rtl()) ? margin.x : margin.y;
right_menu_spacer->set_custom_minimum_size(Size2(w, 0));
}
+ if (menu_hb) {
+ menu_hb->set_custom_minimum_size(Size2(0, margin.z - menu_hb->get_global_position().y));
+ }
}
void EditorNode::_version_button_pressed() {
@@ -1269,7 +1274,7 @@ void EditorNode::edit_node(Node *p_node) {
void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) {
editor_data.apply_changes_in_editors();
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
@@ -1614,7 +1619,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
// which would result in an invalid texture.
if (c3d == 0 && c2d == 0) {
img.instantiate();
- img->create(1, 1, false, Image::FORMAT_RGB8);
+ img->initialize_data(1, 1, false, Image::FORMAT_RGB8);
} else if (c3d < c2d) {
Ref<ViewportTexture> viewport_texture = scene_root->get_texture();
if (viewport_texture->get_width() > 0 && viewport_texture->get_height() > 0) {
@@ -1636,7 +1641,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
save.step(TTR("Creating Thumbnail"), 2);
save.step(TTR("Creating Thumbnail"), 3);
- int preview_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int preview_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
preview_size *= EDSCALE;
// Consider a square region.
@@ -1665,10 +1670,8 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
cache_base = temp_path.path_join("resthumb-" + cache_base);
// Does not have it, try to load a cached thumbnail.
- String file = cache_base + ".png";
-
post_process_preview(img);
- img->save_png(file);
+ img->save_png(cache_base + ".png");
}
}
@@ -1699,7 +1702,7 @@ int EditorNode::_save_external_resources() {
// Save external resources and its subresources if any was modified.
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
@@ -1805,7 +1808,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
}
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
@@ -2038,8 +2041,8 @@ void EditorNode::_dialog_action(String p_file) {
ERR_FAIL_COND(saving_resource.is_null());
save_resource_in_path(saving_resource, p_file);
saving_resource = Ref<Resource>();
- ObjectID current = editor_history.get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
+ ObjectID current_id = editor_history.get_current();
+ Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
ERR_FAIL_COND(!current_obj);
current_obj->notify_property_list_changed();
} break;
@@ -2240,8 +2243,8 @@ static bool overrides_external_editor(Object *p_object) {
}
void EditorNode::_edit_current(bool p_skip_foreign) {
- ObjectID current = editor_history.get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
+ ObjectID current_id = editor_history.get_current();
+ Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
Ref<Resource> res = Object::cast_to<Resource>(current_obj);
if (p_skip_foreign && res.is_valid()) {
@@ -2405,7 +2408,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (main_plugin && !skip_main_plugin) {
// Special case if use of external editor is true.
Resource *current_res = Object::cast_to<Resource>(current_obj);
- if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
+ if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EDITOR_GET("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
if (!changing_scene) {
main_plugin->edit(current_obj);
}
@@ -2691,9 +2694,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
save_confirmation->set_text(TTR("Save modified resources before closing?"));
}
} else {
- Node *scene_root = editor_data.get_edited_scene_root(tab_closing_idx);
- if (scene_root) {
- String scene_filename = scene_root->get_scene_file_path();
+ Node *ed_scene_root = editor_data.get_edited_scene_root(tab_closing_idx);
+ if (ed_scene_root) {
+ String scene_filename = ed_scene_root->get_scene_file_path();
if (p_option == FILE_CLOSE_ALL_AND_RELOAD_CURRENT_PROJECT) {
save_confirmation->set_ok_button_text(TTR("Save & Reload"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before reloading?"), !scene_filename.is_empty() ? scene_filename : "unsaved scene"));
@@ -3103,7 +3106,7 @@ 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()) {
+ switch (GLOBAL_GET("editor/scene/scene_naming").operator int()) {
case SCENE_NAME_CASING_AUTO:
// Use casing of the root node.
break;
@@ -3123,7 +3126,7 @@ void EditorNode::_screenshot(bool p_use_utc) {
String name = "editor_screenshot_" + Time::get_singleton()->get_datetime_string_from_system(p_use_utc).replace(":", "") + ".png";
NodePath path = String("user://") + name;
_save_screenshot(path);
- if (EditorSettings::get_singleton()->get("interface/editor/automatically_open_screenshots")) {
+ if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
OS::get_singleton()->shell_open(String("file://") + ProjectSettings::get_singleton()->globalize_path(path));
}
}
@@ -3368,7 +3371,7 @@ void EditorNode::editor_select(int p_which) {
editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name());
}
- if (EditorSettings::get_singleton()->get("interface/editor/separate_distraction_mode")) {
+ if (EDITOR_GET("interface/editor/separate_distraction_mode")) {
if (p_which == EDITOR_SCRIPT) {
set_distraction_free_mode(script_distraction_free);
} else {
@@ -3511,39 +3514,39 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
}
String script_path = cf->get_value("plugin", "script");
- Ref<Script> script; // We need to save it for creating "ep" below.
+ Ref<Script> scr; // We need to save it for creating "ep" below.
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
script_path = addon_path.get_base_dir().path_join(script_path);
- script = ResourceLoader::load(script_path);
+ scr = ResourceLoader::load(script_path);
- if (script.is_null()) {
+ if (scr.is_null()) {
show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path));
return;
}
// Errors in the script cause the base_type to be an empty StringName.
- if (script->get_instance_base_type() == StringName()) {
+ if (scr->get_instance_base_type() == StringName()) {
show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, addon_path));
_remove_plugin_from_enabled(addon_path);
return;
}
// Plugin init scripts must inherit from EditorPlugin and be tools.
- if (String(script->get_instance_base_type()) != "EditorPlugin") {
+ if (String(scr->get_instance_base_type()) != "EditorPlugin") {
show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), script_path));
return;
}
- if (!script->is_tool()) {
+ if (!scr->is_tool()) {
show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), script_path));
return;
}
}
EditorPlugin *ep = memnew(EditorPlugin);
- ep->set_script(script);
+ ep->set_script(scr);
addon_name_to_plugin[addon_path] = ep;
add_editor_plugin(ep, p_config_changed);
@@ -3558,6 +3561,14 @@ bool EditorNode::is_addon_plugin_enabled(const String &p_addon) const {
return addon_name_to_plugin.has("res://addons/" + p_addon + "/plugin.cfg");
}
+void EditorNode::set_movie_maker_enabled(bool p_enabled) {
+ write_movie_button->set_pressed(p_enabled);
+}
+
+bool EditorNode::is_movie_maker_enabled() const {
+ return write_movie_button->is_pressed();
+}
+
void EditorNode::_remove_edited_scene(bool p_change_tab) {
int new_index = editor_data.get_edited_scene();
int old_index = new_index;
@@ -3641,17 +3652,17 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
changing_scene = false;
- int current = -1;
+ int current_tab = -1;
for (int i = 0; i < editor_table.size(); i++) {
if (editor_plugin_screen == editor_table[i]) {
- current = i;
+ current_tab = i;
break;
}
}
if (p_state.has("editor_index")) {
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 (current_tab < 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);
}
@@ -3659,7 +3670,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
}
if (get_edited_scene()) {
- if (current < 2) {
+ if (current_tab < 2) {
// Use heuristic instead.
int n2d = 0, n3d = 0;
_find_node_types(get_edited_scene(), n2d, n3d);
@@ -3687,6 +3698,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
EditorDebuggerNode::get_singleton()->update_live_edit_root();
ScriptEditor::get_singleton()->set_scene_root_script(editor_data.get_scene_root_script(editor_data.get_edited_scene()));
editor_data.notify_edited_scene_changed();
+ emit_signal(SNAME("scene_changed"));
}
bool EditorNode::is_changing_scene() const {
@@ -3772,7 +3784,7 @@ int EditorNode::new_scene() {
if (editor_data.get_edited_scene_count() > 1) {
for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) {
bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
- if (!unsaved && editor_data.get_scene_path(i).is_empty()) {
+ if (!unsaved && editor_data.get_scene_path(i).is_empty() && editor_data.get_edited_scene_root(i) == nullptr) {
editor_data.remove_scene(i);
idx--;
}
@@ -3939,9 +3951,9 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
void EditorNode::open_request(const String &p_path) {
if (!opening_prev) {
- List<String>::Element *prev_scene = previous_scenes.find(p_path);
- if (prev_scene != nullptr) {
- prev_scene->erase();
+ List<String>::Element *prev_scene_item = previous_scenes.find(p_path);
+ if (prev_scene_item != nullptr) {
+ prev_scene_item->erase();
}
}
@@ -4073,7 +4085,7 @@ void EditorNode::_quick_opened() {
List<String> scene_extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
- if (open_scene_dialog || scene_extensions.find(files[i].get_extension())) {
+ if (open_scene_dialog || scene_extensions.find(files[i].get_extension().to_lower())) {
open_request(res_path);
} else {
load_resource(res_path);
@@ -4192,9 +4204,9 @@ void EditorNode::stop_child_process(OS::ProcessID p_pid) {
Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const {
ERR_FAIL_COND_V(!p_object, nullptr);
- Ref<Script> script = p_object->get_script();
+ Ref<Script> scr = p_object->get_script();
- if (script.is_valid()) {
+ if (scr.is_valid()) {
// Uncommenting would break things! Consider adding a parameter if you need it.
// StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
// if (name != StringName()) {
@@ -4202,18 +4214,18 @@ Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) cons
// }
// TODO: Should probably be deprecated in 4.x
- StringName base = script->get_instance_base_type();
+ StringName base = scr->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
- Ref<Script> base_script = script;
- while (base_script.is_valid()) {
+ Ref<Script> base_scr = scr;
+ while (base_scr.is_valid()) {
for (int i = 0; i < types.size(); ++i) {
- if (types[i].script == base_script) {
+ if (types[i].script == base_scr) {
return types[i].script;
}
}
- base_script = base_script->get_base_script();
+ base_scr = base_scr->get_base_script();
}
}
}
@@ -4224,30 +4236,30 @@ Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) cons
StringName EditorNode::get_object_custom_type_name(const Object *p_object) const {
ERR_FAIL_COND_V(!p_object, StringName());
- Ref<Script> script = p_object->get_script();
- if (script.is_null() && Object::cast_to<Script>(p_object)) {
- script = p_object;
+ Ref<Script> scr = p_object->get_script();
+ if (scr.is_null() && Object::cast_to<Script>(p_object)) {
+ scr = p_object;
}
- if (script.is_valid()) {
- Ref<Script> base_script = script;
- while (base_script.is_valid()) {
- StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
+ if (scr.is_valid()) {
+ Ref<Script> base_scr = scr;
+ while (base_scr.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(base_scr->get_path());
if (name != StringName()) {
return name;
}
// TODO: Should probably be deprecated in 4.x.
- StringName base = base_script->get_instance_base_type();
+ StringName base = base_scr->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
for (int i = 0; i < types.size(); ++i) {
- if (types[i].script == base_script) {
+ if (types[i].script == base_scr) {
return types[i].name;
}
}
}
- base_script = base_script->get_base_script();
+ base_scr = base_scr->get_base_script();
}
}
@@ -4291,40 +4303,40 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na
Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String &p_fallback) {
ERR_FAIL_COND_V(!p_object || !gui_base, nullptr);
- Ref<Script> script = p_object->get_script();
- if (script.is_null() && p_object->is_class("Script")) {
- script = p_object;
+ Ref<Script> scr = p_object->get_script();
+ if (scr.is_null() && p_object->is_class("Script")) {
+ scr = p_object;
}
- if (script.is_valid() && !script_icon_cache.has(script)) {
- Ref<Script> base_script = script;
- while (base_script.is_valid()) {
- StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
+ if (scr.is_valid() && !script_icon_cache.has(scr)) {
+ Ref<Script> base_scr = scr;
+ while (base_scr.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(base_scr->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
Ref<ImageTexture> icon = _load_custom_class_icon(icon_path);
if (icon.is_valid()) {
- script_icon_cache[script] = icon;
+ script_icon_cache[scr] = icon;
return icon;
}
// TODO: should probably be deprecated in 4.x
- StringName base = base_script->get_instance_base_type();
+ StringName base = base_scr->get_instance_base_type();
if (base != StringName() && EditorNode::get_editor_data().get_custom_types().has(base)) {
const Vector<EditorData::CustomType> &types = EditorNode::get_editor_data().get_custom_types()[base];
for (int i = 0; i < types.size(); ++i) {
- if (types[i].script == base_script && types[i].icon.is_valid()) {
- script_icon_cache[script] = types[i].icon;
+ if (types[i].script == base_scr && types[i].icon.is_valid()) {
+ script_icon_cache[scr] = types[i].icon;
return types[i].icon;
}
}
}
- base_script = base_script->get_base_script();
+ base_scr = base_scr->get_base_script();
}
// If no icon found, cache it as null.
- script_icon_cache[script] = Ref<Texture>();
- } else if (script.is_valid() && script_icon_cache.has(script) && script_icon_cache[script].is_valid()) {
- return script_icon_cache[script];
+ script_icon_cache[scr] = Ref<Texture>();
+ } else if (scr.is_valid() && script_icon_cache.has(scr) && script_icon_cache[scr].is_valid()) {
+ return script_icon_cache[scr];
}
// TODO: Should probably be deprecated in 4.x.
@@ -4348,7 +4360,7 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
if (ScriptServer::is_global_class(p_class)) {
String class_name = p_class;
- Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(class_name);
+ Ref<Script> scr = EditorNode::get_editor_data().script_class_load_script(class_name);
while (true) {
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(class_name);
@@ -4359,18 +4371,18 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
// Find next global class along the inheritance chain.
do {
- Ref<Script> base_script = script->get_base_script();
- if (base_script.is_null()) {
+ Ref<Script> base_scr = scr->get_base_script();
+ if (base_scr.is_null()) {
// We've reached a native class, use its icon.
String base_type;
- script->get_language()->get_global_class_name(script->get_path(), &base_type);
+ scr->get_language()->get_global_class_name(scr->get_path(), &base_type);
if (gui_base->has_theme_icon(base_type, "EditorIcons")) {
return gui_base->get_theme_icon(base_type, "EditorIcons");
}
return gui_base->get_theme_icon(p_fallback, "EditorIcons");
}
- script = base_script;
- class_name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ scr = base_scr;
+ class_name = EditorNode::get_editor_data().script_class_get_name(scr->get_path());
} while (class_name.is_empty());
}
}
@@ -4390,6 +4402,27 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
return nullptr;
}
+bool EditorNode::is_object_of_custom_type(const Object *p_object, const StringName &p_class) {
+ ERR_FAIL_COND_V(!p_object, false);
+
+ Ref<Script> scr = p_object->get_script();
+ if (scr.is_null() && Object::cast_to<Script>(p_object)) {
+ scr = p_object;
+ }
+
+ if (scr.is_valid()) {
+ Ref<Script> base_script = scr;
+ while (base_script.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
+ if (name == p_class) {
+ return true;
+ }
+ base_script = base_script->get_base_script();
+ }
+ }
+ return false;
+}
+
void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
if (singleton->cmdline_export_mode) {
print_line(p_task + ": begin: " + p_label + " steps: " + itos(p_steps));
@@ -4532,7 +4565,7 @@ void EditorNode::_dock_floating_close_request(Control *p_control) {
dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_tab_count()));
dock_slot[window_slot]->set_current_tab(window->get_meta("dock_index"));
- window->queue_delete();
+ window->queue_free();
_update_dock_containers();
@@ -4675,26 +4708,24 @@ void EditorNode::_dock_move_left() {
if (dock_popup_selected_idx < 0 || dock_popup_selected_idx >= DOCK_SLOT_MAX) {
return;
}
- Control *current = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab());
- Control *prev = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1);
- if (!current || !prev) {
+ Control *current_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab());
+ Control *prev_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1);
+ if (!current_ctl || !prev_ctl) {
return;
}
- dock_slot[dock_popup_selected_idx]->move_child(current, prev->get_index());
- dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1);
+ dock_slot[dock_popup_selected_idx]->move_child(current_ctl, prev_ctl->get_index(false));
dock_select->queue_redraw();
_edit_current();
_save_docks();
}
void EditorNode::_dock_move_right() {
- Control *current = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab());
- Control *next = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1);
- if (!current || !next) {
+ Control *current_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab());
+ Control *next_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1);
+ if (!current_ctl || !next_ctl) {
return;
}
- dock_slot[dock_popup_selected_idx]->move_child(next, current->get_index());
- dock_slot[dock_popup_selected_idx]->set_current_tab(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1);
+ dock_slot[dock_popup_selected_idx]->move_child(next_ctl, current_ctl->get_index(false));
dock_select->queue_redraw();
_edit_current();
_save_docks();
@@ -5283,9 +5314,9 @@ void EditorNode::_layout_menu_option(int p_id) {
}
void EditorNode::_scene_tab_script_edited(int p_tab) {
- Ref<Script> script = editor_data.get_scene_root_script(p_tab);
- if (script.is_valid()) {
- InspectorDock::get_singleton()->edit_resource(script);
+ Ref<Script> scr = editor_data.get_scene_root_script(p_tab);
+ if (scr.is_valid()) {
+ InspectorDock::get_singleton()->edit_resource(scr);
}
}
@@ -5538,7 +5569,7 @@ bool EditorNode::get_docks_visible() const {
}
void EditorNode::_toggle_distraction_free_mode() {
- if (EditorSettings::get_singleton()->get("interface/editor/separate_distraction_mode")) {
+ if (EDITOR_GET("interface/editor/separate_distraction_mode")) {
int screen = -1;
for (int i = 0; i < editor_table.size(); i++) {
if (editor_plugin_screen == editor_table[i]) {
@@ -5909,7 +5940,7 @@ 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")));
+ renderer->add_theme_color_override("font_color", theme_base->get_theme_color(SNAME("highend_color"), SNAME("Editor")));
}
}
@@ -6011,6 +6042,7 @@ void EditorNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
ADD_SIGNAL(MethodInfo("scene_saved", PropertyInfo(Variant::STRING, "path")));
ADD_SIGNAL(MethodInfo("project_settings_changed"));
+ ADD_SIGNAL(MethodInfo("scene_changed"));
}
static Node *_resource_get_edited_scene() {
@@ -6147,7 +6179,7 @@ EditorNode::EditorNode() {
FileAccess::set_backup_save(EDITOR_GET("filesystem/on_save/safe_save_on_backup_then_rename"));
{
- int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ int display_scale = EDITOR_GET("interface/editor/display_scale");
switch (display_scale) {
case 0:
@@ -6173,7 +6205,7 @@ EditorNode::EditorNode() {
editor_set_scale(2.0);
break;
default:
- editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
+ editor_set_scale(EDITOR_GET("interface/editor/custom_display_scale"));
break;
}
}
@@ -6181,10 +6213,17 @@ EditorNode::EditorNode() {
// Define a minimum window size to prevent UI elements from overlapping or being cut off.
DisplayServer::get_singleton()->window_set_min_size(Size2(1024, 600) * EDSCALE);
+ FileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
+
+ int swap_cancel_ok = EDITOR_GET("interface/editor/accept_dialog_cancel_ok_buttons");
+ if (swap_cancel_ok != 0) { // 0 is auto, set in register_scene based on DisplayServer.
+ // Swap on means OK first.
+ AcceptDialog::set_swap_cancel_ok(swap_cancel_ok == 2);
+ }
+
ResourceLoader::set_abort_on_missing_resources(false);
- FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
- EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
- EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
ResourceLoader::set_error_notify_func(this, _load_error_notify);
ResourceLoader::set_dependency_error_notify_func(this, _dependency_error_report);
@@ -6345,7 +6384,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), Key::SPACE);
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
textfile_extensions.insert(E);
}
@@ -7069,6 +7108,8 @@ EditorNode::EditorNode() {
filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks));
get_project_settings()->connect_filesystem_dock_signals(filesystem_dock);
+ HistoryDock *hd = memnew(HistoryDock);
+
// Scene: Top left.
dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton());
dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(dock_slot[DOCK_SLOT_LEFT_UR]->get_tab_idx_from_control(SceneTreeDock::get_singleton()), TTR("Scene"));
@@ -7089,6 +7130,10 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(NodeDock::get_singleton());
dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(NodeDock::get_singleton()), TTR("Node"));
+ // History: Full height right, behind Node.
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(hd);
+ dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(hd), TTR("History"));
+
// Hide unused dock slots and vsplits.
dock_slot[DOCK_SLOT_LEFT_UL]->hide();
dock_slot[DOCK_SLOT_LEFT_BL]->hide();
@@ -7564,7 +7609,6 @@ EditorNode::EditorNode() {
// Extend menu bar to window title.
if (can_expand) {
- DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(menu_hb->get_minimum_size().y / 2, menu_hb->get_minimum_size().y / 2), DisplayServer::MAIN_WINDOW_ID);
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
menu_hb->set_can_move_window(true);
}
@@ -7618,7 +7662,7 @@ bool EditorPluginList::forward_gui_input(const Ref<InputEvent> &p_event) {
return discard;
}
-EditorPlugin::AfterGUIInput EditorPluginList::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
+EditorPlugin::AfterGUIInput EditorPluginList::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled) {
EditorPlugin::AfterGUIInput after = EditorPlugin::AFTER_GUI_INPUT_PASS;
for (int i = 0; i < plugins_list.size(); i++) {
@@ -7626,7 +7670,7 @@ EditorPlugin::AfterGUIInput EditorPluginList::forward_spatial_gui_input(Camera3D
continue;
}
- EditorPlugin::AfterGUIInput current_after = plugins_list[i]->forward_spatial_gui_input(p_camera, p_event);
+ EditorPlugin::AfterGUIInput current_after = plugins_list[i]->forward_3d_gui_input(p_camera, p_event);
if (current_after == EditorPlugin::AFTER_GUI_INPUT_STOP) {
after = EditorPlugin::AFTER_GUI_INPUT_STOP;
}
@@ -7650,15 +7694,15 @@ void EditorPluginList::forward_canvas_force_draw_over_viewport(Control *p_overla
}
}
-void EditorPluginList::forward_spatial_draw_over_viewport(Control *p_overlay) {
+void EditorPluginList::forward_3d_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < plugins_list.size(); i++) {
- plugins_list[i]->forward_spatial_draw_over_viewport(p_overlay);
+ plugins_list[i]->forward_3d_draw_over_viewport(p_overlay);
}
}
-void EditorPluginList::forward_spatial_force_draw_over_viewport(Control *p_overlay) {
+void EditorPluginList::forward_3d_force_draw_over_viewport(Control *p_overlay) {
for (int i = 0; i < plugins_list.size(); i++) {
- plugins_list[i]->forward_spatial_force_draw_over_viewport(p_overlay);
+ plugins_list[i]->forward_3d_force_draw_over_viewport(p_overlay);
}
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 3c236a1301..9c8d564057 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -770,6 +770,9 @@ public:
void set_addon_plugin_enabled(const String &p_addon, bool p_enabled, bool p_config_changed = false);
bool is_addon_plugin_enabled(const String &p_addon) const;
+ void set_movie_maker_enabled(bool p_enabled);
+ bool is_movie_maker_enabled() const;
+
void edit_node(Node *p_node);
void edit_resource(const Ref<Resource> &p_resource) { InspectorDock::get_singleton()->edit_resource(p_resource); };
@@ -827,6 +830,8 @@ public:
Ref<Texture2D> get_object_icon(const Object *p_object, const String &p_fallback = "Object");
Ref<Texture2D> get_class_icon(const String &p_class, const String &p_fallback = "Object") const;
+ bool is_object_of_custom_type(const Object *p_object, const StringName &p_class);
+
void show_accept(const String &p_text, const String &p_title);
void show_save_accept(const String &p_text, const String &p_title);
void show_warning(const String &p_text, const String &p_title = TTR("Warning!"));
@@ -935,9 +940,9 @@ public:
bool forward_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
void forward_canvas_force_draw_over_viewport(Control *p_overlay);
- EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
- void forward_spatial_draw_over_viewport(Control *p_overlay);
- void forward_spatial_force_draw_over_viewport(Control *p_overlay);
+ EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event, bool serve_when_force_input_enabled);
+ void forward_3d_draw_over_viewport(Control *p_overlay);
+ void forward_3d_force_draw_over_viewport(Control *p_overlay);
void add_plugin(EditorPlugin *p_plugin);
void remove_plugin(EditorPlugin *p_plugin);
void clear();
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index d1f41dad84..a8fd9d0eb0 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -59,7 +59,7 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
continue;
}
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
+ Ref<Texture2D> obj_icon = EditorNode::get_singleton()->get_object_icon(obj);
String proper_name = "";
Vector<String> name_parts = E.name.split("/");
@@ -72,7 +72,7 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
}
int index = sub_objects_menu->get_item_count();
- sub_objects_menu->add_icon_item(icon, proper_name, objects.size());
+ sub_objects_menu->add_icon_item(obj_icon, proper_name, objects.size());
sub_objects_menu->set_item_indent(index, p_depth);
objects.push_back(obj->get_instance_id());
@@ -122,15 +122,15 @@ void EditorPath::update_path() {
continue;
}
- Ref<Texture2D> icon;
+ Ref<Texture2D> obj_icon;
if (Object::cast_to<MultiNodeEdit>(obj)) {
- icon = EditorNode::get_singleton()->get_class_icon(Object::cast_to<MultiNodeEdit>(obj)->get_edited_class_name());
+ obj_icon = EditorNode::get_singleton()->get_class_icon(Object::cast_to<MultiNodeEdit>(obj)->get_edited_class_name());
} else {
- icon = EditorNode::get_singleton()->get_object_icon(obj);
+ obj_icon = EditorNode::get_singleton()->get_object_icon(obj);
}
- if (icon.is_valid()) {
- current_object_icon->set_texture(icon);
+ if (obj_icon.is_valid()) {
+ current_object_icon->set_texture(obj_icon);
}
if (i == history->get_path_size() - 1) {
diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp
index 54d4660cb6..f55c530ffb 100644
--- a/editor/editor_paths.cpp
+++ b/editor/editor_paths.cpp
@@ -83,7 +83,7 @@ String EditorPaths::get_script_templates_dir() const {
}
String EditorPaths::get_project_script_templates_dir() const {
- return ProjectSettings::get_singleton()->get("editor/script/templates_search_path");
+ return GLOBAL_GET("editor/script/templates_search_path");
}
String EditorPaths::get_feature_profiles_dir() const {
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 981dad2d2a..d83dc32e90 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -289,6 +289,14 @@ bool EditorInterface::is_plugin_enabled(const String &p_plugin) const {
return EditorNode::get_singleton()->is_addon_plugin_enabled(p_plugin);
}
+void EditorInterface::set_movie_maker_enabled(bool p_enabled) {
+ EditorNode::get_singleton()->set_movie_maker_enabled(p_enabled);
+}
+
+bool EditorInterface::is_movie_maker_enabled() const {
+ return EditorNode::get_singleton()->is_movie_maker_enabled();
+}
+
EditorInspector *EditorInterface::get_inspector() const {
return InspectorDock::get_inspector_singleton();
}
@@ -364,6 +372,9 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled);
ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled);
+ ClassDB::bind_method(D_METHOD("set_movie_maker_enabled", "enabled"), &EditorInterface::set_movie_maker_enabled);
+ ClassDB::bind_method(D_METHOD("is_movie_maker_enabled"), &EditorInterface::is_movie_maker_enabled);
+
ClassDB::bind_method(D_METHOD("get_inspector"), &EditorInterface::get_inspector);
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
@@ -570,11 +581,9 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) {
}
bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
- bool success;
- if (GDVIRTUAL_CALL(_forward_canvas_gui_input, p_event, success)) {
- return success;
- }
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_forward_canvas_gui_input, p_event, success);
+ return success;
}
void EditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) {
@@ -604,49 +613,36 @@ int EditorPlugin::update_overlays() const {
}
}
-EditorPlugin::AfterGUIInput EditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
- int success;
-
- if (GDVIRTUAL_CALL(_forward_3d_gui_input, p_camera, p_event, success)) {
- return static_cast<EditorPlugin::AfterGUIInput>(success);
- }
-
- return EditorPlugin::AFTER_GUI_INPUT_PASS;
+EditorPlugin::AfterGUIInput EditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+ int success = EditorPlugin::AFTER_GUI_INPUT_PASS;
+ GDVIRTUAL_CALL(_forward_3d_gui_input, p_camera, p_event, success);
+ return static_cast<EditorPlugin::AfterGUIInput>(success);
}
-void EditorPlugin::forward_spatial_draw_over_viewport(Control *p_overlay) {
+void EditorPlugin::forward_3d_draw_over_viewport(Control *p_overlay) {
GDVIRTUAL_CALL(_forward_3d_draw_over_viewport, p_overlay);
}
-void EditorPlugin::forward_spatial_force_draw_over_viewport(Control *p_overlay) {
+void EditorPlugin::forward_3d_force_draw_over_viewport(Control *p_overlay) {
GDVIRTUAL_CALL(_forward_3d_force_draw_over_viewport, p_overlay);
}
String EditorPlugin::get_name() const {
String name;
- if (GDVIRTUAL_CALL(_get_plugin_name, name)) {
- return name;
- }
-
- return String();
+ GDVIRTUAL_CALL(_get_plugin_name, name);
+ return name;
}
const Ref<Texture2D> EditorPlugin::get_icon() const {
Ref<Texture2D> icon;
- if (GDVIRTUAL_CALL(_get_plugin_icon, icon)) {
- return icon;
- }
-
- return Ref<Texture2D>();
+ GDVIRTUAL_CALL(_get_plugin_icon, icon);
+ return icon;
}
bool EditorPlugin::has_main_screen() const {
- bool success;
- if (GDVIRTUAL_CALL(_has_main_screen, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_has_main_screen, success);
+ return success;
}
void EditorPlugin::make_visible(bool p_visible) {
@@ -662,21 +658,15 @@ void EditorPlugin::edit(Object *p_object) {
}
bool EditorPlugin::handles(Object *p_object) const {
- bool success;
- if (GDVIRTUAL_CALL(_handles, p_object, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_handles, p_object, success);
+ return success;
}
Dictionary EditorPlugin::get_state() const {
Dictionary state;
- if (GDVIRTUAL_CALL(_get_state, state)) {
- return state;
- }
-
- return Dictionary();
+ GDVIRTUAL_CALL(_get_state, state);
+ return state;
}
void EditorPlugin::set_state(const Dictionary &p_state) {
@@ -753,12 +743,12 @@ void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporte
EditorExport::get_singleton()->remove_export_plugin(p_exporter);
}
-void EditorPlugin::add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+void EditorPlugin::add_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
ERR_FAIL_COND(!p_gizmo_plugin.is_valid());
Node3DEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin);
}
-void EditorPlugin::remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
+void EditorPlugin::remove_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) {
ERR_FAIL_COND(!p_gizmo_plugin.is_valid());
Node3DEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin);
}
@@ -822,11 +812,9 @@ void EditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
}
bool EditorPlugin::build() {
- bool success;
- if (GDVIRTUAL_CALL(_build, success)) {
- return success;
- }
- return true;
+ bool success = true;
+ GDVIRTUAL_CALL(_build, success);
+ return success;
}
void EditorPlugin::queue_save_layout() {
@@ -908,8 +896,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_scene_post_import_plugin", "scene_import_plugin"), &EditorPlugin::remove_scene_post_import_plugin);
ClassDB::bind_method(D_METHOD("add_export_plugin", "plugin"), &EditorPlugin::add_export_plugin);
ClassDB::bind_method(D_METHOD("remove_export_plugin", "plugin"), &EditorPlugin::remove_export_plugin);
- ClassDB::bind_method(D_METHOD("add_spatial_gizmo_plugin", "plugin"), &EditorPlugin::add_spatial_gizmo_plugin);
- ClassDB::bind_method(D_METHOD("remove_spatial_gizmo_plugin", "plugin"), &EditorPlugin::remove_spatial_gizmo_plugin);
+ ClassDB::bind_method(D_METHOD("add_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::add_node_3d_gizmo_plugin);
+ ClassDB::bind_method(D_METHOD("remove_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::remove_node_3d_gizmo_plugin);
ClassDB::bind_method(D_METHOD("add_inspector_plugin", "plugin"), &EditorPlugin::add_inspector_plugin);
ClassDB::bind_method(D_METHOD("remove_inspector_plugin", "plugin"), &EditorPlugin::remove_inspector_plugin);
ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index a048b174e4..d8c3cc7330 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -113,6 +113,9 @@ public:
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
bool is_plugin_enabled(const String &p_plugin) const;
+ void set_movie_maker_enabled(bool p_enabled);
+ bool is_movie_maker_enabled() const;
+
EditorInspector *get_inspector() const;
Error save_scene();
@@ -237,9 +240,9 @@ public:
virtual void forward_canvas_draw_over_viewport(Control *p_overlay);
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay);
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
- virtual void forward_spatial_draw_over_viewport(Control *p_overlay);
- virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay);
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
+ virtual void forward_3d_draw_over_viewport(Control *p_overlay);
+ virtual void forward_3d_force_draw_over_viewport(Control *p_overlay);
virtual String get_name() const;
virtual const Ref<Texture2D> get_icon() const;
@@ -285,8 +288,8 @@ public:
void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
- void add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
- void remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
+ void add_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
+ void remove_node_3d_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin);
void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index bd19df41fe..dd647c944d 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -98,14 +98,14 @@ void EditorPluginSettings::update_plugins() {
String author = cf->get_value("plugin", "author");
String version = cf->get_value("plugin", "version");
String description = cf->get_value("plugin", "description");
- String script = cf->get_value("plugin", "script");
+ String scr = cf->get_value("plugin", "script");
TreeItem *item = plugin_list->create_item(root);
item->set_text(0, name);
- item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description);
+ item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + scr + "\n" + TTR("Description:") + " " + description);
item->set_metadata(0, path);
item->set_text(1, version);
- item->set_metadata(1, script);
+ item->set_metadata(1, scr);
item->set_text(2, author);
item->set_metadata(2, description);
item->set_cell_mode(3, TreeItem::CELL_MODE_CHECK);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 3b99962435..73691b3461 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/filesystem_dock.h"
+#include "editor/project_settings_editor.h"
#include "scene/2d/gpu_particles_2d.h"
#include "scene/3d/fog_volume.h"
#include "scene/3d/gpu_particles_3d.h"
@@ -51,9 +52,9 @@ void EditorPropertyNil::update_property() {
}
EditorPropertyNil::EditorPropertyNil() {
- Label *label = memnew(Label);
- label->set_text("<null>");
- add_child(label);
+ Label *prop_label = memnew(Label);
+ prop_label->set_text("<null>");
+ add_child(prop_label);
}
///////////////////// TEXT /////////////////////////
@@ -89,7 +90,9 @@ void EditorPropertyText::update_property() {
String s = get_edited_object()->get(get_edited_property());
updating = true;
if (text->get_text() != s) {
+ int caret = text->get_caret_column();
text->set_text(s);
+ text->set_caret_column(caret);
}
text->set_editable(!is_read_only());
updating = false;
@@ -759,8 +762,13 @@ void EditorPropertyEnum::_option_selected(int p_which) {
}
void EditorPropertyEnum::update_property() {
- int64_t which = get_edited_object()->get(get_edited_property());
+ Variant current = get_edited_object()->get(get_edited_property());
+ if (current.get_type() == Variant::NIL) {
+ options->select(-1);
+ return;
+ }
+ int64_t which = current;
for (int i = 0; i < options->get_item_count(); i++) {
if (which == (int64_t)options->get_item_metadata(i)) {
options->select(i);
@@ -1234,7 +1242,7 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) {
String name;
if (ProjectSettings::get_singleton()->has_setting(basename + vformat("/layer_%d", i + 1))) {
- name = ProjectSettings::get_singleton()->get(basename + vformat("/layer_%d", i + 1));
+ name = GLOBAL_GET(basename + vformat("/layer_%d", i + 1));
}
if (name.is_empty()) {
@@ -1252,26 +1260,41 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) {
}
void EditorPropertyLayers::set_layer_name(int p_index, const String &p_name) {
- if (ProjectSettings::get_singleton()->has_setting(basename + vformat("/layer_%d", p_index + 1))) {
- ProjectSettings::get_singleton()->set(basename + vformat("/layer_%d", p_index + 1), p_name);
+ const String property_name = basename + vformat("/layer_%d", p_index + 1);
+ if (ProjectSettings::get_singleton()->has_setting(property_name)) {
+ ProjectSettings::get_singleton()->set(property_name, p_name);
ProjectSettings::get_singleton()->save();
}
}
+String EditorPropertyLayers::get_layer_name(int p_index) const {
+ const String property_name = basename + vformat("/layer_%d", p_index + 1);
+ if (ProjectSettings::get_singleton()->has_setting(property_name)) {
+ return GLOBAL_GET(property_name);
+ }
+ return String();
+}
+
void EditorPropertyLayers::_button_pressed() {
int layer_count = grid->layer_count;
- int layer_group_size = grid->layer_group_size;
-
layers->clear();
for (int i = 0; i < layer_count; i++) {
- if ((i != 0) && ((i % layer_group_size) == 0)) {
- layers->add_separator();
+ const String name = get_layer_name(i);
+ if (name.is_empty()) {
+ continue;
}
- layers->add_check_item(grid->names[i], i);
+ layers->add_check_item(name, i);
int idx = layers->get_item_index(i);
layers->set_item_checked(idx, grid->value & (1 << i));
}
+ if (layers->get_item_count() == 0) {
+ layers->add_item(TTR("No Named Layers"));
+ layers->set_item_disabled(0, true);
+ }
+ layers->add_separator();
+ layers->add_icon_item(get_theme_icon("Edit", "EditorIcons"), TTR("Edit Layer Names"), grid->layer_count);
+
Rect2 gp = button->get_screen_rect();
layers->reset_size();
Vector2 popup_pos = gp.position - Vector2(layers->get_contents_minimum_size().x, 0);
@@ -1280,14 +1303,19 @@ void EditorPropertyLayers::_button_pressed() {
}
void EditorPropertyLayers::_menu_pressed(int p_menu) {
- if (grid->value & (1 << p_menu)) {
- grid->value &= ~(1 << p_menu);
+ if (p_menu == grid->layer_count) {
+ ProjectSettingsEditor::get_singleton()->popup_project_settings();
+ ProjectSettingsEditor::get_singleton()->set_general_page(basename);
} else {
- grid->value |= (1 << p_menu);
+ if (grid->value & (1 << p_menu)) {
+ grid->value &= ~(1 << p_menu);
+ } else {
+ grid->value |= (1 << p_menu);
+ }
+ grid->queue_redraw();
+ layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu));
+ _grid_changed(grid->value);
}
- grid->queue_redraw();
- layers->set_item_checked(layers->get_item_index(p_menu), grid->value & (1 << p_menu));
- _grid_changed(grid->value);
}
void EditorPropertyLayers::_refresh_names() {
@@ -1489,12 +1517,12 @@ void EditorPropertyFloat::update_property() {
void EditorPropertyFloat::_bind_methods() {
}
-void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix, bool p_angle_in_radians) {
+void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix, bool p_angle_in_radians) {
angle_in_radians = p_angle_in_radians;
spin->set_min(p_min);
spin->set_max(p_max);
spin->set_step(p_step);
- spin->set_hide_slider(p_no_slider);
+ spin->set_hide_slider(p_hide_slider);
spin->set_exp_ratio(p_exp_range);
spin->set_allow_greater(p_greater);
spin->set_allow_lesser(p_lesser);
@@ -1797,12 +1825,12 @@ void EditorPropertyVector2::_notification(int p_what) {
}
}
-void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link, const String &p_suffix) {
+void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -1907,12 +1935,12 @@ void EditorPropertyRect2::_notification(int p_what) {
void EditorPropertyRect2::_bind_methods() {
}
-void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2078,13 +2106,13 @@ void EditorPropertyVector3::_notification(int p_what) {
void EditorPropertyVector3::_bind_methods() {
}
-void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link, const String &p_suffix, bool p_angle_in_radians) {
+void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_link, const String &p_suffix, bool p_angle_in_radians) {
angle_in_radians = p_angle_in_radians;
for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2210,12 +2238,12 @@ void EditorPropertyVector2i::_notification(int p_what) {
}
}
-void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider, bool p_link, const String &p_suffix) {
+void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2320,12 +2348,12 @@ void EditorPropertyRect2i::_notification(int p_what) {
void EditorPropertyRect2i::_bind_methods() {
}
-void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2464,12 +2492,12 @@ void EditorPropertyVector3i::_notification(int p_what) {
void EditorPropertyVector3i::_bind_methods() {
}
-void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider, bool p_link, const String &p_suffix) {
+void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) {
for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(1);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -2573,12 +2601,12 @@ void EditorPropertyPlane::_notification(int p_what) {
void EditorPropertyPlane::_bind_methods() {
}
-void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
}
@@ -2660,7 +2688,7 @@ void EditorPropertyQuaternion::_custom_value_changed(double val) {
v.y = Math::deg_to_rad(edit_euler.y);
v.z = Math::deg_to_rad(edit_euler.z);
- Quaternion temp_q = Quaternion(v);
+ Quaternion temp_q = Quaternion::from_euler(v);
spin[0]->set_value(temp_q.x);
spin[1]->set_value(temp_q.y);
spin[2]->set_value(temp_q.z);
@@ -2734,12 +2762,12 @@ void EditorPropertyQuaternion::_notification(int p_what) {
void EditorPropertyQuaternion::_bind_methods() {
}
-void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_hide_editor) {
+void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix, bool p_hide_editor) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
// Quaternion is inherently unitless, however someone may want to use it as
@@ -2882,16 +2910,14 @@ void EditorPropertyVector4::_notification(int p_what) {
void EditorPropertyVector4::_bind_methods() {
}
-void EditorPropertyVector4::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyVector4::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
- // Vector4 is inherently unitless, however someone may want to use it as
- // a generic way to store 4 values, so we'll still respect the suffix.
spin[i]->set_suffix(p_suffix);
}
}
@@ -2974,11 +3000,11 @@ void EditorPropertyVector4i::_notification(int p_what) {
void EditorPropertyVector4i::_bind_methods() {
}
-void EditorPropertyVector4i::setup(double p_min, double p_max, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyVector4i::setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -3069,12 +3095,12 @@ void EditorPropertyAABB::_notification(int p_what) {
void EditorPropertyAABB::_bind_methods() {
}
-void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 6; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix);
@@ -3157,12 +3183,12 @@ void EditorPropertyTransform2D::_notification(int p_what) {
void EditorPropertyTransform2D::_bind_methods() {
}
-void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 6; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 3 == 2) {
@@ -3249,12 +3275,12 @@ void EditorPropertyBasis::_notification(int p_what) {
void EditorPropertyBasis::_bind_methods() {
}
-void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 9; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
// Basis is inherently unitless, however someone may want to use it as
@@ -3347,12 +3373,12 @@ void EditorPropertyTransform3D::_notification(int p_what) {
void EditorPropertyTransform3D::_bind_methods() {
}
-void EditorPropertyTransform3D::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyTransform3D::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 12; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 4 == 3) {
@@ -3393,22 +3419,22 @@ void EditorPropertyProjection::_value_changed(double val, const String &p_name)
}
Projection p;
- p.matrix[0][0] = spin[0]->get_value();
- p.matrix[0][1] = spin[1]->get_value();
- p.matrix[0][2] = spin[2]->get_value();
- p.matrix[0][3] = spin[3]->get_value();
- p.matrix[1][0] = spin[4]->get_value();
- p.matrix[1][1] = spin[5]->get_value();
- p.matrix[1][2] = spin[6]->get_value();
- p.matrix[1][3] = spin[7]->get_value();
- p.matrix[2][0] = spin[8]->get_value();
- p.matrix[2][1] = spin[9]->get_value();
- p.matrix[2][2] = spin[10]->get_value();
- p.matrix[2][3] = spin[11]->get_value();
- p.matrix[3][0] = spin[12]->get_value();
- p.matrix[3][1] = spin[13]->get_value();
- p.matrix[3][2] = spin[14]->get_value();
- p.matrix[3][3] = spin[15]->get_value();
+ p.columns[0][0] = spin[0]->get_value();
+ p.columns[0][1] = spin[1]->get_value();
+ p.columns[0][2] = spin[2]->get_value();
+ p.columns[0][3] = spin[3]->get_value();
+ p.columns[1][0] = spin[4]->get_value();
+ p.columns[1][1] = spin[5]->get_value();
+ p.columns[1][2] = spin[6]->get_value();
+ p.columns[1][3] = spin[7]->get_value();
+ p.columns[2][0] = spin[8]->get_value();
+ p.columns[2][1] = spin[9]->get_value();
+ p.columns[2][2] = spin[10]->get_value();
+ p.columns[2][3] = spin[11]->get_value();
+ p.columns[3][0] = spin[12]->get_value();
+ p.columns[3][1] = spin[13]->get_value();
+ p.columns[3][2] = spin[14]->get_value();
+ p.columns[3][3] = spin[15]->get_value();
emit_changed(get_edited_property(), p, p_name);
}
@@ -3419,22 +3445,22 @@ void EditorPropertyProjection::update_property() {
void EditorPropertyProjection::update_using_transform(Projection p_transform) {
setting = true;
- spin[0]->set_value(p_transform.matrix[0][0]);
- spin[1]->set_value(p_transform.matrix[0][1]);
- spin[2]->set_value(p_transform.matrix[0][2]);
- spin[3]->set_value(p_transform.matrix[0][3]);
- spin[4]->set_value(p_transform.matrix[1][0]);
- spin[5]->set_value(p_transform.matrix[1][1]);
- spin[6]->set_value(p_transform.matrix[1][2]);
- spin[7]->set_value(p_transform.matrix[1][3]);
- spin[8]->set_value(p_transform.matrix[2][0]);
- spin[9]->set_value(p_transform.matrix[2][1]);
- spin[10]->set_value(p_transform.matrix[2][2]);
- spin[11]->set_value(p_transform.matrix[2][3]);
- spin[12]->set_value(p_transform.matrix[3][0]);
- spin[13]->set_value(p_transform.matrix[3][1]);
- spin[14]->set_value(p_transform.matrix[3][2]);
- spin[15]->set_value(p_transform.matrix[3][3]);
+ spin[0]->set_value(p_transform.columns[0][0]);
+ spin[1]->set_value(p_transform.columns[0][1]);
+ spin[2]->set_value(p_transform.columns[0][2]);
+ spin[3]->set_value(p_transform.columns[0][3]);
+ spin[4]->set_value(p_transform.columns[1][0]);
+ spin[5]->set_value(p_transform.columns[1][1]);
+ spin[6]->set_value(p_transform.columns[1][2]);
+ spin[7]->set_value(p_transform.columns[1][3]);
+ spin[8]->set_value(p_transform.columns[2][0]);
+ spin[9]->set_value(p_transform.columns[2][1]);
+ spin[10]->set_value(p_transform.columns[2][2]);
+ spin[11]->set_value(p_transform.columns[2][3]);
+ spin[12]->set_value(p_transform.columns[3][0]);
+ spin[13]->set_value(p_transform.columns[3][1]);
+ spin[14]->set_value(p_transform.columns[3][2]);
+ spin[15]->set_value(p_transform.columns[3][3]);
setting = false;
}
@@ -3453,12 +3479,12 @@ void EditorPropertyProjection::_notification(int p_what) {
void EditorPropertyProjection::_bind_methods() {
}
-void EditorPropertyProjection::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyProjection::setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix) {
for (int i = 0; i < 16; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
spin[i]->set_step(p_step);
- spin[i]->set_hide_slider(p_no_slider);
+ spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true);
if (i % 4 == 3) {
@@ -3646,8 +3672,8 @@ bool EditorPropertyNodePath::can_drop_data_fw(const Point2 &p_point, const Varia
void EditorPropertyNodePath::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
ERR_FAIL_COND(!is_drop_valid(p_data));
- Dictionary data = p_data;
- Array nodes = data["nodes"];
+ Dictionary data_dict = p_data;
+ Array nodes = data_dict["nodes"];
Node *node = get_tree()->get_edited_scene_root()->get_node(nodes[0]);
if (node) {
@@ -3673,7 +3699,8 @@ bool EditorPropertyNodePath::is_drop_valid(const Dictionary &p_drag_data) const
}
for (const StringName &E : valid_types) {
- if (dropped_node->is_class(E)) {
+ if (dropped_node->is_class(E) ||
+ EditorNode::get_singleton()->is_object_of_custom_type(dropped_node, E)) {
return true;
}
}
@@ -3975,19 +4002,19 @@ void EditorPropertyResource::_update_preferred_shader() {
if (parent_property) {
EditorShaderPicker *shader_picker = Object::cast_to<EditorShaderPicker>(resource_picker);
- Object *object = parent_property->get_edited_object();
- const StringName &property = parent_property->get_edited_property();
+ Object *ed_object = parent_property->get_edited_object();
+ const StringName &ed_property = parent_property->get_edited_property();
// Set preferred shader based on edited parent type.
- if ((Object::cast_to<GPUParticles2D>(object) || Object::cast_to<GPUParticles3D>(object)) && property == SNAME("process_material")) {
+ if ((Object::cast_to<GPUParticles2D>(ed_object) || Object::cast_to<GPUParticles3D>(ed_object)) && ed_property == SNAME("process_material")) {
shader_picker->set_preferred_mode(Shader::MODE_PARTICLES);
- } else if (Object::cast_to<FogVolume>(object)) {
+ } else if (Object::cast_to<FogVolume>(ed_object)) {
shader_picker->set_preferred_mode(Shader::MODE_FOG);
- } else if (Object::cast_to<CanvasItem>(object)) {
+ } else if (Object::cast_to<CanvasItem>(ed_object)) {
shader_picker->set_preferred_mode(Shader::MODE_CANVAS_ITEM);
- } else if (Object::cast_to<Node3D>(object) || Object::cast_to<Mesh>(object)) {
+ } else if (Object::cast_to<Node3D>(ed_object) || Object::cast_to<Mesh>(ed_object)) {
shader_picker->set_preferred_mode(Shader::MODE_SPATIAL);
- } else if (Object::cast_to<Sky>(object)) {
+ } else if (Object::cast_to<Sky>(ed_object)) {
shader_picker->set_preferred_mode(Shader::MODE_SKY);
}
}
@@ -4218,7 +4245,7 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
hint.or_greater = true;
} else if (slice == "or_less") {
hint.or_less = true;
- } else if (slice == "no_slider") {
+ } else if (slice == "hide_slider") {
hint.hide_slider = true;
} else if (slice == "exp") {
hint.exp_range = true;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index d6c9510634..20b130f57f 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -357,6 +357,7 @@ protected:
public:
void setup(LayerType p_layer_type);
void set_layer_name(int p_index, const String &p_name);
+ String get_layer_name(int p_index) const;
virtual void update_property() override;
EditorPropertyLayers();
};
@@ -433,7 +434,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix = String(), bool p_angle_in_radians = false);
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix = String(), bool p_angle_in_radians = false);
EditorPropertyFloat();
};
@@ -496,7 +497,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2(bool p_force_wide = false);
};
@@ -513,7 +514,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyRect2(bool p_force_wide = false);
};
@@ -541,7 +542,7 @@ public:
virtual void update_property() override;
virtual void update_using_vector(Vector3 p_vector);
virtual Vector3 get_vector();
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_link = false, const String &p_suffix = String(), bool p_angle_in_radians = false);
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, bool p_link = false, const String &p_suffix = String(), bool p_angle_in_radians = false);
EditorPropertyVector3(bool p_force_wide = false);
};
@@ -561,7 +562,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2i(bool p_force_wide = false);
};
@@ -578,7 +579,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyRect2i(bool p_force_wide = false);
};
@@ -603,7 +604,7 @@ protected:
public:
virtual void update_property() override;
- void setup(int p_min, int p_max, bool p_no_slider, bool p_link = false, const String &p_suffix = String());
+ void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector3i(bool p_force_wide = false);
};
@@ -620,7 +621,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyPlane(bool p_force_wide = false);
};
@@ -654,7 +655,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_hide_editor = false);
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String(), bool p_hide_editor = false);
EditorPropertyQuaternion();
};
@@ -671,7 +672,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyVector4();
};
@@ -688,7 +689,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyVector4i();
};
@@ -705,7 +706,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyAABB();
};
@@ -722,7 +723,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyTransform2D(bool p_include_origin = true);
};
@@ -739,7 +740,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyBasis();
};
@@ -757,7 +758,7 @@ protected:
public:
virtual void update_property() override;
virtual void update_using_transform(Transform3D p_transform);
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyTransform3D();
};
@@ -775,7 +776,7 @@ protected:
public:
virtual void update_property() override;
virtual void update_using_transform(Projection p_transform);
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_hide_slider, const String &p_suffix = String());
EditorPropertyProjection();
};
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 728a3b0f80..bec05a0cd6 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -260,9 +260,9 @@ void EditorPropertyArray::update_property() {
HBoxContainer *hbox = memnew(HBoxContainer);
vbox->add_child(hbox);
- Label *label = memnew(Label(TTR("Size:")));
- label->set_h_size_flags(SIZE_EXPAND_FILL);
- hbox->add_child(label);
+ Label *size_label = memnew(Label(TTR("Size:")));
+ size_label->set_h_size_flags(SIZE_EXPAND_FILL);
+ hbox->add_child(size_label);
size_slider = memnew(EditorSpinSlider);
size_slider->set_step(1);
@@ -293,7 +293,7 @@ void EditorPropertyArray::update_property() {
continue; // Don't remove the property that the user is moving.
}
- child->queue_delete(); // Button still needed after pressed is called.
+ child->queue_free(); // Button still needed after pressed is called.
property_vbox->remove_child(child);
}
}
@@ -367,17 +367,17 @@ void EditorPropertyArray::update_property() {
bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL;
if (is_untyped_array) {
- 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));
+ Button *edit_btn = memnew(Button);
+ edit_btn->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ hbox->add_child(edit_btn);
+ edit_btn->set_disabled(is_read_only());
+ edit_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit_btn, i + offset));
} else {
- Button *remove = 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);
+ Button *remove_btn = memnew(Button);
+ remove_btn->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ remove_btn->set_disabled(is_read_only());
+ remove_btn->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(i + offset));
+ hbox->add_child(remove_btn);
}
prop->update_property();
@@ -510,7 +510,7 @@ void EditorPropertyArray::_notification(int p_what) {
change_type->add_separator();
change_type->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Remove Item"), Variant::VARIANT_MAX);
- if (Object::cast_to<Button>(button_add_item)) {
+ if (button_add_item) {
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
} break;
@@ -861,7 +861,7 @@ void EditorPropertyDictionary::update_property() {
} else {
// Queue children for deletion, deleting immediately might cause errors.
for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
- property_vbox->get_child(i)->queue_delete();
+ property_vbox->get_child(i)->queue_free();
}
}
@@ -1155,11 +1155,11 @@ void EditorPropertyDictionary::update_property() {
}
hbox->add_child(prop);
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));
+ Button *edit_btn = memnew(Button);
+ edit_btn->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ edit_btn->set_disabled(is_read_only());
+ hbox->add_child(edit_btn);
+ edit_btn->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, change_index));
prop->update_property();
@@ -1205,7 +1205,7 @@ void EditorPropertyDictionary::_notification(int p_what) {
change_type->add_separator();
change_type->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Remove Item"), Variant::VARIANT_MAX);
- if (Object::cast_to<Button>(button_add_item)) {
+ if (button_add_item) {
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
} break;
@@ -1349,7 +1349,7 @@ void EditorPropertyLocalizableString::update_property() {
} else {
// Queue children for deletion, deleting immediately might cause errors.
for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
- property_vbox->get_child(i)->queue_delete();
+ property_vbox->get_child(i)->queue_free();
}
}
@@ -1396,10 +1396,10 @@ void EditorPropertyLocalizableString::update_property() {
property_vbox->add_child(hbox);
hbox->add_child(prop);
prop->set_h_size_flags(SIZE_EXPAND_FILL);
- Button *edit = memnew(Button);
- edit->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- hbox->add_child(edit);
- edit->connect("pressed", callable_mp(this, &EditorPropertyLocalizableString::_remove_item).bind(edit, remove_index));
+ Button *edit_btn = memnew(Button);
+ edit_btn->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ hbox->add_child(edit_btn);
+ edit_btn->connect("pressed", callable_mp(this, &EditorPropertyLocalizableString::_remove_item).bind(edit_btn, remove_index));
prop->update_property();
}
@@ -1431,7 +1431,7 @@ void EditorPropertyLocalizableString::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
- if (Object::cast_to<Button>(button_add_item)) {
+ if (button_add_item) {
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
} break;
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index f89aef4cc3..7c1e3e63ef 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -96,9 +96,9 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
}
if (preview_rect) {
- Ref<Script> script = edited_resource;
- if (script.is_valid()) {
- assign_button->set_text(script->get_path().get_file());
+ Ref<Script> scr = edited_resource;
+ if (scr.is_valid()) {
+ assign_button->set_text(scr->get_path().get_file());
return;
}
@@ -111,7 +111,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
assign_button->set_custom_minimum_size(assign_button_min_size);
} else {
preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
assign_button->set_custom_minimum_size(Size2(MAX(1, assign_button_min_size.x), MAX(thumbnail_size, assign_button_min_size.y)));
}
@@ -512,12 +512,9 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) {
}
bool EditorResourcePicker::handle_menu_selected(int p_which) {
- bool success;
- if (GDVIRTUAL_CALL(_handle_menu_selected, p_which, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_handle_menu_selected, p_which, success);
+ return success;
}
void EditorResourcePicker::_button_draw() {
@@ -958,6 +955,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
preview_rect->set_offset(SIDE_TOP, 1);
preview_rect->set_offset(SIDE_BOTTOM, -1);
preview_rect->set_offset(SIDE_RIGHT, -1);
+ preview_rect->set_texture_filter(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
assign_button->add_child(preview_rect);
}
@@ -981,8 +979,8 @@ void EditorScriptPicker::set_create_options(Object *p_menu_node) {
menu_node->add_icon_item(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")), TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
if (script_owner) {
- Ref<Script> script = script_owner->get_script();
- if (script.is_valid()) {
+ Ref<Script> scr = script_owner->get_script();
+ if (scr.is_valid()) {
menu_node->add_icon_item(get_theme_icon(SNAME("ScriptExtend"), SNAME("EditorIcons")), TTR("Extend Script"), OBJ_MENU_EXTEND_SCRIPT);
}
}
@@ -1040,12 +1038,12 @@ void EditorShaderPicker::set_create_options(Object *p_menu_node) {
}
bool EditorShaderPicker::handle_menu_selected(int p_which) {
- Ref<ShaderMaterial> material = Ref<ShaderMaterial>(get_edited_material());
+ Ref<ShaderMaterial> ed_material = Ref<ShaderMaterial>(get_edited_material());
switch (p_which) {
case OBJ_MENU_NEW_SHADER: {
- if (material.is_valid()) {
- SceneTreeDock::get_singleton()->open_shader_dialog(material, preferred_mode);
+ if (ed_material.is_valid()) {
+ SceneTreeDock::get_singleton()->open_shader_dialog(ed_material, preferred_mode);
return true;
}
} break;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 706b77c142..083b382521 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -41,7 +41,7 @@
#include "editor/editor_settings.h"
bool EditorResourcePreviewGenerator::handles(const String &p_type) const {
- bool success;
+ bool success = false;
if (GDVIRTUAL_CALL(_handles, p_type, success)) {
return success;
}
@@ -70,21 +70,15 @@ Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &
}
bool EditorResourcePreviewGenerator::generate_small_preview_automatically() const {
- bool success;
- if (GDVIRTUAL_CALL(_generate_small_preview_automatically, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_generate_small_preview_automatically, success);
+ return success;
}
bool EditorResourcePreviewGenerator::can_generate_small_preview() const {
- bool success;
- if (GDVIRTUAL_CALL(_can_generate_small_preview, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_can_generate_small_preview, success);
+ return success;
}
void EditorResourcePreviewGenerator::_bind_methods() {
@@ -148,7 +142,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref<
return; //could not guess type
}
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
r_texture = Ref<ImageTexture>();
@@ -232,7 +226,7 @@ void EditorResourcePreview::_iterate() {
Ref<ImageTexture> texture;
Ref<ImageTexture> small_texture;
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
if (item.resource.is_valid()) {
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 99c8481d33..599df12bd3 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -88,7 +88,7 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
}
}
- int screen = EditorSettings::get_singleton()->get("run/window_placement/screen");
+ int screen = EDITOR_GET("run/window_placement/screen");
if (screen == 0) {
// Same as editor
screen = DisplayServer::get_singleton()->window_get_current_screen();
@@ -114,21 +114,21 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
- int window_placement = EditorSettings::get_singleton()->get("run/window_placement/rect");
+ int window_placement = EDITOR_GET("run/window_placement/rect");
if (screen_rect != Rect2()) {
Size2 window_size;
- window_size.x = ProjectSettings::get_singleton()->get("display/window/size/viewport_width");
- window_size.y = ProjectSettings::get_singleton()->get("display/window/size/viewport_height");
+ window_size.x = GLOBAL_GET("display/window/size/viewport_width");
+ window_size.y = GLOBAL_GET("display/window/size/viewport_height");
Size2 desired_size;
- desired_size.x = ProjectSettings::get_singleton()->get("display/window/size/window_width_override");
- desired_size.y = ProjectSettings::get_singleton()->get("display/window/size/window_height_override");
+ desired_size.x = GLOBAL_GET("display/window/size/window_width_override");
+ desired_size.y = GLOBAL_GET("display/window/size/window_height_override");
if (desired_size.x > 0 && desired_size.y > 0) {
window_size = desired_size;
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_HIDPI)) {
- bool hidpi_proj = ProjectSettings::get_singleton()->get("display/window/dpi/allow_hidpi");
+ bool hidpi_proj = GLOBAL_GET("display/window/dpi/allow_hidpi");
int display_scale = 1;
if (OS::get_singleton()->is_hidpi_allowed()) {
@@ -159,7 +159,7 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back(itos(pos.x) + "," + itos(pos.y));
} break;
case 2: { // custom pos
- Vector2 pos = EditorSettings::get_singleton()->get("run/window_placement/rect_custom_position");
+ Vector2 pos = EDITOR_GET("run/window_placement/rect_custom_position");
pos += screen_rect.position;
args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y));
@@ -215,7 +215,7 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
String exec = OS::get_singleton()->get_executable_path();
- const String raw_custom_args = ProjectSettings::get_singleton()->get("editor/run/main_run_args");
+ const String raw_custom_args = GLOBAL_GET("editor/run/main_run_args");
if (!raw_custom_args.is_empty()) {
// Allow the user to specify a command to run, similar to Steam's launch options.
// In this case, Godot will no longer be run directly; it's up to the underlying command
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index e078bea037..ae47bbe864 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -151,7 +151,9 @@ void SectionedInspector::_section_selected() {
void SectionedInspector::set_current_section(const String &p_section) {
if (section_map.has(p_section)) {
- section_map[p_section]->select(0);
+ TreeItem *item = section_map[p_section];
+ item->select(0);
+ sections->scroll_to_item(item);
}
}
@@ -226,9 +228,9 @@ void SectionedInspector::update_category_list() {
TreeItem *root = sections->create_item();
section_map[""] = root;
- String filter;
+ String filter_text;
if (search_box) {
- filter = search_box->get_text();
+ filter_text = search_box->get_text();
}
const EditorPropertyNameProcessor::Style name_style = EditorPropertyNameProcessor::get_settings_style();
@@ -245,7 +247,7 @@ void SectionedInspector::update_category_list() {
continue;
}
- if (!filter.is_empty() && !_property_path_matches(pi.name, filter, name_style)) {
+ if (!filter_text.is_empty() && !_property_path_matches(pi.name, filter_text, name_style)) {
continue;
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 74445e6caa..409ef95fb0 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -76,14 +76,14 @@ bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value)
Array arr = p_value;
for (int i = 0; i < arr.size(); i++) {
Dictionary dict = arr[i];
- String name = dict["name"];
+ String shortcut_name = dict["name"];
Array shortcut_events = dict["shortcuts"];
Ref<Shortcut> sc;
sc.instantiate();
sc->set_events(shortcut_events);
- add_shortcut(name, sc);
+ add_shortcut(shortcut_name, sc);
}
return false;
@@ -92,16 +92,16 @@ bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value)
for (int i = 0; i < actions_arr.size(); i++) {
Dictionary action_dict = actions_arr[i];
- String name = action_dict["name"];
+ String action_name = action_dict["name"];
Array events = action_dict["events"];
InputMap *im = InputMap::get_singleton();
- im->action_erase_events(name);
+ im->action_erase_events(action_name);
- builtin_action_overrides[name].clear();
+ builtin_action_overrides[action_name].clear();
for (int ev_idx = 0; ev_idx < events.size(); ev_idx++) {
- im->action_add_event(name, events[ev_idx]);
- builtin_action_overrides[name].push_back(events[ev_idx]);
+ im->action_add_event(action_name, events[ev_idx]);
+ builtin_action_overrides[action_name].push_back(events[ev_idx]);
}
}
return false;
@@ -438,6 +438,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
_initial_set("interface/editor/mouse_extra_buttons_navigate_history", true);
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
+ EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/accept_dialog_cancel_ok_buttons", 0,
+ vformat("Auto (%s),Cancel First,OK First", DisplayServer::get_singleton()->get_swap_cancel_ok() ? "OK First" : "Cancel First"),
+ PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
#ifdef DEV_ENABLED
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_internal_errors_in_toast_notifications", 0, "Auto (Enabled),Enabled,Disabled")
#else
@@ -735,8 +738,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) {
Vector<String> list = p_extra_config->get_value("init_projects", "list");
for (int i = 0; i < list.size(); i++) {
- String name = list[i].replace("/", "::");
- set("projects/" + name, list[i]);
+ String proj_name = list[i].replace("/", "::");
+ set("projects/" + proj_name, list[i]);
}
}
@@ -774,7 +777,7 @@ void EditorSettings::_load_godot2_text_editor_theme() {
_initial_set("text_editor/theme/highlighting/safe_line_number_color", Color(0.67, 0.78, 0.67, 0.6));
_initial_set("text_editor/theme/highlighting/caret_color", Color(0.67, 0.67, 0.67));
_initial_set("text_editor/theme/highlighting/caret_background_color", Color(0, 0, 0));
- _initial_set("text_editor/theme/highlighting/text_selected_color", Color(0, 0, 0));
+ _initial_set("text_editor/theme/highlighting/text_selected_color", Color(0, 0, 0, 0));
_initial_set("text_editor/theme/highlighting/selection_color", Color(0.41, 0.61, 0.91, 0.35));
_initial_set("text_editor/theme/highlighting/brace_mismatch_color", Color(1, 0.2, 0.2));
_initial_set("text_editor/theme/highlighting/current_line_color", Color(0.3, 0.5, 0.8, 0.15));
@@ -1057,7 +1060,7 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default, bool p_re
Variant ret = p_default;
if (EditorSettings::get_singleton()->has_setting(p_setting)) {
- ret = EditorSettings::get_singleton()->get(p_setting);
+ ret = EDITOR_GET(p_setting);
} else {
EditorSettings::get_singleton()->set_manually(p_setting, p_default);
EditorSettings::get_singleton()->set_restart_if_changed(p_setting, p_restart_if_changed);
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 2c09543d92..db501aac03 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -41,6 +41,8 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/event_listener_line_edit.h"
+#include "editor/input_event_configuration_dialog.h"
#include "scene/gui/margin_container.h"
void EditorSettingsDialog::ok_pressed() {
@@ -106,11 +108,16 @@ void EditorSettingsDialog::popup_edit_settings() {
_focus_current_search_box();
}
-void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) {
- shortcut_filter = p_filter;
+void EditorSettingsDialog::_filter_shortcuts(const String &) {
_update_shortcuts();
}
+void EditorSettingsDialog::_filter_shortcuts_by_event(const Ref<InputEvent> &p_event) {
+ if (p_event.is_null() || (p_event->is_pressed() && !p_event->is_echo())) {
+ _update_shortcuts();
+ }
+}
+
void EditorSettingsDialog::_undo_redo_callback(void *p_self, const String &p_name) {
EditorNode::get_log()->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
}
@@ -326,6 +333,22 @@ void EditorSettingsDialog::_create_shortcut_treeitem(TreeItem *p_parent, const S
}
}
+bool EditorSettingsDialog::_should_display_shortcut(const String &p_name, const Array &p_events) const {
+ const Ref<InputEvent> search_ev = shortcut_search_by_event->get_event();
+ bool event_match = true;
+ if (search_ev.is_valid()) {
+ event_match = false;
+ for (int i = 0; i < p_events.size(); ++i) {
+ const Ref<InputEvent> ev = p_events[i];
+ if (ev.is_valid() && ev->is_match(search_ev, true)) {
+ event_match = true;
+ }
+ }
+ }
+
+ return event_match && shortcut_search_box->get_text().is_subsequence_ofn(p_name);
+}
+
void EditorSettingsDialog::_update_shortcuts() {
// Before clearing the tree, take note of which categories are collapsed so that this state can be maintained when the tree is repopulated.
HashMap<String, bool> collapsed;
@@ -379,32 +402,17 @@ void EditorSettingsDialog::_update_shortcuts() {
const String &action_name = E.key;
const InputMap::Action &action = E.value;
- Array events; // Need to get the list of events into an array so it can be set as metadata on the item.
- Vector<String> event_strings;
-
// Skip non-builtin actions.
if (!InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().has(action_name)) {
continue;
}
const List<Ref<InputEvent>> &all_default_events = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(action_name)->value;
- List<Ref<InputEventKey>> key_default_events;
- // Remove all non-key events from the defaults. Only check keys, since we are in the editor.
- for (const List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
- Ref<InputEventKey> k = I->get();
- if (k.is_valid()) {
- key_default_events.push_back(k);
- }
- }
-
- // Join the text of the events with a delimiter so they can all be displayed in one cell.
- String events_display_string = event_strings.is_empty() ? "None" : String("; ").join(event_strings);
-
- if (!shortcut_filter.is_subsequence_ofn(action_name) && (events_display_string == "None" || !shortcut_filter.is_subsequence_ofn(events_display_string))) {
+ Array action_events = _event_list_to_array_helper(action.inputs);
+ if (!_should_display_shortcut(action_name, action_events)) {
continue;
}
- Array action_events = _event_list_to_array_helper(action.inputs);
Array default_events = _event_list_to_array_helper(all_default_events);
bool same_as_defaults = Shortcut::is_event_array_equal(default_events, action_events);
bool collapse = !collapsed.has(action_name) || (collapsed.has(action_name) && collapsed[action_name]);
@@ -459,8 +467,7 @@ void EditorSettingsDialog::_update_shortcuts() {
String section_name = E.get_slice("/", 0);
TreeItem *section = sections[section_name];
- // Shortcut Item
- if (!shortcut_filter.is_subsequence_ofn(sc->get_name())) {
+ if (!_should_display_shortcut(sc->get_name(), sc->get_events())) {
continue;
}
@@ -749,12 +756,29 @@ EditorSettingsDialog::EditorSettingsDialog() {
tabs->add_child(tab_shortcuts);
tab_shortcuts->set_name(TTR("Shortcuts"));
+ HBoxContainer *top_hbox = memnew(HBoxContainer);
+ top_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ tab_shortcuts->add_child(top_hbox);
+
shortcut_search_box = memnew(LineEdit);
- shortcut_search_box->set_placeholder(TTR("Filter Shortcuts"));
+ shortcut_search_box->set_placeholder(TTR("Filter by name..."));
shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- tab_shortcuts->add_child(shortcut_search_box);
+ top_hbox->add_child(shortcut_search_box);
shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts));
+ shortcut_search_by_event = memnew(EventListenerLineEdit);
+ shortcut_search_by_event->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ shortcut_search_by_event->set_stretch_ratio(0.75);
+ shortcut_search_by_event->set_allowed_input_types(INPUT_KEY);
+ shortcut_search_by_event->connect("event_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts_by_event));
+ top_hbox->add_child(shortcut_search_by_event);
+
+ Button *clear_all_search = memnew(Button);
+ clear_all_search->set_text(TTR("Clear All"));
+ clear_all_search->connect("pressed", callable_mp(shortcut_search_box, &LineEdit::clear));
+ clear_all_search->connect("pressed", callable_mp(shortcut_search_by_event, &EventListenerLineEdit::clear_event));
+ top_hbox->add_child(clear_all_search);
+
shortcuts = memnew(Tree);
shortcuts->set_v_size_flags(Control::SIZE_EXPAND_FILL);
shortcuts->set_columns(2);
@@ -771,8 +795,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
// Adding event dialog
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);
+ shortcut_editor->set_allowed_input_types(INPUT_KEY);
add_child(shortcut_editor);
set_hide_on_ok(true);
diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h
index 87ed6a77eb..05424a64ed 100644
--- a/editor/editor_settings_dialog.h
+++ b/editor/editor_settings_dialog.h
@@ -53,6 +53,7 @@ class EditorSettingsDialog : public AcceptDialog {
LineEdit *search_box = nullptr;
LineEdit *shortcut_search_box = nullptr;
+ EventListenerLineEdit *shortcut_search_by_event = nullptr;
SectionedInspector *inspector = nullptr;
// Shortcuts
@@ -64,7 +65,6 @@ class EditorSettingsDialog : public AcceptDialog {
};
Tree *shortcuts = nullptr;
- String shortcut_filter;
InputEventConfigurationDialog *shortcut_editor = nullptr;
@@ -103,13 +103,13 @@ class EditorSettingsDialog : public AcceptDialog {
void _focus_current_search_box();
void _filter_shortcuts(const String &p_filter);
+ void _filter_shortcuts_by_event(const Ref<InputEvent> &p_event);
+ bool _should_display_shortcut(const String &p_name, const Array &p_events) const;
void _update_shortcuts();
void _shortcut_button_pressed(Object *p_item, int p_column, int p_idx, MouseButton p_button = MouseButton::LEFT);
void _shortcut_cell_double_clicked();
- void _builtin_action_popup_index_pressed(int p_index);
-
static void _undo_redo_callback(void *p_self, const String &p_name);
Label *restart_label = nullptr;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 5edb6d877c..1cdfceebc8 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -143,7 +143,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed() && k->is_action("ui_accept")) {
+ if (k.is_valid() && k->is_pressed() && k->is_action("ui_accept", true)) {
_focus_entered();
}
}
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index f4c1f308cc..17b5eb3314 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -564,9 +564,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("readonly_color", "Editor", readonly_color);
if (!dark_theme) {
- theme->set_color("vulkan_color", "Editor", Color::hex(0xad1128ff));
+ theme->set_color("highend_color", "Editor", Color::hex(0xad1128ff));
} else {
- theme->set_color("vulkan_color", "Editor", Color(1.0, 0.0, 0.0));
+ theme->set_color("highend_color", "Editor", Color(1.0, 0.0, 0.0));
}
const int thumb_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
theme->set_constant("scale", "Editor", EDSCALE);
@@ -1471,6 +1471,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
theme->set_stylebox("grabber_area_highlight", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
+ theme->set_constant("grabber_offset", "HSlider", 0);
// VSlider
theme->set_icon("grabber", "VSlider", theme->get_icon(SNAME("GuiSliderGrabber"), SNAME("EditorIcons")));
@@ -1478,6 +1479,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
+ theme->set_constant("grabber_offset", "VSlider", 0);
// RichTextLabel
theme->set_color("default_color", "RichTextLabel", font_color);
@@ -1714,6 +1716,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("h_width", "ColorPicker", 30 * EDSCALE);
theme->set_constant("label_width", "ColorPicker", 10 * EDSCALE);
theme->set_icon("screen_picker", "ColorPicker", theme->get_icon(SNAME("ColorPick"), SNAME("EditorIcons")));
+ theme->set_icon("shape_circle", "ColorPicker", theme->get_icon(SNAME("PickerShapeCircle"), SNAME("EditorIcons")));
+ theme->set_icon("shape_rect", "ColorPicker", theme->get_icon(SNAME("PickerShapeRectangle"), SNAME("EditorIcons")));
+ theme->set_icon("shape_rect_wheel", "ColorPicker", theme->get_icon(SNAME("PickerShapeRectangleWheel"), SNAME("EditorIcons")));
theme->set_icon("add_preset", "ColorPicker", theme->get_icon(SNAME("Add"), SNAME("EditorIcons")));
theme->set_icon("sample_bg", "ColorPicker", theme->get_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")));
theme->set_icon("overbright_indicator", "ColorPicker", theme->get_icon(SNAME("OverbrightIndicator"), SNAME("EditorIcons")));
@@ -1796,7 +1801,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color safe_line_number_color = dark_theme ? (dim_color * Color(1, 1.2, 1, 1.5)) : Color(0, 0.4, 0, 0.75);
const Color caret_color = mono_color;
const Color caret_background_color = mono_color.inverted();
- const Color text_selected_color = dark_color_3;
+ const Color text_selected_color = Color(0, 0, 0, 0);
const Color brace_mismatch_color = dark_theme ? error_color : Color(1, 0.08, 0, 1);
const Color current_line_color = alpha1;
const Color line_length_guideline_color = dark_theme ? base_color : background_color;
@@ -1902,7 +1907,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
Ref<Theme> theme = create_editor_theme(p_theme);
- const String custom_theme_path = EditorSettings::get_singleton()->get("interface/theme/custom_theme");
+ const String custom_theme_path = EDITOR_GET("interface/theme/custom_theme");
if (!custom_theme_path.is_empty()) {
Ref<Theme> custom_theme = ResourceLoader::load(custom_theme_path);
if (custom_theme.is_valid()) {
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 6a5242f0c6..504c8f0432 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -78,19 +78,19 @@ void EditorToaster::_notification(int p_what) {
// Change alpha over time.
bool needs_update = false;
for (const KeyValue<Control *, Toast> &element : toasts) {
- Color modulate = element.key->get_modulate();
+ Color modulate_fade = element.key->get_modulate();
// Change alpha over time.
- if (element.value.popped && modulate.a < 1.0) {
- modulate.a += delta * 3;
- element.key->set_modulate(modulate);
- } else if (!element.value.popped && modulate.a > 0.0) {
- modulate.a -= delta * 2;
- element.key->set_modulate(modulate);
+ if (element.value.popped && modulate_fade.a < 1.0) {
+ modulate_fade.a += delta * 3;
+ element.key->set_modulate(modulate_fade);
+ } else if (!element.value.popped && modulate_fade.a > 0.0) {
+ modulate_fade.a -= delta * 2;
+ element.key->set_modulate(modulate_fade);
}
// Hide element if it is not visible anymore.
- if (modulate.a <= 0) {
+ if (modulate_fade.a <= 0) {
if (element.key->is_visible()) {
element.key->hide();
needs_update = true;
@@ -231,7 +231,7 @@ void EditorToaster::_auto_hide_or_free_toasts() {
// Delete the control right away (removed as child) as it might cause issues otherwise when iterative over the vbox_container children.
for (unsigned int i = 0; i < to_delete.size(); i++) {
vbox_container->remove_child(to_delete[i]);
- to_delete[i]->queue_delete();
+ to_delete[i]->queue_free();
toasts.erase(to_delete[i]);
}
@@ -317,7 +317,7 @@ void EditorToaster::_set_notifications_enabled(bool p_enabled) {
void EditorToaster::_repop_old() {
// Repop olds, up to max_temporary_count
bool needs_update = false;
- int visible = 0;
+ int visible_count = 0;
for (int i = vbox_container->get_child_count() - 1; i >= 0; i--) {
Control *control = Object::cast_to<Control>(vbox_container->get_child(i));
if (!control->is_visible()) {
@@ -326,8 +326,8 @@ void EditorToaster::_repop_old() {
toasts[control].popped = true;
needs_update = true;
}
- visible++;
- if (visible >= max_temporary_count) {
+ visible_count++;
+ if (visible_count >= max_temporary_count) {
break;
}
}
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 064448fd96..09b567fc68 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -241,6 +241,7 @@ void EditorUndoRedoManager::commit_action(bool p_execute) {
history.undo_stack.push_back(pending_action);
pending_action = Action();
is_committing = false;
+ emit_signal(SNAME("history_changed"));
}
bool EditorUndoRedoManager::is_committing_action() const {
@@ -252,14 +253,14 @@ bool EditorUndoRedoManager::undo() {
return false;
}
- History *selected_history = nullptr;
+ int selected_history = INVALID_HISTORY;
double global_timestamp = 0;
// Pick the history with greatest last action timestamp (either global or current scene).
{
History &history = get_or_create_history(GLOBAL_HISTORY);
if (!history.undo_stack.is_empty()) {
- selected_history = &history;
+ selected_history = history.id;
global_timestamp = history.undo_stack.back()->get().timestamp;
}
}
@@ -267,32 +268,44 @@ bool EditorUndoRedoManager::undo() {
{
History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) {
- selected_history = &history;
+ selected_history = history.id;
}
}
- if (selected_history) {
- Action action = selected_history->undo_stack.back()->get();
- selected_history->undo_stack.pop_back();
- selected_history->redo_stack.push_back(action);
- return selected_history->undo_redo->undo();
+ if (selected_history != INVALID_HISTORY) {
+ return undo_history(selected_history);
}
return false;
}
+bool EditorUndoRedoManager::undo_history(int p_id) {
+ ERR_FAIL_COND_V(p_id == INVALID_HISTORY, false);
+ History &history = get_or_create_history(p_id);
+
+ Action action = history.undo_stack.back()->get();
+ history.undo_stack.pop_back();
+ history.redo_stack.push_back(action);
+
+ bool success = history.undo_redo->undo();
+ if (success) {
+ emit_signal(SNAME("version_changed"));
+ }
+ return success;
+}
+
bool EditorUndoRedoManager::redo() {
if (!has_redo()) {
return false;
}
- History *selected_history = nullptr;
+ int selected_history = INVALID_HISTORY;
double global_timestamp = INFINITY;
// Pick the history with lowest last action timestamp (either global or current scene).
{
History &history = get_or_create_history(GLOBAL_HISTORY);
if (!history.redo_stack.is_empty()) {
- selected_history = &history;
+ selected_history = history.id;
global_timestamp = history.redo_stack.back()->get().timestamp;
}
}
@@ -300,19 +313,31 @@ bool EditorUndoRedoManager::redo() {
{
History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) {
- selected_history = &history;
+ selected_history = history.id;
}
}
- if (selected_history) {
- Action action = selected_history->redo_stack.back()->get();
- selected_history->redo_stack.pop_back();
- selected_history->undo_stack.push_back(action);
- return selected_history->undo_redo->redo();
+ if (selected_history != INVALID_HISTORY) {
+ return redo_history(selected_history);
}
return false;
}
+bool EditorUndoRedoManager::redo_history(int p_id) {
+ ERR_FAIL_COND_V(p_id == INVALID_HISTORY, false);
+ History &history = get_or_create_history(p_id);
+
+ Action action = history.redo_stack.back()->get();
+ history.redo_stack.pop_back();
+ history.undo_stack.push_back(action);
+
+ bool success = history.undo_redo->redo();
+ if (success) {
+ emit_signal(SNAME("version_changed"));
+ }
+ return success;
+}
+
void EditorUndoRedoManager::set_history_as_saved(int p_id) {
History &history = get_or_create_history(p_id);
history.saved_version = history.undo_redo->get_version();
@@ -352,6 +377,7 @@ void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) {
if (!p_increase_version) {
set_history_as_saved(p_idx);
}
+ emit_signal(SNAME("history_changed"));
return;
}
@@ -359,6 +385,7 @@ void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) {
E.value.undo_redo->clear_history(p_increase_version);
set_history_as_saved(E.key);
}
+ emit_signal(SNAME("history_changed"));
}
String EditorUndoRedoManager::get_current_action_name() {
@@ -434,6 +461,9 @@ void EditorUndoRedoManager::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object);
ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo);
+ ADD_SIGNAL(MethodInfo("history_changed"));
+ ADD_SIGNAL(MethodInfo("version_changed"));
+
BIND_ENUM_CONSTANT(GLOBAL_HISTORY);
BIND_ENUM_CONSTANT(INVALID_HISTORY);
}
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
index c4d85daa22..60bcd059df 100644
--- a/editor/editor_undo_redo_manager.h
+++ b/editor/editor_undo_redo_manager.h
@@ -44,7 +44,6 @@ public:
INVALID_HISTORY = -99,
};
-private:
struct Action {
int history_id = INVALID_HISTORY;
double timestamp = 0;
@@ -60,6 +59,7 @@ private:
List<Action> redo_stack;
};
+private:
HashMap<int, History> history_map;
Action pending_action;
@@ -114,7 +114,9 @@ public:
bool is_committing_action() const;
bool undo();
+ bool undo_history(int p_id);
bool redo();
+ bool redo_history(int p_id);
void clear_history(bool p_increase_version = true, int p_idx = INVALID_HISTORY);
void set_history_as_saved(int p_idx);
diff --git a/editor/editor_zoom_widget.cpp b/editor/editor_zoom_widget.cpp
index 88e99d9b30..8e820f41ee 100644
--- a/editor/editor_zoom_widget.cpp
+++ b/editor/editor_zoom_widget.cpp
@@ -161,13 +161,19 @@ void EditorZoomWidget::_bind_methods() {
ADD_SIGNAL(MethodInfo("zoom_changed", PropertyInfo(Variant::FLOAT, "zoom")));
}
+void EditorZoomWidget::set_shortcut_context(Node *p_node) const {
+ zoom_minus->set_shortcut_context(p_node);
+ zoom_plus->set_shortcut_context(p_node);
+ zoom_reset->set_shortcut_context(p_node);
+}
+
EditorZoomWidget::EditorZoomWidget() {
// Zoom buttons
zoom_minus = memnew(Button);
zoom_minus->set_flat(true);
add_child(zoom_minus);
zoom_minus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_minus));
- zoom_minus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_minus", TTR("Zoom Out"), KeyModifierMask::CMD_OR_CTRL | Key::MINUS));
+ zoom_minus->set_shortcut(ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_minus", TTR("Zoom Out"), { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::MINUS), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_SUBTRACT) }));
zoom_minus->set_shortcut_context(this);
zoom_minus->set_focus_mode(FOCUS_NONE);
@@ -189,7 +195,7 @@ EditorZoomWidget::EditorZoomWidget() {
zoom_plus->set_flat(true);
add_child(zoom_plus);
zoom_plus->connect("pressed", callable_mp(this, &EditorZoomWidget::_button_zoom_plus));
- zoom_plus->set_shortcut(ED_SHORTCUT("canvas_item_editor/zoom_plus", TTR("Zoom In"), KeyModifierMask::CMD_OR_CTRL | Key::EQUAL)); // Usually direct access key for PLUS
+ zoom_plus->set_shortcut(ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_plus", TTR("Zoom In"), { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::EQUAL), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_ADD) }));
zoom_plus->set_shortcut_context(this);
zoom_plus->set_focus_mode(FOCUS_NONE);
diff --git a/editor/editor_zoom_widget.h b/editor/editor_zoom_widget.h
index 4690a57a2b..995b9e1808 100644
--- a/editor/editor_zoom_widget.h
+++ b/editor/editor_zoom_widget.h
@@ -57,6 +57,8 @@ public:
float get_zoom();
void set_zoom(float p_zoom);
void set_zoom_by_increments(int p_increment_count, bool p_integer_only = false);
+ // Sets the shortcut context for the zoom buttons. By default their context is this EditorZoomWidget control.
+ void set_shortcut_context(Node *p_node) const;
};
#endif // EDITOR_ZOOM_WIDGET_H
diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp
new file mode 100644
index 0000000000..e4c35a5b81
--- /dev/null
+++ b/editor/event_listener_line_edit.cpp
@@ -0,0 +1,138 @@
+/*************************************************************************/
+/* event_listener_line_edit.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 "editor/event_listener_line_edit.h"
+
+bool EventListenerLineEdit::_is_event_allowed(const Ref<InputEvent> &p_event) const {
+ const Ref<InputEventMouseButton> mb = p_event;
+ const Ref<InputEventKey> k = p_event;
+ const Ref<InputEventJoypadButton> jb = p_event;
+ const Ref<InputEventJoypadMotion> jm = p_event;
+
+ return (mb.is_valid() && (allowed_input_types & INPUT_MOUSE_BUTTON)) ||
+ (k.is_valid() && (allowed_input_types & INPUT_KEY)) ||
+ (jb.is_valid() && (allowed_input_types & INPUT_JOY_BUTTON)) ||
+ (jm.is_valid() && (allowed_input_types & INPUT_JOY_MOTION));
+}
+
+void EventListenerLineEdit::gui_input(const Ref<InputEvent> &p_event) {
+ const Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ LineEdit::gui_input(p_event);
+ return;
+ }
+
+ // Allow mouse button click on the clear button without being treated as an event.
+ const Ref<InputEventMouseButton> b = p_event;
+ if (b.is_valid() && _is_over_clear_button(b->get_position())) {
+ LineEdit::gui_input(p_event);
+ return;
+ }
+
+ // First event will be an event which is used to focus this control - i.e. a mouse click, or a tab press.
+ // Ignore the first one so that clicking into the LineEdit does not override the current event.
+ // Ignore is reset to true when the control is unfocused.
+ // This class also specially handles grab_focus() calls.
+ if (ignore_next_event) {
+ ignore_next_event = false;
+ return;
+ }
+
+ accept_event();
+ if (!p_event->is_pressed() || p_event->is_echo() || p_event->is_match(event) || !_is_event_allowed(p_event)) {
+ return;
+ }
+
+ event = p_event;
+ set_text(event->as_text());
+ emit_signal("event_changed", event);
+}
+
+void EventListenerLineEdit::_on_text_changed(const String &p_text) {
+ if (p_text.is_empty()) {
+ clear_event();
+ }
+}
+
+void EventListenerLineEdit::_on_focus() {
+ set_placeholder(TTR("Listening for input..."));
+}
+
+void EventListenerLineEdit::_on_unfocus() {
+ ignore_next_event = true;
+ set_placeholder(TTR("Filter by event..."));
+}
+
+Ref<InputEvent> EventListenerLineEdit::get_event() const {
+ return event;
+}
+
+void EventListenerLineEdit::clear_event() {
+ if (event.is_valid()) {
+ event = Ref<InputEvent>();
+ set_text("");
+ emit_signal("event_changed", event);
+ }
+}
+
+void EventListenerLineEdit::set_allowed_input_types(int input_types) {
+ allowed_input_types = input_types;
+}
+
+int EventListenerLineEdit::get_allowed_input_types() const {
+ return allowed_input_types;
+}
+
+void EventListenerLineEdit::grab_focus() {
+ // If we grab focus through code, we don't need to ignore the first event!
+ ignore_next_event = false;
+ Control::grab_focus();
+}
+
+void EventListenerLineEdit::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("text_changed", callable_mp(this, &EventListenerLineEdit::_on_text_changed));
+ connect("focus_entered", callable_mp(this, &EventListenerLineEdit::_on_focus));
+ connect("focus_exited", callable_mp(this, &EventListenerLineEdit::_on_unfocus));
+ set_right_icon(get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons")));
+ set_clear_button_enabled(true);
+ } break;
+ }
+}
+
+void EventListenerLineEdit::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("event_changed", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
+}
+
+EventListenerLineEdit::EventListenerLineEdit() {
+ set_caret_blink_enabled(false);
+ set_placeholder(TTR("Filter by event..."));
+}
diff --git a/modules/websocket/websocket_macros.h b/editor/event_listener_line_edit.h
index b03bd8f45c..c4cd5e4511 100644
--- a/modules/websocket/websocket_macros.h
+++ b/editor/event_listener_line_edit.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* websocket_macros.h */
+/* event_listener_line_edit.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,39 +28,49 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WEBSOCKET_MACROS_H
-#define WEBSOCKET_MACROS_H
+#ifndef EVENT_LISTENER_LINE_EDIT_H
+#define EVENT_LISTENER_LINE_EDIT_H
-// Defaults per peer buffers, 1024 packets with a shared 65536 bytes payload.
-#define DEF_PKT_SHIFT 10
-#define DEF_BUF_SHIFT 16
+#include "scene/gui/line_edit.h"
-#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:
+enum InputType {
+ INPUT_KEY = 1,
+ INPUT_MOUSE_BUTTON = 2,
+ INPUT_JOY_BUTTON = 4,
+ INPUT_JOY_MOTION = 8
+};
+
+class EventListenerLineEdit : public LineEdit {
+ GDCLASS(EventListenerLineEdit, LineEdit)
+
+ int allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
+ bool ignore_next_event = true;
+ bool share_keycodes = false;
+ Ref<InputEvent> event;
+
+ bool _is_event_allowed(const Ref<InputEvent> &p_event) const;
+
+ void gui_input(const Ref<InputEvent> &p_event) override;
+ void _on_text_changed(const String &p_text);
-#define GDCINULL(CNAME) \
- CNAME *(*CNAME::_create)() = nullptr;
+ void _on_focus();
+ void _on_unfocus();
-#define GDCIIMPL(IMPNAME, CNAME) \
-public: \
- static CNAME *_create() { return memnew(IMPNAME); } \
- static void make_default() { CNAME::_create = IMPNAME::_create; } \
- \
protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ Ref<InputEvent> get_event() const;
+ void clear_event();
+
+ void set_allowed_input_types(int input_types);
+ int get_allowed_input_types() const;
+
+ void grab_focus();
+
+public:
+ EventListenerLineEdit();
+};
-#endif // WEBSOCKET_MACROS_H
+#endif // EVENT_LISTENER_LINE_EDIT_H
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 29b6a5e546..c2aa27b34d 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -124,7 +124,7 @@ void EditorExport::add_export_preset(const Ref<EditorExportPreset> &p_preset, in
}
String EditorExportPlatform::test_etc2() const {
- const bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2");
+ const bool etc2_supported = GLOBAL_GET("rendering/textures/vram_compression/import_etc2");
if (!etc2_supported) {
return TTR("Target platform requires 'ETC2' texture compression. Enable 'Import Etc 2' in Project Settings.");
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index c86114a140..7c5c7da2ef 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -136,16 +136,16 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
}
void EditorExportPlatform::gen_debug_flags(Vector<String> &r_flags, int p_flags) {
- String host = EditorSettings::get_singleton()->get("network/debug/remote_host");
- int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ String host = EDITOR_GET("network/debug/remote_host");
+ int remote_port = (int)EDITOR_GET("network/debug/remote_port");
if (p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST) {
host = "localhost";
}
if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
- int port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
- String passwd = EditorSettings::get_singleton()->get("filesystem/file_server/password");
+ int port = EDITOR_GET("filesystem/file_server/port");
+ String passwd = EDITOR_GET("filesystem/file_server/password");
r_flags.push_back("--remote-fs");
r_flags.push_back(host + ":" + itos(port));
if (!passwd.is_empty()) {
@@ -813,7 +813,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
continue;
}
- String autoload_path = ProjectSettings::get_singleton()->get(pi.name);
+ String autoload_path = GLOBAL_GET(pi.name);
if (autoload_path.begins_with("*")) {
autoload_path = autoload_path.substr(1);
@@ -1241,8 +1241,8 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
// Store icon and splash images directly, they need to bypass the import system and be loaded as images
- String icon = ProjectSettings::get_singleton()->get("application/config/icon");
- String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ String icon = GLOBAL_GET("application/config/icon");
+ String splash = GLOBAL_GET("application/boot_splash/image");
if (!icon.is_empty() && FileAccess::exists(icon)) {
Vector<uint8_t> array = FileAccess::get_file_as_array(icon);
err = p_func(p_udata, icon, array, idx, total, enc_in_filters, enc_ex_filters, key);
@@ -1277,7 +1277,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
// Store text server data if it is supported.
if (TS->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
- bool use_data = ProjectSettings::get_singleton()->get("internationalization/locale/include_text_server_data");
+ bool use_data = GLOBAL_GET("internationalization/locale/include_text_server_data");
if (use_data) {
// Try using user provided data file.
String ts_data = "res://" + TS->get_support_data_filename();
@@ -1569,16 +1569,16 @@ Error EditorExportPlatform::export_zip(const Ref<EditorExportPreset> &p_preset,
}
void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags) {
- String host = EditorSettings::get_singleton()->get("network/debug/remote_host");
- int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ String host = EDITOR_GET("network/debug/remote_host");
+ int remote_port = (int)EDITOR_GET("network/debug/remote_port");
if (p_flags & DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST) {
host = "localhost";
}
if (p_flags & DEBUG_FLAG_DUMB_CLIENT) {
- int port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
- String passwd = EditorSettings::get_singleton()->get("filesystem/file_server/password");
+ int port = EDITOR_GET("filesystem/file_server/port");
+ String passwd = EDITOR_GET("filesystem/file_server/password");
r_flags.push_back("--remote-fs");
r_flags.push_back(host + ":" + itos(port));
if (!passwd.is_empty()) {
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 88dc7bd5cd..5db79b98d1 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -144,6 +144,7 @@ public:
};
virtual Ref<EditorExportPreset> create_preset();
+ virtual bool is_executable(const String &p_path) const { return false; }
virtual void clear_messages() { messages.clear(); }
virtual void add_message(ExportMessageType p_type, const String &p_category, const String &p_message) {
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 8538414523..c5b61e9b03 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -185,10 +185,12 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
String target_path;
if (so_files[i].target.is_empty()) {
- target_path = p_path.get_base_dir().path_join(src_path.get_file());
+ target_path = p_path.get_base_dir();
} else {
- target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file());
+ target_path = p_path.get_base_dir().path_join(so_files[i].target);
+ da->make_dir_recursive(target_path);
}
+ target_path = target_path.path_join(src_path.get_file());
if (da->dir_exists(src_path)) {
err = da->make_dir_recursive(target_path);
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index 971ea579cc..78d4f93dfe 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -142,10 +142,8 @@ void EditorExportPlugin::_export_end_script() {
bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
bool ret = false;
- if (GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret)) {
- return ret;
- }
- return false;
+ GDVIRTUAL_CALL(_begin_customize_resources, p_platform, p_features, ret);
+ return ret;
}
Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) {
@@ -158,10 +156,8 @@ Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_res
bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const {
bool ret = false;
- if (GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret)) {
- return ret;
- }
- return false;
+ GDVIRTUAL_CALL(_begin_customize_scenes, p_platform, p_features, ret);
+ return ret;
}
Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) {
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index ceb5b63293..9ebf4d795a 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -265,9 +265,9 @@ void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code,
mirrors_available = false;
- Dictionary data = json.get_data();
- if (data.has("mirrors")) {
- Array mirrors = data["mirrors"];
+ Dictionary mirror_data = json.get_data();
+ if (mirror_data.has("mirrors")) {
+ Array mirrors = mirror_data["mirrors"];
for (int i = 0; i < mirrors.size(); i++) {
Dictionary m = mirrors[i];
@@ -401,17 +401,17 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
String file = String::utf8(fname);
if (file.ends_with("version.txt")) {
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
+ Vector<uint8_t> uncomp_data;
+ uncomp_data.resize(info.uncompressed_size);
// Read.
unzOpenCurrentFile(pkg);
- ret = unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ ret = unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", file));
unzCloseCurrentFile(pkg);
String data_str;
- data_str.parse_utf8((const char *)data.ptr(), data.size());
+ data_str.parse_utf8((const char *)uncomp_data.ptr(), uncomp_data.size());
data_str = data_str.strip_edges();
// Version number should be of the form major.minor[.patch].status[.module_config]
@@ -473,12 +473,12 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
continue;
}
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
+ Vector<uint8_t> uncomp_data;
+ uncomp_data.resize(info.uncompressed_size);
// Read
unzOpenCurrentFile(pkg);
- ret = unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ ret = unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", file));
unzCloseCurrentFile(pkg);
@@ -512,7 +512,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
ERR_CONTINUE_MSG(true, "Can't open file from path '" + String(to_write) + "'.");
}
- f->store_buffer(data.ptr(), data.size());
+ f->store_buffer(uncomp_data.ptr(), uncomp_data.size());
f.unref(); // close file.
#ifndef WINDOWS_ENABLED
FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF);
@@ -714,12 +714,12 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
String base_dir = path.get_base_dir();
if (!path.ends_with("/")) {
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
+ Vector<uint8_t> uncomp_data;
+ uncomp_data.resize(info.uncompressed_size);
// Read.
unzOpenCurrentFile(pkg);
- unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
unzCloseCurrentFile(pkg);
if (!dirs_tested.has(base_dir)) {
@@ -730,7 +730,7 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
String to_write = String("res://android/build").path_join(path);
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_valid()) {
- f->store_buffer(data.ptr(), data.size());
+ f->store_buffer(uncomp_data.ptr(), uncomp_data.size());
f.unref(); // close file.
#ifndef WINDOWS_ENABLED
FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF);
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 43aac5e981..6ff3539708 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -94,7 +94,7 @@ void ProjectExportDialog::_add_preset(int p_platform) {
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_platform(p_platform)->create_preset();
ERR_FAIL_COND(!preset.is_valid());
- String name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name();
+ String preset_name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name();
bool make_runnable = true;
int attempt = 1;
while (true) {
@@ -105,7 +105,7 @@ void ProjectExportDialog::_add_preset(int p_platform) {
if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
make_runnable = false;
}
- if (p->get_name() == name) {
+ if (p->get_name() == preset_name) {
valid = false;
break;
}
@@ -116,10 +116,10 @@ void ProjectExportDialog::_add_preset(int p_platform) {
}
attempt++;
- name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name() + " " + itos(attempt);
+ preset_name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name() + " " + itos(attempt);
}
- preset->set_name(name);
+ preset->set_name(preset_name);
if (make_runnable) {
preset->set_runnable(make_runnable);
}
@@ -154,12 +154,12 @@ void ProjectExportDialog::_update_presets() {
current_idx = i;
}
- String name = preset->get_name();
+ String preset_name = preset->get_name();
if (preset->is_runnable()) {
- name += " (" + TTR("Runnable") + ")";
+ preset_name += " (" + TTR("Runnable") + ")";
}
preset->update_files_to_export();
- presets->add_item(name, preset->get_platform()->get_logo());
+ presets->add_item(preset_name, preset->get_platform()->get_logo());
}
if (current_idx != -1) {
@@ -552,7 +552,7 @@ void ProjectExportDialog::_duplicate_preset() {
Ref<EditorExportPreset> preset = current->get_platform()->create_preset();
ERR_FAIL_COND(!preset.is_valid());
- String name = current->get_name() + " (copy)";
+ String preset_name = current->get_name() + " (copy)";
bool make_runnable = true;
while (true) {
bool valid = true;
@@ -562,7 +562,7 @@ void ProjectExportDialog::_duplicate_preset() {
if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
make_runnable = false;
}
- if (p->get_name() == name) {
+ if (p->get_name() == preset_name) {
valid = false;
break;
}
@@ -572,10 +572,10 @@ void ProjectExportDialog::_duplicate_preset() {
break;
}
- name += " (copy)";
+ preset_name += " (copy)";
}
- preset->set_name(name);
+ preset->set_name(preset_name);
if (make_runnable) {
preset->set_runnable(make_runnable);
}
@@ -945,8 +945,8 @@ void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
}
void ProjectExportDialog::_export_all(bool p_debug) {
- String mode = p_debug ? TTR("Debug") : TTR("Release");
- EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count(), true);
+ String export_target = p_debug ? TTR("Debug") : TTR("Release");
+ EditorProgress ep("exportall", TTR("Exporting All") + " " + export_target, EditorExport::get_singleton()->get_export_preset_count(), true);
bool show_dialog = false;
result_dialog_log->clear();
@@ -1015,9 +1015,7 @@ ProjectExportDialog::ProjectExportDialog() {
preset_vb->add_child(mc);
mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
presets = memnew(ItemList);
-#ifndef _MSC_VER
-#warning must reimplement drag forward
-#endif
+ // TODO: Must reimplement drag forwarding.
//presets->set_drag_forwarding(this);
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
@@ -1292,7 +1290,7 @@ ProjectExportDialog::ProjectExportDialog() {
// If no default set, use project name
if (default_filename.is_empty()) {
// If no project name defined, use a sane default
- default_filename = ProjectSettings::get_singleton()->get("application/config/name");
+ default_filename = GLOBAL_GET("application/config/name");
if (default_filename.is_empty()) {
default_filename = "UnnamedProject";
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 424eab2f02..62bcf0b193 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -106,7 +106,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
// Create all items for the files in the subdirectory.
if (display_mode == DISPLAY_MODE_TREE_ONLY) {
- String main_scene = ProjectSettings::get_singleton()->get("application/run/main_scene");
+ String main_scene = GLOBAL_GET("application/run/main_scene");
// Build the list of the files to display.
List<FileInfo> file_list;
@@ -218,11 +218,11 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
TreeItem *root = tree->create_item();
// Handles the favorites.
- TreeItem *favorites = tree->create_item(root);
- favorites->set_icon(0, get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
- favorites->set_text(0, TTR("Favorites:"));
- favorites->set_metadata(0, "Favorites");
- favorites->set_collapsed(p_uncollapsed_paths.find("Favorites") < 0);
+ TreeItem *favorites_item = tree->create_item(root);
+ favorites_item->set_icon(0, get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
+ favorites_item->set_text(0, TTR("Favorites:"));
+ favorites_item->set_metadata(0, "Favorites");
+ favorites_item->set_collapsed(p_uncollapsed_paths.find("Favorites") < 0);
Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorites();
@@ -272,7 +272,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
}
if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) {
- TreeItem *ti = tree->create_item(favorites);
+ TreeItem *ti = tree->create_item(favorites_item);
ti->set_text(0, text);
ti->set_icon(0, icon);
ti->set_icon_modulate(0, color);
@@ -383,7 +383,7 @@ void FileSystemDock::_notification(int p_what) {
current_path->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path).bind(false));
- always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"));
+ always_show_folders = bool(EDITOR_GET("docks/filesystem/always_show_folders"));
set_file_list_display_mode(FileSystemDock::FILE_LIST_DISPLAY_LIST);
@@ -464,7 +464,7 @@ void FileSystemDock::_notification(int p_what) {
file_list_button_sort->set_icon(get_theme_icon(SNAME("Sort"), SNAME("EditorIcons")));
// Update always show folders.
- bool new_always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders"));
+ bool new_always_show_folders = bool(EDITOR_GET("docks/filesystem/always_show_folders"));
if (new_always_show_folders != always_show_folders) {
always_show_folders = new_always_show_folders;
_update_file_list(true);
@@ -743,7 +743,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
String directory = path;
String file = "";
- int thumbnail_size = EditorSettings::get_singleton()->get("docks/filesystem/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("docks/filesystem/thumbnail_size");
thumbnail_size *= EDSCALE;
Ref<Texture2D> folder_thumbnail;
Ref<Texture2D> file_thumbnail;
@@ -784,9 +784,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
List<FileInfo> file_list;
if (path == "Favorites") {
// Display the favorites.
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
- for (int i = 0; i < favorites.size(); i++) {
- String favorite = favorites[i];
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
+ for (const String &favorite : favorites_list) {
String text;
Ref<Texture2D> icon;
if (favorite == "res://") {
@@ -894,7 +893,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
_sort_file_info_list(file_list);
// Fills the ItemList control node from the FileInfos.
- String main_scene = ProjectSettings::get_singleton()->get("application/run/main_scene");
+ String main_scene = GLOBAL_GET("application/run/main_scene");
for (FileInfo &E : file_list) {
FileInfo *finfo = &(E);
String fname = finfo->name;
@@ -1056,15 +1055,15 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit
void FileSystemDock::_tree_activate_file() {
TreeItem *selected = tree->get_selected();
if (selected) {
- String path = selected->get_metadata(0);
+ String file_path = selected->get_metadata(0);
TreeItem *parent = selected->get_parent();
bool is_favorite = parent != nullptr && parent->get_metadata(0) == "Favorites";
- if ((!is_favorite && path.ends_with("/")) || path == "Favorites") {
+ if ((!is_favorite && file_path.ends_with("/")) || file_path == "Favorites") {
bool collapsed = selected->is_collapsed();
selected->set_collapsed(!collapsed);
} else {
- _select_file(path, is_favorite && !path.ends_with("/"));
+ _select_file(file_path, is_favorite && !file_path.ends_with("/"));
}
}
}
@@ -1169,29 +1168,29 @@ void FileSystemDock::_push_to_history() {
button_hist_next->set_disabled(history_pos == history.size() - 1);
}
-void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files, Vector<String> &folders) const {
- if (efsd == nullptr) {
+void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const {
+ if (p_efsd == nullptr) {
return;
}
- for (int i = 0; i < efsd->get_subdir_count(); i++) {
- folders.push_back(efsd->get_subdir(i)->get_path());
- _get_all_items_in_dir(efsd->get_subdir(i), files, folders);
+ for (int i = 0; i < p_efsd->get_subdir_count(); i++) {
+ r_folders.push_back(p_efsd->get_subdir(i)->get_path());
+ _get_all_items_in_dir(p_efsd->get_subdir(i), r_files, r_folders);
}
- for (int i = 0; i < efsd->get_file_count(); i++) {
- files.push_back(efsd->get_file_path(i));
+ for (int i = 0; i < p_efsd->get_file_count(); i++) {
+ r_files.push_back(p_efsd->get_file_path(i));
}
}
-void FileSystemDock::_find_remaps(EditorFileSystemDirectory *efsd, const HashMap<String, String> &renames, Vector<String> &to_remaps) const {
- for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _find_remaps(efsd->get_subdir(i), renames, to_remaps);
+void FileSystemDock::_find_remaps(EditorFileSystemDirectory *p_efsd, const HashMap<String, String> &r_renames, Vector<String> &r_to_remaps) const {
+ for (int i = 0; i < p_efsd->get_subdir_count(); i++) {
+ _find_remaps(p_efsd->get_subdir(i), r_renames, r_to_remaps);
}
- for (int i = 0; i < efsd->get_file_count(); i++) {
- Vector<String> deps = efsd->get_file_deps(i);
+ for (int i = 0; i < p_efsd->get_file_count(); i++) {
+ Vector<String> deps = p_efsd->get_file_deps(i);
for (int j = 0; j < deps.size(); j++) {
- if (renames.has(deps[j])) {
- to_remaps.push_back(efsd->get_file_path(i));
+ if (r_renames.has(deps[j])) {
+ r_to_remaps.push_back(p_efsd->get_file_path(i));
break;
}
}
@@ -1284,42 +1283,71 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
}
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- print_verbose("Duplicating " + old_path + " -> " + new_path);
- Error err = p_item.is_file ? da->copy(old_path, new_path) : da->copy_dir(old_path, new_path);
- if (err == OK) {
- // Move/Rename any corresponding import settings too.
- if (p_item.is_file && FileAccess::exists(old_path + ".import")) {
- err = da->copy(old_path + ".import", new_path + ".import");
+
+ if (p_item.is_file) {
+ print_verbose("Duplicating " + old_path + " -> " + new_path);
+
+ // Create the directory structure.
+ da->make_dir_recursive(new_path.get_base_dir());
+
+ if (FileAccess::exists(old_path + ".import")) {
+ Error err = da->copy(old_path, new_path);
if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ".import\n");
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
+ return;
}
// Remove uid from .import file to avoid conflict.
Ref<ConfigFile> cfg;
cfg.instantiate();
- cfg->load(new_path + ".import");
+ cfg->load(old_path + ".import");
cfg->erase_section_key("remap", "uid");
- cfg->save(new_path + ".import");
- } else if (p_item.is_file && (old_path.get_extension() == "tscn" || old_path.get_extension() == "tres")) {
- // FIXME: Quick hack to fix text resources. This should be fixed properly.
- Ref<FileAccess> file = FileAccess::open(old_path, FileAccess::READ, &err);
- if (err == OK) {
- PackedStringArray lines = file->get_as_utf8_string().split("\n");
- String line = lines[0];
-
- if (line.contains("uid")) {
- line = line.substr(0, line.find(" uid")) + "]";
- lines.write[0] = line;
+ err = cfg->save(new_path + ".import");
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ".import: " + error_names[err] + "\n");
+ return;
+ }
+ } else {
+ // Files which do not use an uid can just be copied.
+ if (ResourceLoader::get_resource_uid(old_path) == ResourceUID::INVALID_ID) {
+ Error err = da->copy(old_path, new_path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + ": " + error_names[err] + "\n");
+ }
+ return;
+ }
- Ref<FileAccess> file2 = FileAccess::open(new_path, FileAccess::WRITE, &err);
- if (err == OK) {
- file2->store_string(String("\n").join(lines));
- }
+ // Load the resource and save it again in the new location (this generates a new UID).
+ Error err;
+ Ref<Resource> res = ResourceLoader::load(old_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ if (err == OK && res.is_valid()) {
+ err = ResourceSaver::save(res, new_path, ResourceSaver::FLAG_COMPRESS);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to save resource at %s: %s"), new_path, error_names[err]));
}
+ } else if (err != OK) {
+ // When loading files like text files the error is OK but the resource is still null.
+ // We can ignore such files.
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + " " + vformat(TTR("Failed to load resource at %s: %s"), new_path, error_names[err]));
}
}
} else {
- EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:") + "\n" + old_path + "\n");
+ // Recursively duplicate all files inside the folder.
+ Ref<DirAccess> old_dir = DirAccess::open(old_path);
+ Ref<FileAccess> file_access = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+ old_dir->set_include_navigational(false);
+ old_dir->list_dir_begin();
+ for (String f = old_dir->_get_next(); !f.is_empty(); f = old_dir->_get_next()) {
+ if (f.get_extension() == "import") {
+ continue;
+ }
+ if (file_access->file_exists(old_path + f)) {
+ _try_duplicate_item(FileOrFolder(old_path + f, true), new_path + f);
+ } else if (da->dir_exists(old_path + f)) {
+ _try_duplicate_item(FileOrFolder(old_path + f, false), new_path + f);
+ }
+ }
+ old_dir->list_dir_end();
}
}
@@ -1345,25 +1373,25 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str
}
for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) {
- String path;
+ String file_path;
if (i == EditorNode::get_editor_data().get_edited_scene()) {
if (!get_tree()->get_edited_scene_root()) {
continue;
}
- path = get_tree()->get_edited_scene_root()->get_scene_file_path();
+ file_path = get_tree()->get_edited_scene_root()->get_scene_file_path();
} else {
- path = EditorNode::get_editor_data().get_scene_path(i);
+ file_path = EditorNode::get_editor_data().get_scene_path(i);
}
- if (p_renames.has(path)) {
- path = p_renames[path];
+ if (p_renames.has(file_path)) {
+ file_path = p_renames[file_path];
}
if (i == EditorNode::get_editor_data().get_edited_scene()) {
- get_tree()->get_edited_scene_root()->set_scene_file_path(path);
+ get_tree()->get_edited_scene_root()->set_scene_file_path(file_path);
} else {
- EditorNode::get_editor_data().set_scene_path(i, path);
+ EditorNode::get_editor_data().set_scene_path(i, file_path);
}
}
}
@@ -1421,11 +1449,10 @@ void FileSystemDock::_update_project_settings_after_move(const HashMap<String, S
}
void FileSystemDock::_update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const {
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
Vector<String> new_favorites;
- for (int i = 0; i < favorites.size(); i++) {
- String old_path = favorites[i];
+ for (const String &old_path : favorites_list) {
if (p_folders_renames.has(old_path)) {
new_favorites.push_back(p_folders_renames[old_path]);
} else if (p_files_renames.has(old_path)) {
@@ -1836,23 +1863,23 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
case FILE_ADD_FAVORITE: {
// Add the files from favorites.
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
for (int i = 0; i < p_selected.size(); i++) {
- if (!favorites.has(p_selected[i])) {
- favorites.push_back(p_selected[i]);
+ if (!favorites_list.has(p_selected[i])) {
+ favorites_list.push_back(p_selected[i]);
}
}
- EditorSettings::get_singleton()->set_favorites(favorites);
+ EditorSettings::get_singleton()->set_favorites(favorites_list);
_update_tree(_compute_uncollapsed_paths());
} break;
case FILE_REMOVE_FAVORITE: {
// Remove the files from favorites.
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
for (int i = 0; i < p_selected.size(); i++) {
- favorites.erase(p_selected[i]);
+ favorites_list.erase(p_selected[i]);
}
- EditorSettings::get_singleton()->set_favorites(favorites);
+ EditorSettings::get_singleton()->set_favorites(favorites_list);
_update_tree(_compute_uncollapsed_paths());
if (path == "Favorites") {
_update_file_list(true);
@@ -2274,7 +2301,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
int drop_section = tree->get_drop_section_at_position(p_point);
int drop_position;
- Vector<String> files = drag_data["files"];
+ Vector<String> drag_files = drag_data["files"];
TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *resources_item = favorites_item->get_next();
@@ -2295,8 +2322,8 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
// Remove dragged favorites.
Vector<int> to_remove;
int offset = 0;
- for (int i = 0; i < files.size(); i++) {
- int to_remove_pos = dirs.find(files[i]);
+ for (int i = 0; i < drag_files.size(); i++) {
+ int to_remove_pos = dirs.find(drag_files[i]);
to_remove.push_back(to_remove_pos);
if (to_remove_pos < drop_position) {
offset++;
@@ -2309,8 +2336,8 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
// Re-add them at the right position.
- for (int i = 0; i < files.size(); i++) {
- dirs.insert(drop_position, files[i]);
+ for (int i = 0; i < drag_files.size(); i++) {
+ dirs.insert(drop_position, drag_files[i]);
drop_position++;
}
@@ -2379,13 +2406,13 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
} else if (favorite) {
// Add the files from favorites.
Vector<String> fnames = drag_data["files"];
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
for (int i = 0; i < fnames.size(); i++) {
- if (!favorites.has(fnames[i])) {
- favorites.push_back(fnames[i]);
+ if (!favorites_list.has(fnames[i])) {
+ favorites_list.push_back(fnames[i]);
}
}
- EditorSettings::get_singleton()->set_favorites(favorites);
+ EditorSettings::get_singleton()->set_favorites(favorites_list);
_update_tree(_compute_uncollapsed_paths());
}
}
@@ -2463,7 +2490,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
Vector<String> filenames;
Vector<String> foldernames;
- Vector<String> favorites = EditorSettings::get_singleton()->get_favorites();
+ Vector<String> favorites_list = EditorSettings::get_singleton()->get_favorites();
bool all_files = true;
bool all_files_scenes = true;
@@ -2484,8 +2511,8 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
// Check if in favorites.
bool found = false;
- for (int j = 0; j < favorites.size(); j++) {
- if (favorites[j] == fpath) {
+ for (int j = 0; j < favorites_list.size(); j++) {
+ if (favorites_list[j] == fpath) {
found = true;
break;
}
@@ -2502,7 +2529,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (filenames.size() == 1) {
p_popup->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Open Scene"), FILE_OPEN);
p_popup->add_icon_item(get_theme_icon(SNAME("CreateNewSceneFrom"), SNAME("EditorIcons")), TTR("New Inherited Scene"), FILE_INHERIT);
- if (ProjectSettings::get_singleton()->get("application/run/main_scene") != filenames[0]) {
+ if (GLOBAL_GET("application/run/main_scene") != filenames[0]) {
p_popup->add_icon_item(get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")), TTR("Set As Main Scene"), FILE_MAIN_SCENE);
}
} else {
@@ -2852,10 +2879,10 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
}
}
-void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &files) const {
+void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &r_files) const {
if (!p_path.ends_with("/")) {
if (FileAccess::exists(p_path + ".import")) {
- files.push_back(p_path);
+ r_files.push_back(p_path);
}
return;
}
@@ -2866,7 +2893,7 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &f
while (!n.is_empty()) {
if (n != "." && n != ".." && !n.ends_with(".import")) {
String npath = p_path + n + (da->current_is_dir() ? "/" : "");
- _get_imported_files(npath, files);
+ _get_imported_files(npath, r_files);
}
n = da->get_next();
}
@@ -2996,7 +3023,7 @@ void FileSystemDock::_bind_methods() {
ADD_SIGNAL(MethodInfo("file_removed", PropertyInfo(Variant::STRING, "file")));
ADD_SIGNAL(MethodInfo("folder_removed", PropertyInfo(Variant::STRING, "folder")));
ADD_SIGNAL(MethodInfo("files_moved", PropertyInfo(Variant::STRING, "old_file"), PropertyInfo(Variant::STRING, "new_file")));
- ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_file")));
+ ADD_SIGNAL(MethodInfo("folder_moved", PropertyInfo(Variant::STRING, "old_folder"), PropertyInfo(Variant::STRING, "new_folder")));
ADD_SIGNAL(MethodInfo("display_mode_changed"));
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index c38b3f8a47..f39ca9e74d 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -213,11 +213,11 @@ private:
void _file_multi_selected(int p_index, bool p_selected);
void _tree_multi_selected(Object *p_item, int p_column, bool p_selected);
- void _get_imported_files(const String &p_path, Vector<String> &files) const;
+ void _get_imported_files(const String &p_path, Vector<String> &r_files) const;
void _update_import_dock();
- void _get_all_items_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files, Vector<String> &folders) const;
- void _find_remaps(EditorFileSystemDirectory *efsd, const HashMap<String, String> &renames, Vector<String> &to_remaps) const;
+ void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const;
+ void _find_remaps(EditorFileSystemDirectory *p_efsd, const HashMap<String, String> &r_renames, Vector<String> &r_to_remaps) const;
void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, HashMap<String, String> &p_file_renames, HashMap<String, String> &p_folder_renames);
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const HashMap<String, String> &p_renames) const;
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 16c5003fdc..a2bd1223a9 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -464,9 +464,9 @@ void FindInFilesDialog::_notification(int p_what) {
_search_text_line_edit->select_all();
// Extensions might have changed in the meantime, we clean them and instance them again.
for (int i = 0; i < _filters_container->get_child_count(); i++) {
- _filters_container->get_child(i)->queue_delete();
+ _filters_container->get_child(i)->queue_free();
}
- Array exts = ProjectSettings::get_singleton()->get("editor/script/search_in_file_extensions");
+ Array exts = GLOBAL_GET("editor/script/search_in_file_extensions");
for (int i = 0; i < exts.size(); ++i) {
CheckBox *cb = memnew(CheckBox);
cb->set_text(exts[i]);
@@ -968,8 +968,8 @@ void FindInFilesPanel::update_replace_buttons() {
_replace_all_button->set_disabled(disabled);
}
-void FindInFilesPanel::set_progress_visible(bool visible) {
- _progress_bar->set_self_modulate(Color(1, 1, 1, visible ? 1 : 0));
+void FindInFilesPanel::set_progress_visible(bool p_visible) {
+ _progress_bar->set_self_modulate(Color(1, 1, 1, p_visible ? 1 : 0));
}
void FindInFilesPanel::_bind_methods() {
diff --git a/editor/find_in_files.h b/editor/find_in_files.h
index c57a084779..46ba3842af 100644
--- a/editor/find_in_files.h
+++ b/editor/find_in_files.h
@@ -198,7 +198,7 @@ private:
void draw_result_text(Object *item_obj, Rect2 rect);
- void set_progress_visible(bool visible);
+ void set_progress_visible(bool p_visible);
void clear();
FindInFiles *_finder = nullptr;
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index dac86acae4..f11e328087 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -39,6 +39,24 @@
#include "scene/gui/label.h"
#include "scene/resources/packed_scene.h"
+static bool can_edit(Node *p_node, String p_group) {
+ Node *n = p_node;
+ bool can_edit = true;
+ while (n) {
+ Ref<SceneState> ss = (n == EditorNode::get_singleton()->get_edited_scene()) ? n->get_scene_inherited_state() : n->get_scene_instance_state();
+ if (ss.is_valid()) {
+ int path = ss->find_node_by_path(n->get_path_to(p_node));
+ if (path != -1) {
+ if (ss->is_node_in_group(path, p_group)) {
+ can_edit = false;
+ }
+ }
+ }
+ n = n->get_owner();
+ }
+ return can_edit;
+}
+
void GroupDialog::_group_selected() {
nodes_to_add->clear();
add_node_root = nodes_to_add->create_item();
@@ -94,7 +112,7 @@ void GroupDialog::_load_nodes(Node *p_current) {
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(p_current, "Node");
node->set_icon(0, icon);
- if (!_can_edit(p_current, selected_group)) {
+ if (!can_edit(p_current, selected_group)) {
node->set_selectable(0, false);
node->set_custom_color(0, groups->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
}
@@ -105,24 +123,6 @@ void GroupDialog::_load_nodes(Node *p_current) {
}
}
-bool GroupDialog::_can_edit(Node *p_node, String p_group) {
- Node *n = p_node;
- bool can_edit = true;
- while (n) {
- Ref<SceneState> ss = (n == EditorNode::get_singleton()->get_edited_scene()) ? n->get_scene_inherited_state() : n->get_scene_instance_state();
- if (ss.is_valid()) {
- int path = ss->find_node_by_path(n->get_path_to(p_node));
- if (path != -1) {
- if (ss->is_node_in_group(path, p_group)) {
- can_edit = false;
- }
- }
- }
- n = n->get_owner();
- }
- return can_edit;
-}
-
void GroupDialog::_add_pressed() {
TreeItem *selected = nodes_to_add->get_next_selected(nullptr);
@@ -218,19 +218,14 @@ void GroupDialog::_add_group_text_changed(const String &p_new_text) {
}
void GroupDialog::_group_renamed() {
- TreeItem *renamed_group = groups->get_edited();
+ TreeItem *renamed_group = groups->get_selected();
if (!renamed_group) {
return;
}
const String name = renamed_group->get_text(0).strip_edges();
- for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
- if (E != renamed_group && E->get_text(0) == name) {
- renamed_group->set_text(0, selected_group);
- error->set_text(TTR("Group name already exists."));
- error->popup_centered();
- return;
- }
+ if (name == selected_group) {
+ return;
}
if (name.is_empty()) {
@@ -240,6 +235,15 @@ void GroupDialog::_group_renamed() {
return;
}
+ for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
+ if (E != renamed_group && E->get_text(0) == name) {
+ renamed_group->set_text(0, selected_group);
+ error->set_text(TTR("Group name already exists."));
+ error->popup_centered();
+ return;
+ }
+ }
+
renamed_group->set_text(0, name); // Spaces trimmed.
undo_redo->create_action(TTR("Rename Group"));
@@ -248,7 +252,7 @@ void GroupDialog::_group_renamed() {
scene_tree->get_nodes_in_group(selected_group, &nodes);
bool removed_all = true;
for (Node *node : nodes) {
- if (_can_edit(node, selected_group)) {
+ if (can_edit(node, selected_group)) {
undo_redo->add_do_method(node, "remove_from_group", selected_group);
undo_redo->add_undo_method(node, "remove_from_group", name);
undo_redo->add_do_method(node, "add_to_group", name, true);
@@ -324,7 +328,7 @@ void GroupDialog::_modify_group_pressed(Object *p_item, int p_column, int p_id,
scene_tree->get_nodes_in_group(name, &nodes);
bool removed_all = true;
for (Node *E : nodes) {
- if (_can_edit(E, name)) {
+ if (can_edit(E, name)) {
undo_redo->add_do_method(E, "remove_from_group", name);
undo_redo->add_undo_method(E, "add_to_group", name, true);
} else {
@@ -571,7 +575,7 @@ GroupDialog::GroupDialog() {
set_title(TTR("Group Editor"));
- error = memnew(ConfirmationDialog);
+ error = memnew(AcceptDialog);
add_child(error);
error->set_ok_button_text(TTR("Close"));
@@ -584,14 +588,12 @@ void GroupsEditor::_add_group(const String &p_group) {
if (!node) {
return;
}
-
const String name = group_name->get_text().strip_edges();
- if (name.is_empty()) {
- return;
- }
group_name->clear();
if (node->is_in_group(name)) {
+ error->set_text(TTR("Group name already exists."));
+ error->popup_centered();
return;
}
@@ -609,6 +611,65 @@ void GroupsEditor::_add_group(const String &p_group) {
undo_redo->commit_action();
}
+void GroupsEditor::_group_selected() {
+ if (!tree->is_anything_selected()) {
+ return;
+ }
+ selected_group = tree->get_selected()->get_text(0);
+}
+
+void GroupsEditor::_group_renamed() {
+ if (!node || !can_edit(node, selected_group)) {
+ return;
+ }
+
+ TreeItem *ti = tree->get_selected();
+ if (!ti) {
+ return;
+ }
+
+ const String name = ti->get_text(0).strip_edges();
+ if (name == selected_group) {
+ return;
+ }
+
+ if (name.is_empty()) {
+ ti->set_text(0, selected_group);
+ error->set_text(TTR("Invalid group name."));
+ error->popup_centered();
+ return;
+ }
+
+ for (TreeItem *E = groups_root->get_first_child(); E; E = E->get_next()) {
+ if (E != ti && E->get_text(0) == name) {
+ ti->set_text(0, selected_group);
+ error->set_text(TTR("Group name already exists."));
+ error->popup_centered();
+ return;
+ }
+ }
+
+ ti->set_text(0, name); // Spaces trimmed.
+
+ undo_redo->create_action(TTR("Rename Group"));
+
+ undo_redo->add_do_method(node, "remove_from_group", selected_group);
+ undo_redo->add_undo_method(node, "remove_from_group", name);
+ undo_redo->add_do_method(node, "add_to_group", name, true);
+ undo_redo->add_undo_method(node, "add_to_group", selected_group, true);
+
+ undo_redo->add_do_method(this, "_group_selected");
+ undo_redo->add_undo_method(this, "_group_selected");
+ undo_redo->add_do_method(this, "update_tree");
+ undo_redo->add_undo_method(this, "update_tree");
+
+ // To force redraw of scene tree.
+ undo_redo->add_do_method(SceneTreeDock::get_singleton()->get_tree_editor(), "update_tree");
+ undo_redo->add_undo_method(SceneTreeDock::get_singleton()->get_tree_editor(), "update_tree");
+
+ undo_redo->commit_action();
+}
+
void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseButton p_button) {
if (p_button != MouseButton::LEFT) {
return;
@@ -624,7 +685,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu
}
switch (p_id) {
case DELETE_GROUP: {
- String name = ti->get_text(0);
+ const String name = ti->get_text(0);
undo_redo->create_action(TTR("Remove from Group"));
undo_redo->add_do_method(node, "remove_from_group", name);
@@ -666,6 +727,7 @@ void GroupsEditor::update_tree() {
groups.sort_custom<_GroupInfoComparator>();
TreeItem *root = tree->create_item();
+ groups_root = root;
for (const GroupInfo &gi : groups) {
if (!gi.persistent) {
@@ -692,6 +754,7 @@ void GroupsEditor::update_tree() {
TreeItem *item = tree->create_item(root);
item->set_text(0, gi.name);
+ item->set_editable(0, true);
if (can_be_deleted) {
item->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), DELETE_GROUP);
item->add_button(0, get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), COPY_GROUP);
@@ -717,6 +780,7 @@ void GroupsEditor::_show_group_dialog() {
void GroupsEditor::_bind_methods() {
ClassDB::bind_method("update_tree", &GroupsEditor::update_tree);
+ ClassDB::bind_method("_group_selected", &GroupsEditor::_group_selected);
}
GroupsEditor::GroupsEditor() {
@@ -749,13 +813,21 @@ GroupsEditor::GroupsEditor() {
add->connect("pressed", callable_mp(this, &GroupsEditor::_add_group).bind(String()));
tree = memnew(Tree);
+ vbc->add_child(tree);
tree->set_hide_root(true);
+ tree->set_allow_reselect(true);
+ tree->set_allow_rmb_select(true);
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- vbc->add_child(tree);
+ tree->connect("item_selected", callable_mp(this, &GroupsEditor::_group_selected));
tree->connect("button_clicked", callable_mp(this, &GroupsEditor::_modify_group));
+ tree->connect("item_edited", callable_mp(this, &GroupsEditor::_group_renamed));
tree->add_theme_constant_override("draw_guides", 1);
add_theme_constant_override("separation", 3 * EDSCALE);
+ error = memnew(AcceptDialog);
+ add_child(error);
+ error->get_ok_button()->set_text(TTR("Close"));
+
_group_name_changed("");
}
diff --git a/editor/groups_editor.h b/editor/groups_editor.h
index 8bbea4e652..5d012a3501 100644
--- a/editor/groups_editor.h
+++ b/editor/groups_editor.h
@@ -44,7 +44,7 @@ class EditorUndoRedoManager;
class GroupDialog : public AcceptDialog {
GDCLASS(GroupDialog, AcceptDialog);
- ConfirmationDialog *error = nullptr;
+ AcceptDialog *error = nullptr;
SceneTree *scene_tree = nullptr;
TreeItem *groups_root = nullptr;
@@ -88,8 +88,6 @@ class GroupDialog : public AcceptDialog {
void _modify_group_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _delete_group_item(const String &p_name);
- bool _can_edit(Node *p_node, String p_group);
-
void _load_groups(Node *p_current);
void _load_nodes(Node *p_current);
@@ -113,8 +111,10 @@ class GroupsEditor : public VBoxContainer {
GDCLASS(GroupsEditor, VBoxContainer);
Node *node = nullptr;
+ TreeItem *groups_root = nullptr;
GroupDialog *group_dialog = nullptr;
+ AcceptDialog *error = nullptr;
LineEdit *group_name = nullptr;
Button *add = nullptr;
@@ -122,11 +122,16 @@ class GroupsEditor : public VBoxContainer {
Ref<EditorUndoRedoManager> undo_redo;
+ String selected_group;
+
void update_tree();
void _add_group(const String &p_group = "");
void _modify_group(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _group_name_changed(const String &p_new_text);
+ void _group_selected();
+ void _group_renamed();
+
void _show_group_dialog();
protected:
diff --git a/editor/history_dock.cpp b/editor/history_dock.cpp
new file mode 100644
index 0000000000..57088a76cb
--- /dev/null
+++ b/editor/history_dock.cpp
@@ -0,0 +1,251 @@
+/*************************************************************************/
+/* history_dock.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 "history_dock.h"
+
+#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/item_list.h"
+
+struct SortActionsByTimestamp {
+ bool operator()(const EditorUndoRedoManager::Action &l, const EditorUndoRedoManager::Action &r) const {
+ return l.timestamp > r.timestamp;
+ }
+};
+
+void HistoryDock::on_history_changed() {
+ if (is_visible_in_tree()) {
+ refresh_history();
+ } else {
+ need_refresh = true;
+ }
+}
+
+void HistoryDock::refresh_history() {
+ action_list->clear();
+ bool include_scene = current_scene_checkbox->is_pressed();
+ bool include_global = global_history_checkbox->is_pressed();
+
+ if (!include_scene && !include_global) {
+ action_list->add_item(TTR("The Beginning"));
+ return;
+ }
+
+ const EditorUndoRedoManager::History &current_scene_history = ur_manager->get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ const EditorUndoRedoManager::History &global_history = ur_manager->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY);
+
+ Vector<EditorUndoRedoManager::Action> full_history;
+ {
+ int full_size = 0;
+ if (include_scene) {
+ full_size += current_scene_history.redo_stack.size() + current_scene_history.undo_stack.size();
+ }
+ if (include_global) {
+ full_size += global_history.redo_stack.size() + global_history.undo_stack.size();
+ }
+ full_history.resize(full_size);
+ }
+
+ int i = 0;
+ if (include_scene) {
+ for (const EditorUndoRedoManager::Action &E : current_scene_history.redo_stack) {
+ full_history.write[i] = E;
+ i++;
+ }
+ for (const EditorUndoRedoManager::Action &E : current_scene_history.undo_stack) {
+ full_history.write[i] = E;
+ i++;
+ }
+ }
+ if (include_global) {
+ for (const EditorUndoRedoManager::Action &E : global_history.redo_stack) {
+ full_history.write[i] = E;
+ i++;
+ }
+ for (const EditorUndoRedoManager::Action &E : global_history.undo_stack) {
+ full_history.write[i] = E;
+ i++;
+ }
+ }
+
+ full_history.sort_custom<SortActionsByTimestamp>();
+ for (const EditorUndoRedoManager::Action &E : full_history) {
+ action_list->add_item(E.action_name);
+ if (E.history_id == EditorUndoRedoManager::GLOBAL_HISTORY) {
+ action_list->set_item_custom_fg_color(-1, get_theme_color(SNAME("accent_color"), SNAME("Editor")));
+ }
+ }
+
+ action_list->add_item(TTR("The Beginning"));
+ refresh_version();
+}
+
+void HistoryDock::on_version_changed() {
+ if (is_visible_in_tree()) {
+ refresh_version();
+ } else {
+ need_refresh = true;
+ }
+}
+
+void HistoryDock::refresh_version() {
+ int idx = 0;
+ bool include_scene = current_scene_checkbox->is_pressed();
+ bool include_global = global_history_checkbox->is_pressed();
+
+ if (!include_scene && !include_global) {
+ current_version = idx;
+ action_list->set_current(idx);
+ return;
+ }
+
+ const EditorUndoRedoManager::History &current_scene_history = ur_manager->get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ const EditorUndoRedoManager::History &global_history = ur_manager->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY);
+ double newest_undo_timestamp = 0;
+
+ if (include_scene && !current_scene_history.undo_stack.is_empty()) {
+ newest_undo_timestamp = current_scene_history.undo_stack.front()->get().timestamp;
+ }
+
+ if (include_global && !global_history.undo_stack.is_empty()) {
+ double global_undo_timestamp = global_history.undo_stack.front()->get().timestamp;
+ if (global_undo_timestamp > newest_undo_timestamp) {
+ newest_undo_timestamp = global_undo_timestamp;
+ }
+ }
+
+ if (include_scene) {
+ int skip = 0;
+ for (const EditorUndoRedoManager::Action &E : current_scene_history.redo_stack) {
+ if (E.timestamp < newest_undo_timestamp) {
+ skip++;
+ } else {
+ break;
+ }
+ }
+ idx += current_scene_history.redo_stack.size() - skip;
+ }
+
+ if (include_global) {
+ int skip = 0;
+ for (const EditorUndoRedoManager::Action &E : global_history.redo_stack) {
+ if (E.timestamp < newest_undo_timestamp) {
+ skip++;
+ } else {
+ break;
+ }
+ }
+ idx += global_history.redo_stack.size() - skip;
+ }
+
+ current_version = idx;
+ action_list->set_current(idx);
+}
+
+void HistoryDock::seek_history(int p_index) {
+ bool include_scene = current_scene_checkbox->is_pressed();
+ bool include_global = global_history_checkbox->is_pressed();
+
+ if (!include_scene && !include_global) {
+ return;
+ }
+ int current_scene_id = EditorNode::get_editor_data().get_current_edited_scene_history_id();
+
+ while (current_version < p_index) {
+ if (include_scene) {
+ if (include_global) {
+ ur_manager->undo();
+ } else {
+ ur_manager->undo_history(current_scene_id);
+ }
+ } else {
+ ur_manager->undo_history(EditorUndoRedoManager::GLOBAL_HISTORY);
+ }
+ }
+
+ while (current_version > p_index) {
+ if (include_scene) {
+ if (include_global) {
+ ur_manager->redo();
+ } else {
+ ur_manager->redo_history(current_scene_id);
+ }
+ } else {
+ ur_manager->redo_history(EditorUndoRedoManager::GLOBAL_HISTORY);
+ }
+ }
+}
+
+void HistoryDock::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ EditorNode::get_singleton()->connect("scene_changed", callable_mp(this, &HistoryDock::on_history_changed));
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (is_visible_in_tree() && need_refresh) {
+ refresh_history();
+ }
+ } break;
+ }
+}
+
+HistoryDock::HistoryDock() {
+ ur_manager = EditorNode::get_undo_redo();
+ ur_manager->connect("history_changed", callable_mp(this, &HistoryDock::on_history_changed));
+ ur_manager->connect("version_changed", callable_mp(this, &HistoryDock::on_version_changed));
+
+ HBoxContainer *mode_hb = memnew(HBoxContainer);
+ add_child(mode_hb);
+
+ current_scene_checkbox = memnew(CheckBox);
+ mode_hb->add_child(current_scene_checkbox);
+ current_scene_checkbox->set_flat(true);
+ current_scene_checkbox->set_pressed(true);
+ current_scene_checkbox->set_text(TTR("Scene"));
+ current_scene_checkbox->set_h_size_flags(SIZE_EXPAND_FILL);
+ current_scene_checkbox->set_clip_text(true);
+ current_scene_checkbox->connect("toggled", callable_mp(this, &HistoryDock::refresh_history).unbind(1));
+
+ global_history_checkbox = memnew(CheckBox);
+ mode_hb->add_child(global_history_checkbox);
+ global_history_checkbox->set_flat(true);
+ global_history_checkbox->set_pressed(true);
+ global_history_checkbox->set_text(TTR("Global"));
+ global_history_checkbox->set_h_size_flags(SIZE_EXPAND_FILL);
+ global_history_checkbox->set_clip_text(true);
+ global_history_checkbox->connect("toggled", callable_mp(this, &HistoryDock::refresh_history).unbind(1));
+
+ action_list = memnew(ItemList);
+ add_child(action_list);
+ action_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ action_list->connect("item_selected", callable_mp(this, &HistoryDock::seek_history));
+}
diff --git a/editor/history_dock.h b/editor/history_dock.h
new file mode 100644
index 0000000000..9dda8165e6
--- /dev/null
+++ b/editor/history_dock.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* history_dock.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 HISTORY_DOCK_H
+#define HISTORY_DOCK_H
+
+#include "scene/gui/box_container.h"
+
+class CheckBox;
+class ItemList;
+class EditorUndoRedoManager;
+
+class HistoryDock : public VBoxContainer {
+ GDCLASS(HistoryDock, VBoxContainer);
+
+ Ref<EditorUndoRedoManager> ur_manager;
+ ItemList *action_list = nullptr;
+
+ CheckBox *current_scene_checkbox = nullptr;
+ CheckBox *global_history_checkbox = nullptr;
+
+ bool need_refresh = true;
+ int current_version = 0;
+
+ void on_history_changed();
+ void refresh_history();
+ void on_version_changed();
+ void refresh_version();
+
+protected:
+ void _notification(int p_notification);
+
+public:
+ void seek_history(int p_index);
+
+ HistoryDock();
+};
+
+#endif // HISTORY_DOCK_H
diff --git a/editor/icons/BoneMapHumanBody.svg b/editor/icons/BoneMapHumanBody.svg
index 2c2c5db1f6..8674157aaa 100644
--- a/editor/icons/BoneMapHumanBody.svg
+++ b/editor/icons/BoneMapHumanBody.svg
@@ -1 +1,26 @@
-<svg enable-background="new 0 0 1024 1024" height="1024" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h1024v1024h-1024z" fill="#3f3f3f"/><path d="m926.5 217.162c-11.5-2-26.03 4.547-37.5 6.5-15.723 2.678-25.238 3.24-33.333 5.167-1.227.292-3.103.763-5.792.958 0 0-.019.16-.052.437-36.819.994-106.823-6.062-138.156-2.062-23.816 3.041-86.334-5.667-105.667-6-13.911-.239-59.292-4.583-71.75-2.5-.667-4.083-1.5-10.75.95-17.468 14.881-7.246 27.229-21.569 35.341-38.467.922 4.424 6.252 4.929 12.459-14.231 5.662-17.478 2.324-22.254-2.313-22.525.172-2.056.279-4.105.313-6.142.788-48.041-15-78.667-69-78.667s-69.787 30.626-69 78.667c.033 2.036.141 4.086.313 6.142-4.637.271-7.975 5.048-2.313 22.525 6.207 19.16 11.537 18.655 12.459 14.231 8.113 16.897 20.461 31.221 35.342 38.467 2.449 6.718 1.617 13.385.949 17.468-12.457-2.083-57.838 2.261-71.75 2.5-19.332.333-81.85 9.041-105.666 6-31.333-4-101.337 3.056-138.156 2.062-.033-.276-.053-.437-.053-.437-2.689-.195-4.564-.666-5.791-.958-8.096-1.927-17.611-2.489-33.334-5.167-11.469-1.953-26-8.5-37.5-6.5-3.367.586 6 9.834 15.5 12.334 13.635 3.588 25.25 10.666 36 13.166-2.25 3.75-15.59 7.063-23 12-5.336 3.557 6.5 6.5 12 5 20.842-5.684 22.973.389 37.514-9.019 30.078 4.078 102.537 20.514 122.154 14.186 12.457-4.018 100.332 7.083 142.332 5.833 6.039-.18 1.656 65.563 2 73.5 3 69-16.842 133.135-18.666 169.667-1.92 38.42-3.42 57.919 7.666 131.333 6.967 46.126-2.521 82.079-2 94 6 137 29 172 4 221-14 27.44 67.449 26.958 65 9-3.012-22.092-12.666-22.333-10.666-46.333 1.896-22.768 16.049-151.298 8.666-206.667-2-15 0-26 2-66 2.355-47.101 7-88 14-123 7 35 11.645 75.899 14 123 2 40 4 51 2 66-7.383 55.369 6.77 183.899 8.667 206.667 2 24-7.654 24.241-10.667 46.333-2.449 17.958 79 18.44 65-9-25-49-2-84 4-221 .522-11.921-8.966-47.874-2-94 11.086-73.414 9.586-92.913 7.667-131.333-1.824-36.532-21.667-100.667-18.667-169.667.345-7.938-4.039-73.68 2-73.5 42 1.25 129.876-9.852 142.333-5.833 19.616 6.328 92.076-10.107 122.153-14.186 14.541 9.407 16.673 3.335 37.514 9.019 5.5 1.5 17.336-1.443 12-5-7.409-4.937-20.75-8.25-23-12 10.75-2.5 22.366-9.578 36.001-13.166 9.5-2.5 18.866-11.748 15.499-12.334z" fill="#b2b2b2"/></svg>
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="レイヤー_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
+ y="0px" width="1024px" height="1024px" viewBox="0 0 1024 1024" enable-background="new 0 0 1024 1024" xml:space="preserve">
+<path fill="#3F3F3F" d="M0,0h1024v1024H0V0z"/>
+<path fill="#B2B2B2" d="M512,536.162c7,35,11.645,66.898,14,114c2,40,4,51,2,66c-7.384,55.369,6.77,183.898,8.666,206.667
+ c2,24-7.653,24.241-10.666,46.333c-2.449,17.958,79,18.439,65-9c-25-49-2-84,4-221c0.521-11.921-8.967-47.874-2-94
+ c11.086-73.414,8.42-107.242,6.5-145.662c-1.245-31.973-1-56.963-9-138.963c-0.976-10.002,5.915-79.268,11.954-79.088
+ c42,1.25,97.313-5.009,118.145-14.68c28.901,3.73,97.81-12.047,127.887-16.126c14.541,9.407,16.673,3.335,37.515,9.019
+ c5.5,1.5,17.336-1.443,12-5c-7.409-4.937-20.75-8.25-23-12c10.75-2.5,22.365-9.578,36-13.166c9.5-2.5,18.866-11.748,15.5-12.334l0,0
+ c-11.5-2-26.03,4.547-37.5,6.5c-15.724,2.678-25.238,3.24-33.334,5.167c-1.227,0.292-3.103,0.763-5.791,0.958
+ c0,0-0.02,0.16-0.053,0.437c-36.818,0.994-80.322-9.724-130.31-5.569c-34.026-3.925-94.181-5.16-113.513-5.493
+ c-13.911-0.239-59.293-2.583-71.75-0.5c-0.668-4.083-1.5-9.75,0.949-16.468c14.881-7.246,19.188-17.796,27.301-34.694
+ c0.922,4.424,6.252,4.929,12.459-14.231c5.661-17.478,2.323-22.254-2.313-22.525c0.172-2.056,0.279-4.105,0.313-6.142
+ C573.746,76.562,566,42.163,512,42.163s-61.746,34.399-60.959,82.44c0.034,2.037,0.142,4.086,0.313,6.142
+ c-4.637,0.271-7.975,5.047-2.313,22.525c6.207,19.16,11.537,18.655,12.459,14.231c8.112,16.898,12.42,27.448,27.301,34.694
+ c2.449,6.718,1.617,12.385,0.949,16.468c-12.457-2.083-57.839,0.261-71.75,0.5c-19.332,0.333-79.486,1.568-113.513,5.493
+ c-49.987-4.155-93.491,6.563-130.31,5.569c-0.033-0.277-0.053-0.437-0.053-0.437c-2.688-0.195-4.564-0.666-5.791-0.958
+ c-8.096-1.927-17.61-2.489-33.334-5.167c-11.47-1.953-26-8.5-37.5-6.5l0,0c-3.366,0.586,6,9.834,15.5,12.334
+ c13.635,3.588,25.25,10.666,36,13.166c-2.25,3.75-15.591,7.063-23,12c-5.336,3.557,6.5,6.5,12,5
+ c20.842-5.684,22.974,0.388,37.515-9.019c30.077,4.079,98.985,19.857,127.887,16.126c20.832,9.671,76.145,15.93,118.145,14.68
+ c6.039-0.18,12.93,69.085,11.954,79.088c-8,82-7.755,106.99-9,138.963c-1.92,38.419-4.586,72.248,6.5,145.662
+ c6.967,46.126-2.521,82.079-2,94c6,137,29,172,4,221c-14,27.439,67.449,26.958,65,9c-3.013-22.092-12.666-22.333-10.666-46.333
+ c1.896-22.769,16.05-151.298,8.666-206.667c-2-15,0-26,2-66C500.356,603.061,505,571.162,512,536.162z"/>
+</svg>
diff --git a/editor/icons/Line.svg b/editor/icons/Line.svg
new file mode 100644
index 0000000000..c7b1f8a701
--- /dev/null
+++ b/editor/icons/Line.svg
@@ -0,0 +1 @@
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#ffffff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/PickerShapeCircle.svg b/editor/icons/PickerShapeCircle.svg
new file mode 100644
index 0000000000..8e7fb7f06e
--- /dev/null
+++ b/editor/icons/PickerShapeCircle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><rect height="11" rx="5.5" transform="translate(1 2)" width="11"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/editor/icons/PickerShapeRectangle.svg b/editor/icons/PickerShapeRectangle.svg
new file mode 100644
index 0000000000..3c7dd46884
--- /dev/null
+++ b/editor/icons/PickerShapeRectangle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><path d="m0 0h11v11h-11z" transform="translate(1 2)"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/editor/icons/PickerShapeRectangleWheel.svg b/editor/icons/PickerShapeRectangleWheel.svg
new file mode 100644
index 0000000000..e85665a8f2
--- /dev/null
+++ b/editor/icons/PickerShapeRectangleWheel.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ height="16"
+ viewBox="0 0 16 16"
+ width="16"
+ version="1.1"
+ id="svg11"
+ sodipodi:docname="PickerShapeRectangleWheel.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs15" />
+ <sodipodi:namedview
+ id="namedview13"
+ pagecolor="#505050"
+ bordercolor="#ffffff"
+ borderopacity="1"
+ inkscape:pageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="1"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="0.53125"
+ inkscape:cy="5.28125"
+ inkscape:window-width="1920"
+ inkscape:window-height="1001"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg11">
+ <inkscape:grid
+ type="xygrid"
+ id="grid944" />
+ </sodipodi:namedview>
+ <clipPath
+ id="a">
+ <path
+ d="m0 0h16v16h-16z"
+ id="path2" />
+ </clipPath>
+ <g
+ clip-path="url(#a)"
+ fill="#eaeaea"
+ id="g9"
+ transform="matrix(0.85714286,0,0,0.85714286,1.1428571,1.1428571)">
+ <path
+ d="M 7,2 A 5,5 0 1 0 12,7 5.006,5.006 0 0 0 7,2 M 7,0 A 7,7 0 1 1 0,7 7,7 0 0 1 7,0 Z"
+ transform="translate(1,1)"
+ id="path5" />
+ <path
+ d="M 0,0 H 7 V 7 H 0 Z"
+ transform="translate(4.5,4.5)"
+ id="path7" />
+ </g>
+</svg>
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index e3da82a5cb..d94b517003 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -76,7 +76,7 @@ void AudioStreamImportSettings::_notification(int p_what) {
void AudioStreamImportSettings::_draw_preview() {
Rect2 rect = _preview->get_rect();
- Size2 size = rect.size;
+ Size2 rect_size = rect.size;
Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);
float preview_offset = zoom_bar->get_value();
@@ -85,7 +85,7 @@ void AudioStreamImportSettings::_draw_preview() {
Ref<Font> beat_font = get_theme_font(SNAME("main"), SNAME("EditorFonts"));
int main_size = get_theme_font_size(SNAME("main_size"), SNAME("EditorFonts"));
Vector<Vector2> lines;
- lines.resize(size.width * 2);
+ lines.resize(rect_size.width * 2);
Color color_active = get_theme_color(SNAME("contrast_color_2"), SNAME("Editor"));
Color color_inactive = color_active;
color_inactive.a *= 0.5;
@@ -107,9 +107,9 @@ void AudioStreamImportSettings::_draw_preview() {
}
}
- for (int i = 0; i < size.width; i++) {
- float ofs = preview_offset + i * preview_len / size.width;
- float ofs_n = preview_offset + (i + 1) * preview_len / size.width;
+ for (int i = 0; i < rect_size.width; i++) {
+ float ofs = preview_offset + i * preview_len / rect_size.width;
+ float ofs_n = preview_offset + (i + 1) * preview_len / rect_size.width;
float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5;
float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5;
@@ -139,8 +139,8 @@ void AudioStreamImportSettings::_draw_preview() {
int bar_beats = stream->get_bar_beats();
int last_text_end_x = 0;
- for (int i = 0; i < size.width; i++) {
- float ofs = preview_offset + i * preview_len / size.width;
+ for (int i = 0; i < rect_size.width; i++) {
+ float ofs = preview_offset + i * preview_len / rect_size.width;
int beat = int(ofs / beat_size);
if (beat != prev_beat) {
String text = itos(beat);
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index 5d8e453395..c54b10842f 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -848,6 +848,8 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
CurveData &curvedata = state.curve_data_map[p_id];
curvedata.name = p_name;
+ String closed = parser.get_attribute_value_safe("closed").to_lower();
+ curvedata.closed = closed == "true" || closed == "1";
COLLADA_PRINT("curve name: " + p_name);
@@ -2036,11 +2038,7 @@ void Collada::_merge_skeletons(VisualScene *p_vscene, Node *p_node) {
ERR_CONTINUE(!state.scene_map.has(nodeid)); //weird, it should have it...
-#ifdef NO_SAFE_CAST
- NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
-#else
NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
-#endif
ERR_CONTINUE(!nj); //broken collada
ERR_CONTINUE(!nj->owner); //weird, node should have a skeleton owner
@@ -2197,11 +2195,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
String nodeid = ng->skeletons[0];
ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
-#ifdef NO_SAFE_CAST
- NodeJoint *nj = static_cast<NodeJoint *>(state.scene_map[nodeid]);
-#else
NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
-#endif
ERR_FAIL_COND_V(!nj, false);
ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index 1e0f45419f..5585c8edd2 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -949,11 +949,11 @@ void DynamicFontImportSettings::_re_import() {
void DynamicFontImportSettings::open_settings(const String &p_path) {
// Load base font data.
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
+ Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path);
// Load font for preview.
font_preview.instantiate();
- font_preview->set_data(data);
+ font_preview->set_data(font_data);
String font_name = vformat("%s (%s)", font_preview->get_font_name(), font_preview->get_font_style_name());
String sample;
@@ -976,7 +976,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
// Load second copy of font with MSDF disabled for the glyph table and metadata extraction.
font_main.instantiate();
- font_main->set_data(data);
+ font_main->set_data(font_data);
font_main->set_multichannel_signed_distance_field(false);
text_edit->add_theme_font_override("font", font_main);
@@ -1036,7 +1036,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
double embolden = preload_config.has("variation_embolden") ? preload_config["variation_embolden"].operator double() : 0;
int face_index = preload_config.has("variation_face_index") ? preload_config["variation_face_index"].operator int() : 0;
Transform2D transform = preload_config.has("variation_transform") ? preload_config["variation_transform"].operator Transform2D() : Transform2D();
- Vector2i size = preload_config.has("size") ? preload_config["size"].operator Vector2i() : Vector2i(16, 0);
+ Vector2i font_size = preload_config.has("size") ? preload_config["size"].operator Vector2i() : Vector2i(16, 0);
String cfg_name = preload_config.has("name") ? preload_config["name"].operator String() : vformat("Configuration %d", i);
TreeItem *vars_item = vars_list->create_item(vars_list_root);
@@ -1061,8 +1061,8 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
import_variation_data_custom->options = options_variations;
vars_item->set_metadata(0, import_variation_data_custom);
- import_variation_data_custom->set("size", size.x);
- import_variation_data_custom->set("outline_size", size.y);
+ import_variation_data_custom->set("size", font_size.x);
+ import_variation_data_custom->set("outline_size", font_size.y);
import_variation_data_custom->set("variation_opentype", variation);
import_variation_data_custom->set("variation_embolden", embolden);
import_variation_data_custom->set("variation_face_index", face_index);
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 8d44329022..6890a46193 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1090,6 +1090,12 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
c->set_point_tilt(i, tilts->array[i]);
}
}
+ if (cd.closed && pc > 1) {
+ Vector3 pos = c->get_point_position(0);
+ Vector3 in = c->get_point_in(0);
+ Vector3 out = c->get_point_out(0);
+ c->add_point(pos, in, out, -1);
+ }
curve_cache[ng->source] = c;
path->set_curve(c);
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index 5211f003c1..5d684fc5db 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -154,7 +154,7 @@ bool EditorImportPlugin::get_option_visibility(const String &p_path, const Strin
d[E->key] = E->value;
++E;
}
- bool visible;
+ bool visible = false;
if (GDVIRTUAL_CALL(_get_option_visibility, p_path, p_option, d, visible)) {
return visible;
}
@@ -172,7 +172,7 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa
++E;
}
- int err;
+ int err = 0;
if (GDVIRTUAL_CALL(_import, p_source_file, p_save_path, options, platform_variants, gen_files, err)) {
Error ret_err = Error(err);
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index ed83535421..ab15aa4fdc 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -135,7 +135,7 @@ String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const {
}
void ResourceImporterLayeredTexture::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const {
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless (PNG),Lossy (WebP),Video RAM (S3TC/ETC/BPTC),Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0));
@@ -186,9 +186,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons
int mm_d = MAX(1, d >> 1);
for (int i = 0; i < mm_d; i++) {
- Ref<Image> mm;
- mm.instantiate();
- mm->create(mm_w, mm_h, false, p_images[0]->get_format());
+ Ref<Image> mm = Image::create_empty(mm_w, mm_h, false, p_images[0]->get_format());
Vector3 pos;
pos.z = float(i) * float(d) / float(mm_d) + 0.5;
for (int x = 0; x < mm_w; x++) {
@@ -396,12 +394,12 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
texture_import->used_channels = used_channels;
_check_compress_ctex(p_source_file, texture_import);
if (r_metadata) {
- Dictionary metadata;
- metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
+ Dictionary meta;
+ meta["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
if (formats_imported.size()) {
- metadata["imported_formats"] = formats_imported;
+ meta["imported_formats"] = formats_imported;
}
- *r_metadata = metadata;
+ *r_metadata = meta;
}
return OK;
@@ -420,7 +418,7 @@ String ResourceImporterLayeredTexture::get_import_settings_string() const {
int index = 0;
while (compression_formats[index]) {
String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
- bool test = ProjectSettings::get_singleton()->get(setting_path);
+ bool test = GLOBAL_GET(setting_path);
if (test) {
s += String(compression_formats[index]);
}
@@ -432,27 +430,27 @@ String ResourceImporterLayeredTexture::get_import_settings_string() const {
bool ResourceImporterLayeredTexture::are_import_settings_valid(const String &p_path) const {
//will become invalid if formats are missing to import
- Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
+ Dictionary meta = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
- if (!metadata.has("vram_texture")) {
+ if (!meta.has("vram_texture")) {
return false;
}
- bool vram = metadata["vram_texture"];
+ bool vram = meta["vram_texture"];
if (!vram) {
return true; //do not care about non vram
}
Vector<String> formats_imported;
- if (metadata.has("imported_formats")) {
- formats_imported = metadata["imported_formats"];
+ if (meta.has("imported_formats")) {
+ formats_imported = meta["imported_formats"];
}
int index = 0;
bool valid = true;
while (compression_formats[index]) {
String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
- bool test = ProjectSettings::get_singleton()->get(setting_path);
+ bool test = GLOBAL_GET(setting_path);
if (test) {
if (!formats_imported.has(compression_formats[index])) {
valid = false;
@@ -486,7 +484,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
// Must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc).
// Android, GLES 2.x
- bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc");
+ bool can_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_bptc");
if (can_bptc) {
r_texture_import->formats_imported.push_back("bptc"); // BPTC needs to be added anyway.
}
@@ -494,7 +492,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
ERR_FAIL_NULL(r_texture_import->image);
bool is_hdr = (r_texture_import->image->get_format() >= Image::FORMAT_RF && r_texture_import->image->get_format() <= Image::FORMAT_RGBE9995);
bool is_ldr = (r_texture_import->image->get_format() >= Image::FORMAT_L8 && r_texture_import->image->get_format() <= Image::FORMAT_RGB565);
- bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc");
+ bool can_s3tc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc");
ERR_FAIL_NULL(r_texture_import->slices);
// Can compress hdr, but hdr with alpha is not compressible.
if (r_texture_import->hdr_compression == 2) {
@@ -532,7 +530,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
}
}
if (!(r_texture_import->used_channels == Image::USED_CHANNELS_LA || r_texture_import->used_channels == Image::USED_CHANNELS_RGBA)) {
- if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) {
+ if (GLOBAL_GET("rendering/textures/vram_compression/import_etc2")) {
_save_tex(*r_texture_import->slices, r_texture_import->save_path + ".etc2." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_ETC2, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true);
r_texture_import->platform_variants->push_back("etc2");
r_texture_import->formats_imported.push_back("etc2");
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index b5798a5784..8ede88a888 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -953,43 +953,49 @@ Node *ResourceImporterScene::_pre_fix_animations(Node *p_node, Node *p_root, con
if (Object::cast_to<AnimationPlayer>(p_node)) {
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
- Array animation_clips;
- {
- int clip_count = node_settings["clips/amount"];
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ Array animation_slices;
- for (int i = 0; i < clip_count; i++) {
- String name = node_settings["clip_" + itos(i + 1) + "/name"];
- int from_frame = node_settings["clip_" + itos(i + 1) + "/start_frame"];
- int end_frame = node_settings["clip_" + itos(i + 1) + "/end_frame"];
- Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)node_settings["clip_" + itos(i + 1) + "/loop_mode"]);
- bool save_to_file = node_settings["clip_" + itos(i + 1) + "/save_to_file/enabled"];
- bool save_to_path = node_settings["clip_" + itos(i + 1) + "/save_to_file/path"];
- bool save_to_file_keep_custom = node_settings["clip_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
+ if (p_animation_data.has(name)) {
+ Dictionary anim_settings = p_animation_data[name];
+ int slices_count = anim_settings["slices/amount"];
+
+ for (int i = 0; i < slices_count; i++) {
+ String slice_name = anim_settings["slice_" + itos(i + 1) + "/name"];
+ int from_frame = anim_settings["slice_" + itos(i + 1) + "/start_frame"];
+ int end_frame = anim_settings["slice_" + itos(i + 1) + "/end_frame"];
+ Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)anim_settings["slice_" + itos(i + 1) + "/loop_mode"]);
+ bool save_to_file = anim_settings["slice_" + itos(i + 1) + "/save_to_file/enabled"];
+ bool save_to_path = anim_settings["slice_" + itos(i + 1) + "/save_to_file/path"];
+ bool save_to_file_keep_custom = anim_settings["slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
+
+ animation_slices.push_back(slice_name);
+ animation_slices.push_back(from_frame / p_animation_fps);
+ animation_slices.push_back(end_frame / p_animation_fps);
+ animation_slices.push_back(loop_mode);
+ animation_slices.push_back(save_to_file);
+ animation_slices.push_back(save_to_path);
+ animation_slices.push_back(save_to_file_keep_custom);
+ }
+ }
- animation_clips.push_back(name);
- animation_clips.push_back(from_frame / p_animation_fps);
- animation_clips.push_back(end_frame / p_animation_fps);
- animation_clips.push_back(loop_mode);
- animation_clips.push_back(save_to_file);
- animation_clips.push_back(save_to_path);
- animation_clips.push_back(save_to_file_keep_custom);
+ if (animation_slices.size() > 0) {
+ _create_slices(ap, anim, animation_slices, true);
}
}
- if (animation_clips.size()) {
- _create_clips(ap, animation_clips, true);
- } else {
- List<StringName> anims;
- ap->get_animation_list(&anims);
- AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
- AnimationImportTracks(int(node_settings["import_tracks/position"])),
- AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
- AnimationImportTracks(int(node_settings["import_tracks/scale"]))
- };
- if (anims.size() > 1 && (import_tracks_mode[0] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[1] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[2] != ANIMATION_IMPORT_TRACKS_IF_PRESENT)) {
- _optimize_track_usage(ap, import_tracks_mode);
- }
+ AnimationImportTracks import_tracks_mode[TRACK_CHANNEL_MAX] = {
+ AnimationImportTracks(int(node_settings["import_tracks/position"])),
+ AnimationImportTracks(int(node_settings["import_tracks/rotation"])),
+ AnimationImportTracks(int(node_settings["import_tracks/scale"]))
+ };
+
+ if (anims.size() > 1 && (import_tracks_mode[0] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[1] != ANIMATION_IMPORT_TRACKS_IF_PRESENT || import_tracks_mode[2] != ANIMATION_IMPORT_TRACKS_IF_PRESENT)) {
+ _optimize_track_usage(ap, import_tracks_mode);
}
}
@@ -1367,7 +1373,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
}
for (int i = 0; i < post_importer_plugins.size(); i++) {
- post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION, p_root, p_node, anim, node_settings);
+ post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION, p_root, p_node, anim, anim_settings);
}
}
}
@@ -1408,144 +1414,138 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
return anim;
}
-void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all) {
- if (!anim->has_animation("default")) {
- ERR_FAIL_COND_MSG(p_clips.size() > 0, "To create clips, animations must be named \"default\".");
- return;
- }
+void ResourceImporterScene::_create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_slices, bool p_bake_all) {
+ Ref<AnimationLibrary> al = ap->get_animation_library(ap->find_animation_library(anim));
- Ref<Animation> default_anim = anim->get_animation("default");
- Ref<AnimationLibrary> al = anim->get_animation_library(anim->find_animation(default_anim));
-
- for (int i = 0; i < p_clips.size(); i += 7) {
- String name = p_clips[i];
- float from = p_clips[i + 1];
- float to = p_clips[i + 2];
- Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)p_clips[i + 3]);
- bool save_to_file = p_clips[i + 4];
- String save_to_path = p_clips[i + 5];
- bool keep_current = p_clips[i + 6];
+ for (int i = 0; i < p_slices.size(); i += 7) {
+ String name = p_slices[i];
+ float from = p_slices[i + 1];
+ float to = p_slices[i + 2];
+ Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)p_slices[i + 3]);
+ bool save_to_file = p_slices[i + 4];
+ String save_to_path = p_slices[i + 5];
+ bool keep_current = p_slices[i + 6];
if (from >= to) {
continue;
}
Ref<Animation> new_anim = memnew(Animation);
- for (int j = 0; j < default_anim->get_track_count(); j++) {
+ for (int j = 0; j < anim->get_track_count(); j++) {
List<float> keys;
- int kc = default_anim->track_get_key_count(j);
+ int kc = anim->track_get_key_count(j);
int dtrack = -1;
for (int k = 0; k < kc; k++) {
- float kt = default_anim->track_get_key_time(j, k);
+ float kt = anim->track_get_key_time(j, k);
if (kt >= from && kt < to) {
//found a key within range, so create track
if (dtrack == -1) {
- new_anim->add_track(default_anim->track_get_type(j));
+ new_anim->add_track(anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
- new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
+ new_anim->track_set_path(dtrack, anim->track_get_path(j));
if (kt > (from + 0.01) && k > 0) {
- if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
+ if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
- default_anim->position_track_interpolate(j, from, &p);
+ anim->position_track_interpolate(j, from, &p);
new_anim->position_track_insert_key(dtrack, 0, p);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quaternion r;
- default_anim->rotation_track_interpolate(j, from, &r);
+ anim->rotation_track_interpolate(j, from, &r);
new_anim->rotation_track_insert_key(dtrack, 0, r);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->scale_track_interpolate(j, from, &s);
+ anim->scale_track_interpolate(j, from, &s);
new_anim->scale_track_insert_key(dtrack, 0, s);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
- Variant var = default_anim->value_track_interpolate(j, from);
+ } else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ Variant var = anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
float interp;
- default_anim->blend_shape_track_interpolate(j, from, &interp);
+ anim->blend_shape_track_interpolate(j, from, &interp);
new_anim->blend_shape_track_insert_key(dtrack, 0, interp);
}
}
}
- if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
+ if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
- default_anim->position_track_get_key(j, k, &p);
+ anim->position_track_get_key(j, k, &p);
new_anim->position_track_insert_key(dtrack, kt - from, p);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quaternion r;
- default_anim->rotation_track_get_key(j, k, &r);
+ anim->rotation_track_get_key(j, k, &r);
new_anim->rotation_track_insert_key(dtrack, kt - from, r);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->scale_track_get_key(j, k, &s);
+ anim->scale_track_get_key(j, k, &s);
new_anim->scale_track_insert_key(dtrack, kt - from, s);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
- Variant var = default_anim->track_get_key_value(j, k);
+ } else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ Variant var = anim->track_get_key_value(j, k);
new_anim->track_insert_key(dtrack, kt - from, var);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
float interp;
- default_anim->blend_shape_track_get_key(j, k, &interp);
+ anim->blend_shape_track_get_key(j, k, &interp);
new_anim->blend_shape_track_insert_key(dtrack, kt - from, interp);
}
}
if (dtrack != -1 && kt >= to) {
- if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
+ if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
- default_anim->position_track_interpolate(j, to, &p);
+ anim->position_track_interpolate(j, to, &p);
new_anim->position_track_insert_key(dtrack, to - from, p);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quaternion r;
- default_anim->rotation_track_interpolate(j, to, &r);
+ anim->rotation_track_interpolate(j, to, &r);
new_anim->rotation_track_insert_key(dtrack, to - from, r);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->scale_track_interpolate(j, to, &s);
+ anim->scale_track_interpolate(j, to, &s);
new_anim->scale_track_insert_key(dtrack, to - from, s);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
- Variant var = default_anim->value_track_interpolate(j, to);
+ } else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ Variant var = anim->value_track_interpolate(j, to);
new_anim->track_insert_key(dtrack, to - from, var);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
float interp;
- default_anim->blend_shape_track_interpolate(j, to, &interp);
+ anim->blend_shape_track_interpolate(j, to, &interp);
new_anim->blend_shape_track_insert_key(dtrack, to - from, interp);
}
}
}
if (dtrack == -1 && p_bake_all) {
- new_anim->add_track(default_anim->track_get_type(j));
+ new_anim->add_track(anim->track_get_type(j));
dtrack = new_anim->get_track_count() - 1;
- new_anim->track_set_path(dtrack, default_anim->track_get_path(j));
- if (default_anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
+ new_anim->track_set_path(dtrack, anim->track_get_path(j));
+ if (anim->track_get_type(j) == Animation::TYPE_POSITION_3D) {
Vector3 p;
- default_anim->position_track_interpolate(j, from, &p);
+ anim->position_track_interpolate(j, from, &p);
new_anim->position_track_insert_key(dtrack, 0, p);
- default_anim->position_track_interpolate(j, to, &p);
+ anim->position_track_interpolate(j, to, &p);
new_anim->position_track_insert_key(dtrack, to - from, p);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_ROTATION_3D) {
Quaternion r;
- default_anim->rotation_track_interpolate(j, from, &r);
+ anim->rotation_track_interpolate(j, from, &r);
new_anim->rotation_track_insert_key(dtrack, 0, r);
- default_anim->rotation_track_interpolate(j, to, &r);
+ anim->rotation_track_interpolate(j, to, &r);
new_anim->rotation_track_insert_key(dtrack, to - from, r);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_SCALE_3D) {
Vector3 s;
- default_anim->scale_track_interpolate(j, from, &s);
+ anim->scale_track_interpolate(j, from, &s);
new_anim->scale_track_insert_key(dtrack, 0, s);
- default_anim->scale_track_interpolate(j, to, &s);
+ anim->scale_track_interpolate(j, to, &s);
new_anim->scale_track_insert_key(dtrack, to - from, s);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_VALUE) {
- Variant var = default_anim->value_track_interpolate(j, from);
+ } else if (anim->track_get_type(j) == Animation::TYPE_VALUE) {
+ Variant var = anim->value_track_interpolate(j, from);
new_anim->track_insert_key(dtrack, 0, var);
- Variant to_var = default_anim->value_track_interpolate(j, to);
+ Variant to_var = anim->value_track_interpolate(j, to);
new_anim->track_insert_key(dtrack, to - from, to_var);
- } else if (default_anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
+ } else if (anim->track_get_type(j) == Animation::TYPE_BLEND_SHAPE) {
float interp;
- default_anim->blend_shape_track_interpolate(j, from, &interp);
+ anim->blend_shape_track_interpolate(j, from, &interp);
new_anim->blend_shape_track_insert_key(dtrack, 0, interp);
- default_anim->blend_shape_track_interpolate(j, to, &interp);
+ anim->blend_shape_track_interpolate(j, to, &interp);
new_anim->blend_shape_track_insert_key(dtrack, to - from, interp);
}
}
@@ -1562,7 +1562,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
}
}
- al->remove_animation("default"); // Remove default (no longer needed).
+ al->remove_animation(ap->find_animation(anim)); // Remove original animation (no longer needed).
}
void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) {
@@ -1642,6 +1642,17 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
+
+ for (int i = 0; i < 256; i++) {
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
+ }
} break;
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
@@ -1654,17 +1665,6 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/rotation", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/scale", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/amount", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
-
- for (int i = 0; i < 256; i++) {
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Pingpong"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
- }
} break;
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
@@ -1767,6 +1767,13 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
if (p_option == "save_to_file/path" || p_option == "save_to_file/keep_custom_tracks") {
return p_options["save_to_file/enabled"];
}
+ if (p_option.begins_with("slice_")) {
+ int max_slice = p_options["slices/amount"];
+ int slice = p_option.get_slice("_", 1).to_int() - 1;
+ if (slice >= max_slice) {
+ return false;
+ }
+ }
} break;
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
if (p_option.begins_with("optimizer/") && p_option != "optimizer/enabled" && !bool(p_options["optimizer/enabled"])) {
@@ -1775,14 +1782,6 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
if (p_option.begins_with("compression/") && p_option != "compression/enabled" && !bool(p_options["compression/enabled"])) {
return false;
}
-
- if (p_option.begins_with("slice_")) {
- int max_slice = p_options["slices/amount"];
- int slice = p_option.get_slice("_", 1).to_int() - 1;
- if (slice >= max_slice) {
- return false;
- }
- }
} break;
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
const bool use_retarget = p_options["retarget/bone_map"].get_validated_object() != nullptr;
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 386519bc59..5f64330453 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -283,7 +283,7 @@ public:
Node *_post_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps);
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
- void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
+ void _create_slices(AnimationPlayer *ap, Ref<Animation> anim, const Array &p_clips, bool p_bake_all);
void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error);
void _compress_animations(AnimationPlayer *anim, int p_page_size_kb);
@@ -474,7 +474,7 @@ Transform3D ResourceImporterScene::get_collision_shapes_transform(const M &p_opt
}
if (p_options.has(SNAME("primitive/rotation"))) {
- transform.basis.set_euler((p_options[SNAME("primitive/rotation")].operator Vector3() / 180.0) * Math_PI);
+ transform.basis = Basis::from_euler(p_options[SNAME("primitive/rotation")].operator Vector3() * (Math_PI / 180.0));
}
}
return transform;
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index c06756ff0b..54ad840f3d 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -192,7 +192,7 @@ bool ResourceImporterTexture::get_option_visibility(const String &p_path, const
if (compress_mode < COMPRESS_VRAM_COMPRESSED) {
return false;
}
- if (!ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc")) {
+ if (!GLOBAL_GET("rendering/textures/vram_compression/import_bptc")) {
return false;
}
}
@@ -233,7 +233,8 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
- if (p_path.get_extension() == "svg") {
+ // Do path based customization only if a path was passed.
+ if (p_path.is_empty() || p_path.get_extension() == "svg") {
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "svg/scale", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 1.0));
// Editor use only, applies to SVG.
@@ -245,7 +246,7 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) {
switch (p_compress_mode) {
case COMPRESS_LOSSLESS: {
- bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png") ||
+ bool lossless_force_png = GLOBAL_GET("rendering/textures/lossless_compression/force_png") ||
!Image::_webp_mem_loader_func; // WebP module disabled.
bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit
f->store_32(use_webp ? CompressedTexture2D::DATA_FORMAT_WEBP : CompressedTexture2D::DATA_FORMAT_PNG);
@@ -598,8 +599,8 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
const bool is_hdr = (image->get_format() >= Image::FORMAT_RF && image->get_format() <= Image::FORMAT_RGBE9995);
bool is_ldr = (image->get_format() >= Image::FORMAT_L8 && image->get_format() <= Image::FORMAT_RGB565);
- const bool can_bptc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_bptc");
- const bool can_s3tc = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_s3tc");
+ const bool can_bptc = GLOBAL_GET("rendering/textures/vram_compression/import_bptc");
+ const bool can_s3tc = GLOBAL_GET("rendering/textures/vram_compression/import_s3tc");
if (can_bptc) {
// Add to the list anyway.
@@ -644,13 +645,13 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
formats_imported.push_back("s3tc");
}
- if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2")) {
+ if (GLOBAL_GET("rendering/textures/vram_compression/import_etc2")) {
_save_ctex(image, p_save_path + ".etc2.ctex", compress_mode, lossy, Image::COMPRESS_ETC2, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc2");
formats_imported.push_back("etc2");
}
- if (ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc")) {
+ if (GLOBAL_GET("rendering/textures/vram_compression/import_etc")) {
_save_ctex(image, p_save_path + ".etc.ctex", compress_mode, lossy, Image::COMPRESS_ETC, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, true, mipmap_limit, normal_image, roughness_channel);
r_platform_variants->push_back("etc");
formats_imported.push_back("etc");
@@ -669,23 +670,23 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
}
if (r_metadata) {
- Dictionary metadata;
- metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
+ Dictionary meta;
+ meta["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
if (formats_imported.size()) {
- metadata["imported_formats"] = formats_imported;
+ meta["imported_formats"] = formats_imported;
}
if (editor_image.is_valid()) {
- metadata["has_editor_variant"] = true;
+ meta["has_editor_variant"] = true;
if (use_editor_scale) {
- metadata["editor_scale"] = EDSCALE;
+ meta["editor_scale"] = EDSCALE;
}
if (convert_editor_colors) {
- metadata["editor_dark_theme"] = EditorSettings::get_singleton()->is_dark_theme();
+ meta["editor_dark_theme"] = EditorSettings::get_singleton()->is_dark_theme();
}
}
- *r_metadata = metadata;
+ *r_metadata = meta;
}
return OK;
}
@@ -703,7 +704,7 @@ String ResourceImporterTexture::get_import_settings_string() const {
int index = 0;
while (compression_formats[index]) {
String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
- bool test = ProjectSettings::get_singleton()->get(setting_path);
+ bool test = GLOBAL_GET(setting_path);
if (test) {
s += String(compression_formats[index]);
}
@@ -715,36 +716,36 @@ String ResourceImporterTexture::get_import_settings_string() const {
bool ResourceImporterTexture::are_import_settings_valid(const String &p_path) const {
//will become invalid if formats are missing to import
- Dictionary metadata = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
+ Dictionary meta = ResourceFormatImporter::get_singleton()->get_resource_metadata(p_path);
- if (metadata.has("has_editor_variant")) {
- if (metadata.has("editor_scale") && (float)metadata["editor_scale"] != EDSCALE) {
+ if (meta.has("has_editor_variant")) {
+ if (meta.has("editor_scale") && (float)meta["editor_scale"] != EDSCALE) {
return false;
}
- if (metadata.has("editor_dark_theme") && (bool)metadata["editor_dark_theme"] != EditorSettings::get_singleton()->is_dark_theme()) {
+ if (meta.has("editor_dark_theme") && (bool)meta["editor_dark_theme"] != EditorSettings::get_singleton()->is_dark_theme()) {
return false;
}
}
- if (!metadata.has("vram_texture")) {
+ if (!meta.has("vram_texture")) {
return false;
}
- bool vram = metadata["vram_texture"];
+ bool vram = meta["vram_texture"];
if (!vram) {
return true; // Do not care about non-VRAM.
}
Vector<String> formats_imported;
- if (metadata.has("imported_formats")) {
- formats_imported = metadata["imported_formats"];
+ if (meta.has("imported_formats")) {
+ formats_imported = meta["imported_formats"];
}
int index = 0;
bool valid = true;
while (compression_formats[index]) {
String setting_path = "rendering/textures/vram_compression/import_" + String(compression_formats[index]);
- bool test = ProjectSettings::get_singleton()->get(setting_path);
+ bool test = GLOBAL_GET(setting_path);
if (test) {
if (!formats_imported.has(compression_formats[index])) {
valid = false;
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 9171f04f42..bf22a9377e 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -273,9 +273,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
EditorAtlasPacker::chart_pack(charts, atlas_width, atlas_height);
//blit the atlas
- Ref<Image> new_atlas;
- new_atlas.instantiate();
- new_atlas->create(atlas_width, atlas_height, false, Image::FORMAT_RGBA8);
+ Ref<Image> new_atlas = Image::create_empty(atlas_width, atlas_height, false, Image::FORMAT_RGBA8);
for (int i = 0; i < pack_data_files.size(); i++) {
PackData &pack_data = pack_data_files.write[i];
diff --git a/editor/import_defaults_editor.cpp b/editor/import_defaults_editor.cpp
index a70f5225e9..a801a678fc 100644
--- a/editor/import_defaults_editor.cpp
+++ b/editor/import_defaults_editor.cpp
@@ -140,7 +140,7 @@ void ImportDefaultsEditor::_update_importer() {
importer->get_import_options("", &options);
Dictionary d;
if (ProjectSettings::get_singleton()->has_setting("importer_defaults/" + importer->get_importer_name())) {
- d = ProjectSettings::get_singleton()->get("importer_defaults/" + importer->get_importer_name());
+ d = GLOBAL_GET("importer_defaults/" + importer->get_importer_name());
}
for (const ResourceImporter::ImportOption &E : options) {
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 4732268256..e6ba19172f 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -384,7 +384,7 @@ void ImportDock::_preset_selected(int p_idx) {
case ITEM_LOAD_DEFAULT: {
ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("importer_defaults/" + params->importer->get_importer_name()));
- Dictionary d = ProjectSettings::get_singleton()->get("importer_defaults/" + params->importer->get_importer_name());
+ Dictionary d = GLOBAL_GET("importer_defaults/" + params->importer->get_importer_name());
List<Variant> v;
d.get_key_list(&v);
diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp
new file mode 100644
index 0000000000..c577c61db7
--- /dev/null
+++ b/editor/input_event_configuration_dialog.cpp
@@ -0,0 +1,704 @@
+/*************************************************************************/
+/* input_event_configuration_dialog.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 "editor/input_event_configuration_dialog.h"
+#include "core/input/input_map.h"
+#include "editor/editor_scale.h"
+#include "editor/event_listener_line_edit.h"
+#include "scene/gui/check_box.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/tree.h"
+
+// Maps to 2*axis if value is neg, or 2*axis+1 if value is pos.
+static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = {
+ TTRC("Left Stick Left, Joystick 0 Left"),
+ TTRC("Left Stick Right, Joystick 0 Right"),
+ TTRC("Left Stick Up, Joystick 0 Up"),
+ TTRC("Left Stick Down, Joystick 0 Down"),
+ TTRC("Right Stick Left, Joystick 1 Left"),
+ TTRC("Right Stick Right, Joystick 1 Right"),
+ TTRC("Right Stick Up, Joystick 1 Up"),
+ TTRC("Right Stick Down, Joystick 1 Down"),
+ TTRC("Joystick 2 Left"),
+ TTRC("Left Trigger, Sony L2, Xbox LT, Joystick 2 Right"),
+ TTRC("Joystick 2 Up"),
+ TTRC("Right Trigger, Sony R2, Xbox RT, Joystick 2 Down"),
+ TTRC("Joystick 3 Left"),
+ TTRC("Joystick 3 Right"),
+ TTRC("Joystick 3 Up"),
+ TTRC("Joystick 3 Down"),
+ TTRC("Joystick 4 Left"),
+ TTRC("Joystick 4 Right"),
+ TTRC("Joystick 4 Up"),
+ TTRC("Joystick 4 Down"),
+};
+
+String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const {
+ ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent");
+
+ String text = p_event->as_text();
+
+ Ref<InputEventKey> key = p_event;
+ if (key.is_valid() && key->is_command_or_control_autoremap()) {
+#ifdef MACOS_ENABLED
+ text = text.replace("Command", "Command/Ctrl");
+#else
+ text = text.replace("Ctrl", "Command/Ctrl");
+#endif
+ }
+ Ref<InputEventMouse> mouse = p_event;
+ Ref<InputEventJoypadMotion> jp_motion = p_event;
+ Ref<InputEventJoypadButton> jp_button = p_event;
+ if (jp_motion.is_valid()) {
+ // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660.
+ String desc = TTR("Unknown Joypad Axis");
+ if (jp_motion->get_axis() < JoyAxis::MAX) {
+ desc = RTR(_joy_axis_descriptions[2 * (size_t)jp_motion->get_axis() + (jp_motion->get_axis_value() < 0 ? 0 : 1)]);
+ }
+
+ text = vformat("Joypad Axis %s %s (%s)", itos((int64_t)jp_motion->get_axis()), jp_motion->get_axis_value() < 0 ? "-" : "+", desc);
+ }
+ if (p_include_device && (mouse.is_valid() || jp_button.is_valid() || jp_motion.is_valid())) {
+ String device_string = _get_device_string(p_event->get_device());
+ text += vformat(" - %s", device_string);
+ }
+
+ return text;
+}
+
+void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection) {
+ if (p_event.is_valid()) {
+ event = p_event;
+
+ // If the event is changed to something which is not the same as the listener,
+ // clear out the event from the listener text box to avoid confusion.
+ const Ref<InputEvent> listener_event = event_listener->get_event();
+ if (listener_event.is_valid() && !listener_event->is_match(p_event)) {
+ event_listener->clear_event();
+ }
+
+ // Update Label
+ event_as_text->set_text(get_event_text(event, true));
+
+ Ref<InputEventKey> k = p_event;
+ Ref<InputEventMouseButton> mb = p_event;
+ Ref<InputEventJoypadButton> joyb = p_event;
+ Ref<InputEventJoypadMotion> joym = p_event;
+ Ref<InputEventWithModifiers> mod = p_event;
+
+ // Update option values and visibility
+ bool show_mods = false;
+ bool show_device = false;
+ bool show_phys_key = false;
+
+ if (mod.is_valid()) {
+ show_mods = true;
+ mod_checkboxes[MOD_ALT]->set_pressed(mod->is_alt_pressed());
+ mod_checkboxes[MOD_SHIFT]->set_pressed(mod->is_shift_pressed());
+ mod_checkboxes[MOD_CTRL]->set_pressed(mod->is_ctrl_pressed());
+ mod_checkboxes[MOD_META]->set_pressed(mod->is_meta_pressed());
+
+ autoremap_command_or_control_checkbox->set_pressed(mod->is_command_or_control_autoremap());
+ }
+
+ if (k.is_valid()) {
+ show_phys_key = true;
+ physical_key_checkbox->set_pressed(k->get_physical_keycode() != Key::NONE && k->get_keycode() == Key::NONE);
+
+ } else if (joyb.is_valid() || joym.is_valid() || mb.is_valid()) {
+ show_device = true;
+ _set_current_device(event->get_device());
+ }
+
+ mod_container->set_visible(show_mods);
+ device_container->set_visible(show_device);
+ physical_key_checkbox->set_visible(show_phys_key);
+ additional_options_container->show();
+
+ // Update selected item in input list.
+ if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid())) {
+ TreeItem *category = input_list_tree->get_root()->get_first_child();
+ while (category) {
+ TreeItem *input_item = category->get_first_child();
+
+ if (input_item != nullptr) {
+ // input_type should always be > 0, unless the tree structure has been misconfigured.
+ int input_type = input_item->get_parent()->get_meta("__type", 0);
+ if (input_type == 0) {
+ return;
+ }
+
+ // If event type matches input types of this category.
+ if ((k.is_valid() && input_type == INPUT_KEY) || (joyb.is_valid() && input_type == INPUT_JOY_BUTTON) || (joym.is_valid() && input_type == INPUT_JOY_MOTION) || (mb.is_valid() && input_type == INPUT_MOUSE_BUTTON)) {
+ // Loop through all items of this category until one matches.
+ while (input_item) {
+ bool key_match = k.is_valid() && (Variant(k->get_keycode()) == input_item->get_meta("__keycode") || Variant(k->get_physical_keycode()) == input_item->get_meta("__keycode"));
+ bool joyb_match = joyb.is_valid() && Variant(joyb->get_button_index()) == input_item->get_meta("__index");
+ bool joym_match = joym.is_valid() && Variant(joym->get_axis()) == input_item->get_meta("__axis") && joym->get_axis_value() == (float)input_item->get_meta("__value");
+ bool mb_match = mb.is_valid() && Variant(mb->get_button_index()) == input_item->get_meta("__index");
+ if (key_match || joyb_match || joym_match || mb_match) {
+ category->set_collapsed(false);
+ input_item->select(0);
+ input_list_tree->ensure_cursor_is_visible();
+ return;
+ }
+ input_item = input_item->get_next();
+ }
+ }
+ }
+
+ category->set_collapsed(true); // Event not in this category, so collapse;
+ category = category->get_next();
+ }
+ }
+ } else {
+ // Event is not valid, reset dialog
+ event = p_event;
+ event_listener->clear_event();
+ event_as_text->set_text(TTR("No Event Configured"));
+
+ additional_options_container->hide();
+ input_list_tree->deselect_all();
+ _update_input_list();
+ }
+}
+
+void InputEventConfigurationDialog::_on_listen_input_changed(const Ref<InputEvent> &p_event) {
+ // Ignore if invalid, echo or not pressed
+ if (p_event.is_null() || p_event->is_echo() || !p_event->is_pressed()) {
+ return;
+ }
+
+ // Create an editable reference
+ Ref<InputEvent> received_event = p_event;
+ // Check what the type is and if it is allowed.
+ Ref<InputEventKey> k = received_event;
+ Ref<InputEventJoypadButton> joyb = received_event;
+ Ref<InputEventJoypadMotion> joym = received_event;
+ Ref<InputEventMouseButton> mb = received_event;
+
+ int type = 0;
+ if (k.is_valid()) {
+ type = INPUT_KEY;
+ } else if (joyb.is_valid()) {
+ type = INPUT_JOY_BUTTON;
+ } else if (joym.is_valid()) {
+ type = INPUT_JOY_MOTION;
+ } else if (mb.is_valid()) {
+ type = INPUT_MOUSE_BUTTON;
+ }
+
+ if (!(allowed_input_types & type)) {
+ return;
+ }
+
+ if (joym.is_valid()) {
+ float axis_value = joym->get_axis_value();
+ if (ABS(axis_value) < 0.9) {
+ // Ignore motion below 0.9 magnitude to avoid accidental touches
+ return;
+ } else {
+ // Always make the value 1 or -1 for display consistency
+ joym->set_axis_value(SIGN(axis_value));
+ }
+ }
+
+ if (k.is_valid()) {
+ k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway.
+ // Maintain physical keycode option state
+ if (physical_key_checkbox->is_pressed()) {
+ k->set_keycode(Key::NONE);
+ } else {
+ k->set_physical_keycode(Key::NONE);
+ }
+ }
+
+ Ref<InputEventWithModifiers> mod = received_event;
+ if (mod.is_valid()) {
+ mod->set_window_id(0);
+ }
+
+ // Maintain device selection.
+ received_event->set_device(_get_current_device());
+
+ _set_event(received_event);
+}
+
+void InputEventConfigurationDialog::_on_listen_focus_changed() {
+ if (event_listener->has_focus()) {
+ set_close_on_escape(false);
+ } else {
+ set_close_on_escape(true);
+ }
+}
+
+void InputEventConfigurationDialog::_search_term_updated(const String &) {
+ _update_input_list();
+}
+
+void InputEventConfigurationDialog::_update_input_list() {
+ input_list_tree->clear();
+
+ TreeItem *root = input_list_tree->create_item();
+ String search_term = input_list_search->get_text();
+
+ bool collapse = input_list_search->get_text().is_empty();
+
+ if (allowed_input_types & INPUT_KEY) {
+ TreeItem *kb_root = input_list_tree->create_item(root);
+ kb_root->set_text(0, TTR("Keyboard Keys"));
+ kb_root->set_icon(0, icon_cache.keyboard);
+ kb_root->set_collapsed(collapse);
+ kb_root->set_meta("__type", INPUT_KEY);
+
+ for (int i = 0; i < keycode_get_count(); i++) {
+ String name = keycode_get_name_by_index(i);
+
+ if (!search_term.is_empty() && name.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(kb_root);
+ item->set_text(0, name);
+ item->set_meta("__keycode", keycode_get_value_by_index(i));
+ }
+ }
+
+ if (allowed_input_types & INPUT_MOUSE_BUTTON) {
+ TreeItem *mouse_root = input_list_tree->create_item(root);
+ mouse_root->set_text(0, TTR("Mouse Buttons"));
+ mouse_root->set_icon(0, icon_cache.mouse);
+ mouse_root->set_collapsed(collapse);
+ mouse_root->set_meta("__type", INPUT_MOUSE_BUTTON);
+
+ MouseButton mouse_buttons[9] = { MouseButton::LEFT, MouseButton::RIGHT, MouseButton::MIDDLE, MouseButton::WHEEL_UP, MouseButton::WHEEL_DOWN, MouseButton::WHEEL_LEFT, MouseButton::WHEEL_RIGHT, MouseButton::MB_XBUTTON1, MouseButton::MB_XBUTTON2 };
+ for (int i = 0; i < 9; i++) {
+ Ref<InputEventMouseButton> mb;
+ mb.instantiate();
+ mb->set_button_index(mouse_buttons[i]);
+ String desc = get_event_text(mb, false);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(mouse_root);
+ item->set_text(0, desc);
+ item->set_meta("__index", mouse_buttons[i]);
+ }
+ }
+
+ if (allowed_input_types & INPUT_JOY_BUTTON) {
+ TreeItem *joyb_root = input_list_tree->create_item(root);
+ joyb_root->set_text(0, TTR("Joypad Buttons"));
+ joyb_root->set_icon(0, icon_cache.joypad_button);
+ joyb_root->set_collapsed(collapse);
+ joyb_root->set_meta("__type", INPUT_JOY_BUTTON);
+
+ for (int i = 0; i < (int)JoyButton::MAX; i++) {
+ Ref<InputEventJoypadButton> joyb;
+ joyb.instantiate();
+ joyb->set_button_index((JoyButton)i);
+ String desc = get_event_text(joyb, false);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(joyb_root);
+ item->set_text(0, desc);
+ item->set_meta("__index", i);
+ }
+ }
+
+ if (allowed_input_types & INPUT_JOY_MOTION) {
+ TreeItem *joya_root = input_list_tree->create_item(root);
+ joya_root->set_text(0, TTR("Joypad Axes"));
+ joya_root->set_icon(0, icon_cache.joypad_axis);
+ joya_root->set_collapsed(collapse);
+ joya_root->set_meta("__type", INPUT_JOY_MOTION);
+
+ for (int i = 0; i < (int)JoyAxis::MAX * 2; i++) {
+ int axis = i / 2;
+ int direction = (i & 1) ? 1 : -1;
+ Ref<InputEventJoypadMotion> joym;
+ joym.instantiate();
+ joym->set_axis((JoyAxis)axis);
+ joym->set_axis_value(direction);
+ String desc = get_event_text(joym, false);
+
+ if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ continue;
+ }
+
+ TreeItem *item = input_list_tree->create_item(joya_root);
+ item->set_text(0, desc);
+ item->set_meta("__axis", i >> 1);
+ item->set_meta("__value", (i & 1) ? 1 : -1);
+ }
+ }
+}
+
+void InputEventConfigurationDialog::_mod_toggled(bool p_checked, int p_index) {
+ Ref<InputEventWithModifiers> ie = event;
+
+ // Not event with modifiers
+ if (ie.is_null()) {
+ return;
+ }
+
+ if (p_index == 0) {
+ ie->set_alt_pressed(p_checked);
+ } else if (p_index == 1) {
+ ie->set_shift_pressed(p_checked);
+ } else if (p_index == 2) {
+ if (!autoremap_command_or_control_checkbox->is_pressed()) {
+ ie->set_ctrl_pressed(p_checked);
+ }
+ } else if (p_index == 3) {
+ if (!autoremap_command_or_control_checkbox->is_pressed()) {
+ ie->set_meta_pressed(p_checked);
+ }
+ }
+
+ _set_event(ie);
+}
+
+void InputEventConfigurationDialog::_autoremap_command_or_control_toggled(bool p_checked) {
+ Ref<InputEventWithModifiers> ie = event;
+ if (ie.is_valid()) {
+ ie->set_command_or_control_autoremap(p_checked);
+ _set_event(ie);
+ }
+
+ if (p_checked) {
+ mod_checkboxes[MOD_META]->hide();
+ mod_checkboxes[MOD_CTRL]->hide();
+ } else {
+ mod_checkboxes[MOD_META]->show();
+ mod_checkboxes[MOD_CTRL]->show();
+ }
+}
+
+void InputEventConfigurationDialog::_physical_keycode_toggled(bool p_checked) {
+ Ref<InputEventKey> k = event;
+
+ if (k.is_null()) {
+ return;
+ }
+
+ if (p_checked) {
+ k->set_physical_keycode(k->get_keycode());
+ k->set_keycode(Key::NONE);
+ } else {
+ k->set_keycode((Key)k->get_physical_keycode());
+ k->set_physical_keycode(Key::NONE);
+ }
+
+ _set_event(k);
+}
+
+void InputEventConfigurationDialog::_input_list_item_selected() {
+ TreeItem *selected = input_list_tree->get_selected();
+
+ // Invalid tree selection - type only exists on the "category" items, which are not a valid selection.
+ if (selected->has_meta("__type")) {
+ return;
+ }
+
+ InputType input_type = (InputType)(int)selected->get_parent()->get_meta("__type");
+
+ switch (input_type) {
+ case INPUT_KEY: {
+ Key keycode = (Key)(int)selected->get_meta("__keycode");
+ Ref<InputEventKey> k;
+ k.instantiate();
+
+ if (physical_key_checkbox->is_pressed()) {
+ k->set_physical_keycode(keycode);
+ k->set_keycode(Key::NONE);
+ } else {
+ k->set_physical_keycode(Key::NONE);
+ k->set_keycode(keycode);
+ }
+
+ // Maintain modifier state from checkboxes
+ k->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
+ k->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ if (autoremap_command_or_control_checkbox->is_pressed()) {
+ k->set_command_or_control_autoremap(true);
+ } else {
+ k->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
+ }
+
+ _set_event(k, false);
+ } break;
+ case INPUT_MOUSE_BUTTON: {
+ MouseButton idx = (MouseButton)(int)selected->get_meta("__index");
+ Ref<InputEventMouseButton> mb;
+ mb.instantiate();
+ mb->set_button_index(idx);
+ // Maintain modifier state from checkboxes
+ mb->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed());
+ mb->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed());
+ if (autoremap_command_or_control_checkbox->is_pressed()) {
+ mb->set_command_or_control_autoremap(true);
+ } else {
+ mb->set_ctrl_pressed(mod_checkboxes[MOD_CTRL]->is_pressed());
+ mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed());
+ }
+
+ // Maintain selected device
+ mb->set_device(_get_current_device());
+
+ _set_event(mb, false);
+ } break;
+ case INPUT_JOY_BUTTON: {
+ JoyButton idx = (JoyButton)(int)selected->get_meta("__index");
+ Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx);
+
+ // Maintain selected device
+ jb->set_device(_get_current_device());
+
+ _set_event(jb, false);
+ } break;
+ case INPUT_JOY_MOTION: {
+ JoyAxis axis = (JoyAxis)(int)selected->get_meta("__axis");
+ int value = selected->get_meta("__value");
+
+ Ref<InputEventJoypadMotion> jm;
+ jm.instantiate();
+ jm->set_axis(axis);
+ jm->set_axis_value(value);
+
+ // Maintain selected device
+ jm->set_device(_get_current_device());
+
+ _set_event(jm, false);
+ } break;
+ }
+}
+
+void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) {
+ // Subtract 1 as option index 0 corresponds to "All Devices" (value of -1)
+ // and option index 1 corresponds to device 0, etc...
+ event->set_device(p_option_button_index - 1);
+ event_as_text->set_text(get_event_text(event, true));
+}
+
+void InputEventConfigurationDialog::_set_current_device(int p_device) {
+ device_id_option->select(p_device + 1);
+}
+
+int InputEventConfigurationDialog::_get_current_device() const {
+ return device_id_option->get_selected() - 1;
+}
+
+String InputEventConfigurationDialog::_get_device_string(int p_device) const {
+ if (p_device == InputMap::ALL_DEVICES) {
+ return TTR("All Devices");
+ }
+ return TTR("Device") + " " + itos(p_device);
+}
+
+void InputEventConfigurationDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ event_listener->grab_focus();
+ } break;
+
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ input_list_search->set_right_icon(input_list_search->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+
+ physical_key_checkbox->set_icon(get_theme_icon(SNAME("KeyboardPhysical"), SNAME("EditorIcons")));
+
+ icon_cache.keyboard = get_theme_icon(SNAME("Keyboard"), SNAME("EditorIcons"));
+ icon_cache.mouse = get_theme_icon(SNAME("Mouse"), SNAME("EditorIcons"));
+ icon_cache.joypad_button = get_theme_icon(SNAME("JoyButton"), SNAME("EditorIcons"));
+ icon_cache.joypad_axis = get_theme_icon(SNAME("JoyAxis"), SNAME("EditorIcons"));
+
+ _update_input_list();
+ } break;
+ }
+}
+
+void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p_event) {
+ if (p_event.is_valid()) {
+ _set_event(p_event);
+ } else {
+ // Clear Event
+ _set_event(p_event);
+
+ // Clear Checkbox Values
+ for (int i = 0; i < MOD_MAX; i++) {
+ mod_checkboxes[i]->set_pressed(false);
+ }
+
+ // Enable the Physical Key checkbox by default to encourage its use.
+ // Physical Key should be used for most game inputs as it allows keys to work
+ // on non-QWERTY layouts out of the box.
+ // This is especially important for WASD movement layouts.
+ physical_key_checkbox->set_pressed(true);
+
+ autoremap_command_or_control_checkbox->set_pressed(false);
+
+ // Select "All Devices" by default.
+ device_id_option->select(0);
+ }
+
+ popup_centered(Size2(0, 400) * EDSCALE);
+}
+
+Ref<InputEvent> InputEventConfigurationDialog::get_event() const {
+ return event;
+}
+
+void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) {
+ allowed_input_types = p_type_masks;
+}
+
+InputEventConfigurationDialog::InputEventConfigurationDialog() {
+ allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
+
+ set_title(TTR("Event Configuration"));
+ set_min_size(Size2i(550 * EDSCALE, 0)); // Min width
+
+ VBoxContainer *main_vbox = memnew(VBoxContainer);
+ add_child(main_vbox);
+
+ event_as_text = memnew(Label);
+ event_as_text->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
+ event_as_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ event_as_text->add_theme_font_override("font", get_theme_font(SNAME("bold"), SNAME("EditorFonts")));
+ event_as_text->add_theme_font_size_override("font_size", 18 * EDSCALE);
+ main_vbox->add_child(event_as_text);
+
+ event_listener = memnew(EventListenerLineEdit);
+ event_listener->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ event_listener->set_stretch_ratio(0.75);
+ event_listener->connect("event_changed", callable_mp(this, &InputEventConfigurationDialog::_on_listen_input_changed));
+ event_listener->connect("focus_entered", callable_mp(this, &InputEventConfigurationDialog::_on_listen_focus_changed));
+ event_listener->connect("focus_exited", callable_mp(this, &InputEventConfigurationDialog::_on_listen_focus_changed));
+ main_vbox->add_child(event_listener);
+
+ main_vbox->add_child(memnew(HSeparator));
+
+ // List of all input options to manually select from.
+ VBoxContainer *manual_vbox = memnew(VBoxContainer);
+ manual_vbox->set_name(TTR("Manual Selection"));
+ manual_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vbox->add_child(manual_vbox);
+
+ input_list_search = memnew(LineEdit);
+ input_list_search->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ input_list_search->set_placeholder(TTR("Filter Inputs"));
+ input_list_search->set_clear_button_enabled(true);
+ input_list_search->connect("text_changed", callable_mp(this, &InputEventConfigurationDialog::_search_term_updated));
+ manual_vbox->add_child(input_list_search);
+
+ input_list_tree = memnew(Tree);
+ input_list_tree->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); // Min height for tree
+ input_list_tree->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_selected));
+ input_list_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ manual_vbox->add_child(input_list_tree);
+
+ input_list_tree->set_hide_root(true);
+ input_list_tree->set_columns(1);
+
+ _update_input_list();
+
+ // Additional Options
+ additional_options_container = memnew(VBoxContainer);
+ additional_options_container->hide();
+
+ Label *opts_label = memnew(Label);
+ opts_label->set_theme_type_variation("HeaderSmall");
+ opts_label->set_text(TTR("Additional Options"));
+ additional_options_container->add_child(opts_label);
+
+ // Device Selection
+ device_container = memnew(HBoxContainer);
+ device_container->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ Label *device_label = memnew(Label);
+ device_label->set_theme_type_variation("HeaderSmall");
+ device_label->set_text(TTR("Device:"));
+ device_container->add_child(device_label);
+
+ device_id_option = memnew(OptionButton);
+ device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ for (int i = -1; i < 8; i++) {
+ device_id_option->add_item(_get_device_string(i));
+ }
+ device_id_option->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed));
+ _set_current_device(InputMap::ALL_DEVICES);
+ device_container->add_child(device_id_option);
+
+ device_container->hide();
+ additional_options_container->add_child(device_container);
+
+ // Modifier Selection
+ mod_container = memnew(HBoxContainer);
+ for (int i = 0; i < MOD_MAX; i++) {
+ String name = mods[i];
+ mod_checkboxes[i] = memnew(CheckBox);
+ mod_checkboxes[i]->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_mod_toggled).bind(i));
+ mod_checkboxes[i]->set_text(name);
+ mod_checkboxes[i]->set_tooltip_text(TTR(mods_tip[i]));
+ mod_container->add_child(mod_checkboxes[i]);
+ }
+
+ mod_container->add_child(memnew(VSeparator));
+
+ autoremap_command_or_control_checkbox = memnew(CheckBox);
+ autoremap_command_or_control_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_autoremap_command_or_control_toggled));
+ autoremap_command_or_control_checkbox->set_pressed(false);
+ autoremap_command_or_control_checkbox->set_text(TTR("Command / Control (auto)"));
+ autoremap_command_or_control_checkbox->set_tooltip_text(TTR("Automatically remaps between 'Meta' ('Command') and 'Control' depending on current platform."));
+ mod_container->add_child(autoremap_command_or_control_checkbox);
+
+ mod_container->hide();
+ additional_options_container->add_child(mod_container);
+
+ // Physical Key Checkbox
+
+ physical_key_checkbox = memnew(CheckBox);
+ physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
+ physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
+ physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
+ physical_key_checkbox->hide();
+ additional_options_container->add_child(physical_key_checkbox);
+
+ main_vbox->add_child(additional_options_container);
+}
diff --git a/editor/input_event_configuration_dialog.h b/editor/input_event_configuration_dialog.h
new file mode 100644
index 0000000000..fc590cba26
--- /dev/null
+++ b/editor/input_event_configuration_dialog.h
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* input_event_configuration_dialog.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 INPUT_EVENT_CONFIGURATION_DIALOG_H
+#define INPUT_EVENT_CONFIGURATION_DIALOG_H
+
+#include "scene/gui/dialogs.h"
+
+class OptionButton;
+class Tree;
+class EventListenerLineEdit;
+class CheckBox;
+
+// Confirmation Dialog used when configuring an input event.
+// Separate from ActionMapEditor for code cleanliness and separation of responsibilities.
+class InputEventConfigurationDialog : public ConfirmationDialog {
+ GDCLASS(InputEventConfigurationDialog, ConfirmationDialog)
+private:
+ struct IconCache {
+ Ref<Texture2D> keyboard;
+ Ref<Texture2D> mouse;
+ Ref<Texture2D> joypad_button;
+ Ref<Texture2D> joypad_axis;
+ } icon_cache;
+
+ Ref<InputEvent> event = Ref<InputEvent>();
+
+ // Listening for input
+ EventListenerLineEdit *event_listener = nullptr;
+ Label *event_as_text = nullptr;
+
+ // List of All Key/Mouse/Joypad input options.
+ int allowed_input_types;
+ Tree *input_list_tree = nullptr;
+ LineEdit *input_list_search = nullptr;
+
+ // Additional Options, shown depending on event selected
+ VBoxContainer *additional_options_container = nullptr;
+
+ HBoxContainer *device_container = nullptr;
+ OptionButton *device_id_option = nullptr;
+
+ HBoxContainer *mod_container = nullptr; // Contains the subcontainer and the store command checkbox.
+
+ enum ModCheckbox {
+ MOD_ALT,
+ MOD_SHIFT,
+ MOD_CTRL,
+ MOD_META,
+ MOD_MAX
+ };
+#if defined(MACOS_ENABLED)
+ String mods[MOD_MAX] = { "Option", "Shift", "Ctrl", "Command" };
+#elif defined(WINDOWS_ENABLED)
+ String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Windows" };
+#else
+ String mods[MOD_MAX] = { "Alt", "Shift", "Ctrl", "Meta" };
+#endif
+ String mods_tip[MOD_MAX] = { "Alt or Option key", "Shift key", "Control key", "Meta/Windows or Command key" };
+
+ CheckBox *mod_checkboxes[MOD_MAX];
+ CheckBox *autoremap_command_or_control_checkbox = nullptr;
+
+ CheckBox *physical_key_checkbox = nullptr;
+
+ void _set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection = true);
+ void _on_listen_input_changed(const Ref<InputEvent> &p_event);
+ void _on_listen_focus_changed();
+
+ void _search_term_updated(const String &p_term);
+ void _update_input_list();
+ void _input_list_item_selected();
+
+ void _mod_toggled(bool p_checked, int p_index);
+ void _autoremap_command_or_control_toggled(bool p_checked);
+ void _physical_keycode_toggled(bool p_checked);
+
+ void _device_selection_changed(int p_option_button_index);
+ void _set_current_device(int p_device);
+ int _get_current_device() const;
+ String _get_device_string(int p_device) const;
+
+protected:
+ void _notification(int p_what);
+
+public:
+ // Pass an existing event to configure it. Alternatively, pass no event to start with a blank configuration.
+ void popup_and_configure(const Ref<InputEvent> &p_event = Ref<InputEvent>());
+ Ref<InputEvent> get_event() const;
+ String get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const;
+
+ void set_allowed_input_types(int p_type_masks);
+
+ InputEventConfigurationDialog();
+};
+
+#endif // INPUT_EVENT_CONFIGURATION_DIALOG_H
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 74fdbdebd7..27b261f320 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -227,7 +227,7 @@ void InspectorDock::_load_resource(const String &p_type) {
load_resource_dialog->add_filter("*." + extensions[i], extensions[i].to_upper());
}
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (int i = 0; i < textfile_ext.size(); i++) {
load_resource_dialog->add_filter("*." + textfile_ext[i], textfile_ext[i].to_upper());
}
@@ -240,7 +240,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
if (ResourceLoader::exists(p_file, "")) {
res = ResourceLoader::load(p_file);
} else {
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
if (textfile_ext.has(p_file.get_extension())) {
res = ScriptEditor::get_singleton()->open_file(p_file);
}
@@ -255,8 +255,8 @@ void InspectorDock::_resource_file_selected(String p_file) {
}
void InspectorDock::_save_resource(bool save_as) {
- ObjectID current = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
+ ObjectID current_id = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
+ Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -270,8 +270,8 @@ void InspectorDock::_save_resource(bool save_as) {
}
void InspectorDock::_unref_resource() {
- ObjectID current = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
+ ObjectID current_id = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
+ Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -281,8 +281,8 @@ void InspectorDock::_unref_resource() {
}
void InspectorDock::_copy_resource() {
- ObjectID current = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
- Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
+ ObjectID current_id = EditorNode::get_singleton()->get_editor_selection_history()->get_current();
+ Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj));
@@ -610,8 +610,8 @@ void InspectorDock::apply_script_properties(Object *p_object) {
}
for (const Pair<StringName, Variant> &E : stored_properties) {
- Variant current;
- if (si->get(E.first, current) && current.get_type() == E.second.get_type()) {
+ Variant current_prop;
+ if (si->get(E.first, current_prop) && current_prop.get_type() == E.second.get_type()) {
si->set(E.first, E.second);
}
}
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 683481ecc1..7727ff31e4 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -73,7 +73,7 @@ void LocalizationEditor::add_translation(const String &p_translation) {
}
void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
- PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ PackedStringArray translations = GLOBAL_GET("internationalization/locale/translations");
for (int i = 0; i < p_paths.size(); i++) {
if (!translations.has(p_paths[i])) {
// Don't add duplicate translation paths.
@@ -83,7 +83,7 @@ void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
undo_redo->create_action(vformat(TTR("Add %d Translations"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", ProjectSettings::get_singleton()->get("internationalization/locale/translations"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -105,7 +105,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
int idx = ti->get_metadata(0);
- PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ PackedStringArray translations = GLOBAL_GET("internationalization/locale/translations");
ERR_FAIL_INDEX(idx, translations.size());
@@ -113,7 +113,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
undo_redo->create_action(TTR("Remove Translation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", ProjectSettings::get_singleton()->get("internationalization/locale/translations"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -130,7 +130,7 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths)
Dictionary remaps;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
- remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
prev = remaps;
}
@@ -158,7 +158,7 @@ void LocalizationEditor::_translation_res_option_file_open() {
void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_paths) {
ERR_FAIL_COND(!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps"));
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -174,7 +174,7 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Remap(s)"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -216,7 +216,7 @@ void LocalizationEditor::_translation_res_option_changed() {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -236,7 +236,7 @@ void LocalizationEditor::_translation_res_option_changed() {
updating_translations = true;
undo_redo->create_action(TTR("Change Resource Remap Language"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -258,7 +258,7 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = Object::cast_to<TreeItem>(p_item);
@@ -269,7 +269,7 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
undo_redo->create_action(TTR("Remove Resource Remap"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -290,7 +290,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
ERR_FAIL_COND(!k);
@@ -308,7 +308,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
undo_redo->create_action(TTR("Remove Resource Remap Option"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -317,7 +317,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
}
void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
+ PackedStringArray pot_translations = GLOBAL_GET("internationalization/locale/translations_pot_files");
for (int i = 0; i < p_paths.size(); i++) {
if (!pot_translations.has(p_paths[i])) {
pot_translations.push_back(p_paths[i]);
@@ -326,7 +326,7 @@ void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
undo_redo->create_action(vformat(TTR("Add %d file(s) for POT generation"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -344,7 +344,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button,
int idx = ti->get_metadata(0);
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
+ PackedStringArray pot_translations = GLOBAL_GET("internationalization/locale/translations_pot_files");
ERR_FAIL_INDEX(idx, pot_translations.size());
@@ -352,7 +352,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button,
undo_redo->create_action(TTR("Remove file from POT generation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files"));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files"));
undo_redo->add_do_method(this, "update_translations");
undo_redo->add_undo_method(this, "update_translations");
undo_redo->add_do_method(this, "emit_signal", localization_changed);
@@ -392,7 +392,7 @@ void LocalizationEditor::_filesystem_files_moved(const String &p_old_file, const
bool remaps_changed = false;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
- remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
}
// Check for the keys.
@@ -442,7 +442,7 @@ void LocalizationEditor::_filesystem_file_removed(const String &p_file) {
Dictionary remaps;
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
- remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
}
bool remaps_changed = remaps.has(p_file);
@@ -481,7 +481,7 @@ void LocalizationEditor::update_translations() {
TreeItem *root = translation_list->create_item(nullptr);
translation_list->set_hide_root(true);
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translations")) {
- PackedStringArray translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ PackedStringArray translations = GLOBAL_GET("internationalization/locale/translations");
for (int i = 0; i < translations.size(); i++) {
TreeItem *t = translation_list->create_item(root);
t->set_editable(0, false);
@@ -507,7 +507,7 @@ void LocalizationEditor::update_translations() {
translation_res_option_add_button->set_disabled(true);
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> rk;
remaps.get_key_list(&rk);
Vector<String> keys;
@@ -568,7 +568,7 @@ void LocalizationEditor::update_translations() {
root = translation_pot_list->create_item(nullptr);
translation_pot_list->set_hide_root(true);
if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translations_pot_files")) {
- PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
+ PackedStringArray pot_translations = GLOBAL_GET("internationalization/locale/translations_pot_files");
for (int i = 0; i < pot_translations.size(); i++) {
TreeItem *t = translation_pot_list->create_item(root);
t->set_editable(0, false);
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 71ff77e9bc..a7ebf21cd2 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -80,11 +80,11 @@ void PluginConfigDialog::_on_confirmed() {
if (!templates.is_empty()) {
template_content = templates[0].content;
}
- Ref<Script> script = ScriptServer::get_language(lang_idx)->make_template(template_content, class_name, "EditorPlugin");
- script->set_path(script_path, true);
- ResourceSaver::save(script);
+ Ref<Script> scr = ScriptServer::get_language(lang_idx)->make_template(template_content, class_name, "EditorPlugin");
+ scr->set_path(script_path, true);
+ ResourceSaver::save(scr);
- emit_signal(SNAME("plugin_ready"), script.ptr(), active_edit->is_pressed() ? _to_absolute_plugin_path(_get_subfolder()) : "");
+ emit_signal(SNAME("plugin_ready"), scr.ptr(), active_edit->is_pressed() ? _to_absolute_plugin_path(_get_subfolder()) : "");
} else {
EditorNode::get_singleton()->get_project_settings()->update_plugins();
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index c928b95642..cb07d8cf01 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -561,8 +561,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl
const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
const Vector2 point = xform.xform(p);
- const Color modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1);
- p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, modulate);
+ const Color overlay_modulate = vertex == active_point ? Color(0.5, 1, 2) : Color(1, 1, 1);
+ p_overlay->draw_texture(handle, point - handle->get_size() * 0.5, overlay_modulate);
if (vertex == hover_point) {
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 0e941ad433..f16a6bfa88 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -381,6 +381,8 @@ void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));
}
}
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index f75dcdf2d6..6f206ff445 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -315,6 +315,8 @@ void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));
}
}
@@ -406,11 +408,11 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) {
making_triangle.clear();
if (p_tool == 2) {
- Vector<Vector2> points;
+ Vector<Vector2> bl_points;
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
- points.push_back(blend_space->get_blend_point_position(i));
+ bl_points.push_back(blend_space->get_blend_point_position(i));
}
- Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(points);
+ Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(bl_points);
for (int i = 0; i < tr.size(); i++) {
blend_space->add_triangle(tr[i].points[0], tr[i].points[1], tr[i].points[2]);
}
@@ -494,8 +496,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
//triangles first
for (int i = 0; i < blend_space->get_triangle_count(); i++) {
- Vector<Vector2> points;
- points.resize(3);
+ Vector<Vector2> bl_points;
+ bl_points.resize(3);
for (int j = 0; j < 3; j++) {
int point_idx = blend_space->get_triangle_point(i, j);
@@ -509,11 +511,11 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s;
point.y = s.height - point.y;
- points.write[j] = point;
+ bl_points.write[j] = point;
}
for (int j = 0; j < 3; j++) {
- blend_space_draw->draw_line(points[j], points[(j + 1) % 3], linecolor, Math::round(EDSCALE), true);
+ blend_space_draw->draw_line(bl_points[j], bl_points[(j + 1) % 3], linecolor, Math::round(EDSCALE), true);
}
Color color;
@@ -530,7 +532,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
color,
color
};
- blend_space_draw->draw_primitive(points, colors, Vector<Vector2>());
+ blend_space_draw->draw_primitive(bl_points, colors, Vector<Vector2>());
}
points.clear();
@@ -560,19 +562,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
}
if (making_triangle.size()) {
- Vector<Vector2> points;
+ Vector<Vector2> bl_points;
for (int i = 0; i < making_triangle.size(); i++) {
Vector2 point = blend_space->get_blend_point_position(making_triangle[i]);
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
point *= s;
point.y = s.height - point.y;
- points.push_back(point);
+ bl_points.push_back(point);
}
- for (int i = 0; i < points.size() - 1; i++) {
- blend_space_draw->draw_line(points[i], points[i + 1], linecolor, Math::round(2 * EDSCALE), true);
+ for (int i = 0; i < bl_points.size() - 1; i++) {
+ blend_space_draw->draw_line(bl_points[i], bl_points[i + 1], linecolor, Math::round(2 * EDSCALE), true);
}
- blend_space_draw->draw_line(points[points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, Math::round(2 * EDSCALE), true);
+ blend_space_draw->draw_line(bl_points[bl_points.size() - 1], blend_space_draw->get_local_mouse_position(), linecolor, Math::round(2 * EDSCALE), true);
}
///draw cursor position
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index ca7b2d0015..6d00e77a4b 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -153,7 +153,8 @@ void AnimationNodeBlendTreeEditor::update_graph() {
node->add_child(name);
node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED);
- name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED);
+ name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(agnode), CONNECT_DEFERRED);
+ name->connect("text_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_rename_lineedit_changed), CONNECT_DEFERRED);
base = 1;
node->set_show_close_button(true);
node->connect("close_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_request).bind(E), CONNECT_DEFERRED);
@@ -262,10 +263,10 @@ void AnimationNodeBlendTreeEditor::update_graph() {
node->add_theme_color_override("resizer_color", c);
}
- List<AnimationNodeBlendTree::NodeConnection> connections;
- blend_tree->get_node_connections(&connections);
+ List<AnimationNodeBlendTree::NodeConnection> node_connections;
+ blend_tree->get_node_connections(&node_connections);
- for (const AnimationNodeBlendTree::NodeConnection &E : connections) {
+ for (const AnimationNodeBlendTree::NodeConnection &E : node_connections) {
StringName from = E.output_node;
StringName to = E.input_node;
int to_idx = E.input_index;
@@ -273,9 +274,9 @@ void AnimationNodeBlendTreeEditor::update_graph() {
graph->connect_node(from, 0, to, to_idx);
}
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
graph->set_connection_lines_curvature(graph_lines_curvature);
}
@@ -283,6 +284,8 @@ void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_node(MENU_LOAD_FILE_CONFIRM);
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));
}
}
@@ -293,9 +296,9 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
if (p_idx == MENU_LOAD_FILE) {
open_file->clear_filters();
- List<String> filters;
- ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &filters);
- for (const String &E : filters) {
+ List<String> ext_filters;
+ ResourceLoader::get_recognized_extensions_for_type("AnimationNode", &ext_filters);
+ for (const String &E : ext_filters) {
open_file->add_filter("*." + E);
}
open_file->popup_file_dialog();
@@ -611,10 +614,10 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
HashSet<String> paths;
HashMap<String, RBSet<String>> types;
{
- List<StringName> animations;
- player->get_animation_list(&animations);
+ List<StringName> animation_list;
+ player->get_animation_list(&animation_list);
- for (const StringName &E : animations) {
+ for (const StringName &E : animation_list) {
Ref<Animation> anim = player->get_animation(E);
for (int i = 0; i < anim->get_track_count(); i++) {
String track_path = anim->track_get_path(i);
@@ -795,8 +798,8 @@ void AnimationNodeBlendTreeEditor::_removed_from_graph() {
}
void AnimationNodeBlendTreeEditor::_update_editor_settings() {
- graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
}
void AnimationNodeBlendTreeEditor::_update_theme() {
@@ -970,10 +973,10 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
//recreate connections
graph->clear_connections();
- List<AnimationNodeBlendTree::NodeConnection> connections;
- blend_tree->get_node_connections(&connections);
+ List<AnimationNodeBlendTree::NodeConnection> node_connections;
+ blend_tree->get_node_connections(&node_connections);
- for (const AnimationNodeBlendTree::NodeConnection &E : connections) {
+ for (const AnimationNodeBlendTree::NodeConnection &E : node_connections) {
StringName from = E.output_node;
StringName to = E.input_node;
int to_idx = E.input_index;
@@ -991,13 +994,18 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
}
update_graph(); // Needed to update the signal connections with the new name.
+ current_node_rename_text = String();
}
-void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
- if (le == nullptr) {
+void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Ref<AnimationNode> p_node) {
+ if (current_node_rename_text.is_empty()) {
return; // The text_submitted signal triggered the graph update and freed the LineEdit.
}
- _node_renamed(le->call("get_text"), p_node);
+ _node_renamed(current_node_rename_text, p_node);
+}
+
+void AnimationNodeBlendTreeEditor::_node_rename_lineedit_changed(const String &p_text) {
+ current_node_rename_text = p_text;
}
bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
@@ -1048,9 +1056,9 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("popup_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_request));
graph->connect("connection_to_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_to_empty));
graph->connect("connection_from_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_from_empty));
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
graph->set_connection_lines_curvature(graph_lines_curvature);
VSeparator *vs = memnew(VSeparator);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 46e0d18c69..b55fc3b617 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -92,9 +92,11 @@ 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_renamed_focus_out(Ref<AnimationNode> p_node);
+ void _node_rename_lineedit_changed(const String &p_text);
void _node_changed(const StringName &p_node_name);
+ String current_node_rename_text;
bool updating;
void _connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index e8caac565c..b4737976d8 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -128,14 +128,11 @@ void AnimationPlayerEditor::_notification(int p_what) {
{
Ref<Image> autoplay_img = autoplay_icon->get_image();
Ref<Image> reset_img = reset_icon->get_image();
- Ref<Image> autoplay_reset_img;
Size2 icon_size = autoplay_img->get_size();
- autoplay_reset_img.instantiate();
- autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format());
+ Ref<Image> autoplay_reset_img = Image::create_empty(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format());
autoplay_reset_img->blit_rect(autoplay_img, Rect2i(Point2i(), icon_size), Point2i());
autoplay_reset_img->blit_rect(reset_img, Rect2i(Point2i(), icon_size), Point2i(icon_size.x, 0));
- autoplay_reset_icon.instantiate();
- autoplay_reset_icon->set_image(autoplay_reset_img);
+ autoplay_reset_icon = ImageTexture::create_from_image(autoplay_reset_img);
}
stop->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
@@ -302,6 +299,8 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
_animation_key_editor_seek(timeline_position, false);
+
+ emit_signal("animation_selected", current);
}
void AnimationPlayerEditor::_animation_new() {
@@ -720,7 +719,18 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
if (p_state.has("player")) {
Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]);
if (Object::cast_to<AnimationPlayer>(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
+ if (player) {
+ if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
+ }
player = Object::cast_to<AnimationPlayer>(n);
+ if (player) {
+ if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
+ }
+
_update_player();
EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
set_process(true);
@@ -826,13 +836,13 @@ void AnimationPlayerEditor::_update_player() {
}
// Check if the global library is foreign since we want to disable options for adding/remove/renaming animations if it is.
- Ref<AnimationLibrary> library = player->get_animation_library(K);
+ Ref<AnimationLibrary> anim_library = player->get_animation_library(K);
if (K == "") {
- foreign_global_anim_lib = EditorNode::get_singleton()->is_resource_read_only(library);
+ foreign_global_anim_lib = EditorNode::get_singleton()->is_resource_read_only(anim_library);
}
List<StringName> animlist;
- library->get_animation_list(&animlist);
+ anim_library->get_animation_list(&animlist);
for (const StringName &E : animlist) {
String path = K;
@@ -913,19 +923,19 @@ void AnimationPlayerEditor::_update_player() {
void AnimationPlayerEditor::_update_animation_list_icons() {
for (int i = 0; i < animation->get_item_count(); i++) {
- String name = animation->get_item_text(i);
+ String anim_name = animation->get_item_text(i);
if (animation->is_item_disabled(i) || animation->is_item_separator(i)) {
continue;
}
Ref<Texture2D> icon;
- if (name == player->get_autoplay()) {
- if (name == SceneStringNames::get_singleton()->RESET) {
+ if (anim_name == player->get_autoplay()) {
+ if (anim_name == SceneStringNames::get_singleton()->RESET) {
icon = autoplay_reset_icon;
} else {
icon = autoplay_icon;
}
- } else if (name == SceneStringNames::get_singleton()->RESET) {
+ } else if (anim_name == SceneStringNames::get_singleton()->RESET) {
icon = reset_icon;
}
@@ -982,9 +992,18 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
if (player && pin->is_pressed()) {
return; // Ignore, pinned.
}
+
+ if (player) {
+ if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
+ }
player = p_player;
if (player) {
+ if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
_update_player();
if (onion.enabled) {
@@ -1151,6 +1170,10 @@ void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
}
}
+void AnimationPlayerEditor::_animation_libraries_updated() {
+ _animation_player_changed(player);
+}
+
void AnimationPlayerEditor::_list_changed() {
if (is_visible_in_tree()) {
_update_player();
@@ -1356,8 +1379,8 @@ void AnimationPlayerEditor::_free_onion_layers() {
void AnimationPlayerEditor::_prepare_onion_layers_1() {
// This would be called per viewport and we want to act once only.
- int64_t frame = get_tree()->get_frame();
- if (frame == onion.last_frame) {
+ int64_t cur_frame = get_tree()->get_frame();
+ if (cur_frame == onion.last_frame) {
return;
}
@@ -1366,7 +1389,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_1() {
return;
}
- onion.last_frame = frame;
+ onion.last_frame = cur_frame;
// Refresh viewports with no onion layers overlaid.
onion.can_overlay = false;
@@ -1545,6 +1568,7 @@ void AnimationPlayerEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_animation_edit"), &AnimationPlayerEditor::_animation_edit);
ClassDB::bind_method(D_METHOD("_animation_resource_edit"), &AnimationPlayerEditor::_animation_resource_edit);
ClassDB::bind_method(D_METHOD("_animation_player_changed"), &AnimationPlayerEditor::_animation_player_changed);
+ ClassDB::bind_method(D_METHOD("_animation_libraries_updated"), &AnimationPlayerEditor::_animation_libraries_updated);
ClassDB::bind_method(D_METHOD("_list_changed"), &AnimationPlayerEditor::_list_changed);
ClassDB::bind_method(D_METHOD("_animation_duplicate"), &AnimationPlayerEditor::_animation_duplicate);
@@ -1552,6 +1576,8 @@ void AnimationPlayerEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_prepare_onion_layers_2"), &AnimationPlayerEditor::_prepare_onion_layers_2);
ClassDB::bind_method(D_METHOD("_start_onion_skinning"), &AnimationPlayerEditor::_start_onion_skinning);
ClassDB::bind_method(D_METHOD("_stop_onion_skinning"), &AnimationPlayerEditor::_stop_onion_skinning);
+
+ ADD_SIGNAL(MethodInfo("animation_selected", PropertyInfo(Variant::STRING, "name")));
}
AnimationPlayerEditor *AnimationPlayerEditor::singleton = nullptr;
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 06fd9455df..ae570e53f3 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -195,6 +195,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _blend_edited();
void _animation_player_changed(Object *p_pl);
+ void _animation_libraries_updated();
void _animation_key_editor_seek(float p_pos, bool p_drag, bool p_timeline_only = false);
void _animation_key_editor_anim_len_changed(float p_len);
@@ -266,7 +267,7 @@ public:
virtual void make_visible(bool p_visible) override;
virtual void forward_canvas_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
- virtual void forward_spatial_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
+ virtual void forward_3d_force_draw_over_viewport(Control *p_overlay) override { anim_editor->forward_force_draw_over_viewport(p_overlay); }
AnimationPlayerEditorPlugin();
~AnimationPlayerEditorPlugin();
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 461326a47b..c32f9b1775 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -974,6 +974,8 @@ void AnimationNodeStateMachineEditor::_file_opened(const String &p_file) {
file_loaded = ResourceLoader::load(p_file);
if (file_loaded.is_valid()) {
_add_menu_type(MENU_LOAD_FILE_CONFIRM);
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("This type of node can't be used. Only animation nodes are allowed."));
}
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 3c9486cdaa..51b65e8eb0 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -243,19 +243,19 @@ void EditorAssetLibraryItemDescription::configure(const String &p_title, int p_a
}
void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, const String &p_url) {
- Preview preview;
- preview.id = p_id;
- preview.video_link = p_url;
- preview.is_video = p_video;
- preview.button = memnew(Button);
- preview.button->set_icon(previews->get_theme_icon(SNAME("ThumbnailWait"), SNAME("EditorIcons")));
- preview.button->set_toggle_mode(true);
- preview.button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click).bind(p_id));
- preview_hb->add_child(preview.button);
+ Preview new_preview;
+ new_preview.id = p_id;
+ new_preview.video_link = p_url;
+ new_preview.is_video = p_video;
+ new_preview.button = memnew(Button);
+ new_preview.button->set_icon(previews->get_theme_icon(SNAME("ThumbnailWait"), SNAME("EditorIcons")));
+ new_preview.button->set_toggle_mode(true);
+ new_preview.button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click).bind(p_id));
+ preview_hb->add_child(new_preview.button);
if (!p_video) {
- preview.image = previews->get_theme_icon(SNAME("ThumbnailWait"), SNAME("EditorIcons"));
+ new_preview.image = previews->get_theme_icon(SNAME("ThumbnailWait"), SNAME("EditorIcons"));
}
- preview_images.push_back(preview);
+ preview_images.push_back(new_preview);
if (preview_images.size() == 1 && !p_video) {
_preview_click(p_id);
}
@@ -460,7 +460,7 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) {
void EditorAssetLibraryItemDownload::_close() {
// Clean up downloaded file.
DirAccess::remove_file_or_error(download->get_download_file());
- queue_delete();
+ queue_free();
}
bool EditorAssetLibraryItemDownload::can_install() const {
@@ -832,7 +832,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
}
}
- image_queue[p_queue_id].request->queue_delete();
+ image_queue[p_queue_id].request->queue_free();
image_queue.erase(p_queue_id);
_update_image_queue();
@@ -868,7 +868,7 @@ void EditorAssetLibrary::_update_image_queue() {
}
while (to_delete.size()) {
- image_queue[to_delete.front()->get()].request->queue_delete();
+ image_queue[to_delete.front()->get()].request->queue_free();
image_queue.erase(to_delete.front()->get());
to_delete.pop_front();
}
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index d670197c53..e21a50a434 100644
--- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -44,8 +44,8 @@ void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) {
}
void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo.is_null());
+ Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo_man.is_null());
AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
if (!randomizer) {
@@ -76,12 +76,12 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und
end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
}
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
// Save layers' properties.
if (p_from_index < 0) {
- undo_redo->add_undo_method(randomizer, "remove_stream", p_to_pos < 0 ? randomizer->get_streams_count() : p_to_pos);
+ undo_redo_man->add_undo_method(randomizer, "remove_stream", p_to_pos < 0 ? randomizer->get_streams_count() : p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_undo_method(randomizer, "add_stream", p_from_index);
+ undo_redo_man->add_undo_method(randomizer, "add_stream", p_from_index);
}
List<PropertyInfo> properties;
@@ -107,11 +107,11 @@ void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_und
#undef ADD_UNDO
if (p_from_index < 0) {
- undo_redo->add_do_method(randomizer, "add_stream", p_to_pos);
+ undo_redo_man->add_do_method(randomizer, "add_stream", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(randomizer, "remove_stream", p_from_index);
+ undo_redo_man->add_do_method(randomizer, "remove_stream", p_from_index);
} else {
- undo_redo->add_do_method(randomizer, "move_stream", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(randomizer, "move_stream", p_from_index, p_to_pos);
}
}
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 60e8f5b44b..c834e0e93e 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -63,16 +63,16 @@ StringName BoneMapperButton::get_profile_bone_name() const {
void BoneMapperButton::set_state(BoneMapState p_state) {
switch (p_state) {
case BONE_MAP_STATE_UNSET: {
- circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/unset"));
+ circle->set_modulate(EDITOR_GET("editors/bone_mapper/handle_colors/unset"));
} break;
case BONE_MAP_STATE_SET: {
- circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/set"));
+ circle->set_modulate(EDITOR_GET("editors/bone_mapper/handle_colors/set"));
} break;
case BONE_MAP_STATE_MISSING: {
- circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/missing"));
+ circle->set_modulate(EDITOR_GET("editors/bone_mapper/handle_colors/missing"));
} break;
case BONE_MAP_STATE_ERROR: {
- circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/error"));
+ circle->set_modulate(EDITOR_GET("editors/bone_mapper/handle_colors/error"));
} break;
default: {
} break;
diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h
index 55261ab477..16e5403978 100644
--- a/editor/plugins/bone_map_editor_plugin.h
+++ b/editor/plugins/bone_map_editor_plugin.h
@@ -206,7 +206,6 @@ class BoneMapEditor : public VBoxContainer {
BoneMapper *bone_mapper = nullptr;
void fetch_objects();
- void clear_editors();
void create_editors();
protected:
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 84b8b4aed8..3f6769a5ad 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -116,6 +116,7 @@ public:
grid_offset_x->set_allow_greater(true);
grid_offset_x->set_suffix("px");
grid_offset_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ grid_offset_x->set_select_all_on_focus(true);
child_container->add_child(grid_offset_x);
grid_offset_y = memnew(SpinBox);
@@ -125,6 +126,7 @@ public:
grid_offset_y->set_allow_greater(true);
grid_offset_y->set_suffix("px");
grid_offset_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ grid_offset_y->set_select_all_on_focus(true);
child_container->add_child(grid_offset_y);
label = memnew(Label);
@@ -138,6 +140,7 @@ public:
grid_step_x->set_allow_greater(true);
grid_step_x->set_suffix("px");
grid_step_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ grid_step_x->set_select_all_on_focus(true);
child_container->add_child(grid_step_x);
grid_step_y = memnew(SpinBox);
@@ -146,6 +149,7 @@ public:
grid_step_y->set_allow_greater(true);
grid_step_y->set_suffix("px");
grid_step_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ grid_step_y->set_select_all_on_focus(true);
child_container->add_child(grid_step_y);
child_container = memnew(GridContainer);
@@ -164,6 +168,7 @@ public:
primary_grid_steps->set_allow_greater(true);
primary_grid_steps->set_suffix(TTR("steps"));
primary_grid_steps->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ primary_grid_steps->set_select_all_on_focus(true);
child_container->add_child(primary_grid_steps);
container->add_child(memnew(HSeparator));
@@ -184,6 +189,7 @@ public:
rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_suffix("deg");
rotation_offset->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ rotation_offset->set_select_all_on_focus(true);
child_container->add_child(rotation_offset);
label = memnew(Label);
@@ -196,6 +202,7 @@ public:
rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_step->set_suffix("deg");
rotation_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ rotation_step->set_select_all_on_focus(true);
child_container->add_child(rotation_step);
container->add_child(memnew(HSeparator));
@@ -214,6 +221,7 @@ public:
scale_step->set_allow_greater(true);
scale_step->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scale_step->set_step(0.01f);
+ scale_step->set_select_all_on_focus(true);
child_container->add_child(scale_step);
}
@@ -304,7 +312,7 @@ void CanvasItemEditor::_snap_other_nodes(
Point2 &r_current_snap, SnapTarget (&r_current_snap_target)[2],
const SnapTarget p_snap_target, List<const CanvasItem *> p_exceptions,
const Node *p_current) {
- const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_current);
+ const CanvasItem *ci = Object::cast_to<CanvasItem>(p_current);
// Check if the element is in the exception
bool exception = false;
@@ -315,12 +323,12 @@ void CanvasItemEditor::_snap_other_nodes(
}
};
- if (canvas_item && !exception) {
- Transform2D ci_transform = canvas_item->get_global_transform_with_canvas();
+ if (ci && !exception) {
+ Transform2D ci_transform = ci->get_global_transform_with_canvas();
if (fmod(ci_transform.get_rotation() - p_transform_to_snap.get_rotation(), (real_t)360.0) == 0.0) {
- if (canvas_item->_edit_use_rect()) {
- Point2 begin = ci_transform.xform(canvas_item->_edit_get_rect().get_position());
- Point2 end = ci_transform.xform(canvas_item->_edit_get_rect().get_position() + canvas_item->_edit_get_rect().get_size());
+ if (ci->_edit_use_rect()) {
+ Point2 begin = ci_transform.xform(ci->_edit_get_rect().get_position());
+ Point2 end = ci_transform.xform(ci->_edit_get_rect().get_position() + ci->_edit_get_rect().get_size());
_snap_if_closer_point(p_value, r_current_snap, r_current_snap_target, begin, p_snap_target, ci_transform.get_rotation());
_snap_if_closer_point(p_value, r_current_snap, r_current_snap_target, end, p_snap_target, ci_transform.get_rotation());
@@ -528,14 +536,14 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li
ERR_FAIL_COND_V(p_list.is_empty(), Rect2());
// Handles the first element
- CanvasItem *canvas_item = p_list.front()->get();
- Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().get_center()), Size2());
+ CanvasItem *ci = p_list.front()->get();
+ Rect2 rect = Rect2(ci->get_global_transform_with_canvas().xform(ci->_edit_get_rect().get_center()), Size2());
// Expand with the other ones
- for (CanvasItem *canvas_item2 : p_list) {
- Transform2D xform = canvas_item2->get_global_transform_with_canvas();
+ for (CanvasItem *ci2 : p_list) {
+ Transform2D xform = ci2->get_global_transform_with_canvas();
- Rect2 current_rect = canvas_item2->_edit_get_rect();
+ Rect2 current_rect = ci2->_edit_get_rect();
rect.expand_to(xform.xform(current_rect.position));
rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0)));
rect.expand_to(xform.xform(current_rect.position + current_rect.size));
@@ -553,24 +561,24 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c
return;
}
- const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+ const CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (canvas_item && !canvas_item->is_set_as_top_level()) {
- _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ if (ci && !ci->is_set_as_top_level()) {
+ _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * ci->get_transform(), p_canvas_xform);
} else {
- const CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
- _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
+ const CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
+ _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
}
}
- if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !_is_node_locked(canvas_item))) {
+ if (ci && ci->is_visible_in_tree() && (include_locked_nodes || !_is_node_locked(ci))) {
Transform2D xform = p_canvas_xform;
- if (!canvas_item->is_set_as_top_level()) {
+ if (!ci->is_set_as_top_level()) {
xform *= p_parent_xform;
}
- xform *= canvas_item->get_transform();
- Rect2 rect = canvas_item->_edit_get_rect();
+ xform *= ci->get_transform();
+ Rect2 rect = ci->_edit_get_rect();
if (r_first) {
r_rect = Rect2(xform.xform(rect.get_center()), Size2());
r_first = false;
@@ -599,14 +607,14 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
}
const real_t grab_distance = EDITOR_GET("editors/polygon_editor/point_grab_radius");
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+ CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (canvas_item) {
- if (!canvas_item->is_set_as_top_level()) {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ if (ci) {
+ if (!ci->is_set_as_top_level()) {
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_parent_xform * ci->get_transform(), p_canvas_xform);
} else {
- _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, canvas_item->get_transform(), p_canvas_xform);
+ _find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, ci->get_transform(), p_canvas_xform);
}
} else {
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
@@ -614,18 +622,18 @@ void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_no
}
}
- if (canvas_item && canvas_item->is_visible_in_tree()) {
+ if (ci && ci->is_visible_in_tree()) {
Transform2D xform = p_canvas_xform;
- if (!canvas_item->is_set_as_top_level()) {
+ if (!ci->is_set_as_top_level()) {
xform *= p_parent_xform;
}
- xform = (xform * canvas_item->get_transform()).affine_inverse();
+ xform = (xform * ci->get_transform()).affine_inverse();
const real_t local_grab_distance = xform.basis_xform(Vector2(grab_distance, 0)).length() / zoom;
- if (canvas_item->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
- Node2D *node = Object::cast_to<Node2D>(canvas_item);
+ if (ci->_edit_is_selected_on_click(xform.xform(p_pos), local_grab_distance)) {
+ Node2D *node = Object::cast_to<Node2D>(ci);
_SelectResult res;
- res.item = canvas_item;
+ res.item = ci;
res.z_index = node ? node->get_z_index() : 0;
res.has_z = node;
r_items.push_back(res);
@@ -647,13 +655,13 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
node = scene->get_deepest_editable_node(node);
}
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(node);
+ CanvasItem *ci = Object::cast_to<CanvasItem>(node);
if (!p_allow_locked) {
// Replace the node by the group if grouped
while (node && node != scene->get_parent()) {
- CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
- if (canvas_item_tmp && node->has_meta("_edit_group_")) {
- canvas_item = canvas_item_tmp;
+ CanvasItem *ci_tmp = Object::cast_to<CanvasItem>(node);
+ if (ci_tmp && node->has_meta("_edit_group_")) {
+ ci = ci_tmp;
}
node = node->get_parent();
}
@@ -662,18 +670,18 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
// Check if the canvas item is already in the list (for groups or scenes)
bool duplicate = false;
for (int j = 0; j < i; j++) {
- if (r_items[j].item == canvas_item) {
+ if (r_items[j].item == ci) {
duplicate = true;
break;
}
}
//Remove the item if invalid
- if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || (!p_allow_locked && _is_node_locked(canvas_item))) {
+ if (!ci || duplicate || (ci != scene && ci->get_owner() != scene && !scene->is_editable_instance(ci->get_owner())) || (!p_allow_locked && _is_node_locked(ci))) {
r_items.remove_at(i);
i--;
} else {
- r_items.write[i].item = canvas_item;
+ r_items.write[i].item = ci;
}
}
}
@@ -686,7 +694,7 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
return;
}
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
+ CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
Node *scene = EditorNode::get_singleton()->get_edited_scene();
bool editable = p_node == scene || p_node->get_owner() == scene || p_node == scene->get_deepest_editable_node(p_node);
@@ -695,37 +703,37 @@ void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_n
if (!lock_children || !editable) {
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
- if (canvas_item) {
- if (!canvas_item->is_set_as_top_level()) {
- _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * canvas_item->get_transform(), p_canvas_xform);
+ if (ci) {
+ if (!ci->is_set_as_top_level()) {
+ _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * ci->get_transform(), p_canvas_xform);
} else {
- _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, canvas_item->get_transform(), p_canvas_xform);
+ _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, ci->get_transform(), p_canvas_xform);
}
} else {
- CanvasLayer *canvas_layer = Object::cast_to<CanvasLayer>(p_node);
- _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), canvas_layer ? canvas_layer->get_transform() : p_canvas_xform);
+ CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
+ _find_canvas_items_in_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
}
}
}
- if (canvas_item && canvas_item->is_visible_in_tree() && !locked && editable) {
+ if (ci && ci->is_visible_in_tree() && !locked && editable) {
Transform2D xform = p_canvas_xform;
- if (!canvas_item->is_set_as_top_level()) {
+ if (!ci->is_set_as_top_level()) {
xform *= p_parent_xform;
}
- xform *= canvas_item->get_transform();
+ xform *= ci->get_transform();
- if (canvas_item->_edit_use_rect()) {
- Rect2 rect = canvas_item->_edit_get_rect();
+ if (ci->_edit_use_rect()) {
+ Rect2 rect = ci->_edit_get_rect();
if (p_rect.has_point(xform.xform(rect.position)) &&
p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, 0))) &&
p_rect.has_point(xform.xform(rect.position + Vector2(rect.size.x, rect.size.y))) &&
p_rect.has_point(xform.xform(rect.position + Vector2(0, rect.size.y)))) {
- r_items->push_back(canvas_item);
+ r_items->push_back(ci);
}
} else {
if (p_rect.has_point(xform.xform(Point2()))) {
- r_items->push_back(canvas_item);
+ r_items->push_back(ci);
}
}
}
@@ -765,11 +773,11 @@ bool CanvasItemEditor::_select_click_on_item(CanvasItem *item, Point2 p_click_po
List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_locked, bool remove_canvas_item_if_parent_in_selection) {
List<CanvasItem *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (canvas_item && canvas_item->is_visible_in_tree() && canvas_item->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(canvas_item))) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
+ if (ci && ci->is_visible_in_tree() && ci->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(ci))) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
if (se) {
- selection.push_back(canvas_item);
+ selection.push_back(ci);
}
}
}
@@ -819,18 +827,18 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
original_transform = Transform2D();
bool transform_stored = false;
- for (CanvasItem *canvas_item : p_canvas_items) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ for (CanvasItem *ci : p_canvas_items) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
if (se) {
if (!transform_stored) {
- original_transform = canvas_item->get_global_transform();
+ original_transform = ci->get_global_transform();
transform_stored = true;
}
- se->undo_state = canvas_item->_edit_get_state();
- se->pre_drag_xform = canvas_item->get_global_transform_with_canvas();
- if (canvas_item->_edit_use_rect()) {
- se->pre_drag_rect = canvas_item->_edit_get_rect();
+ se->undo_state = ci->_edit_get_state();
+ se->pre_drag_xform = ci->get_global_transform_with_canvas();
+ if (ci->_edit_use_rect()) {
+ se->pre_drag_rect = ci->_edit_get_rect();
} else {
se->pre_drag_rect = Rect2();
}
@@ -839,20 +847,20 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items
}
void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) {
- for (CanvasItem *canvas_item : drag_selection) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- canvas_item->_edit_set_state(se->undo_state);
+ for (CanvasItem *ci : drag_selection) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
+ ci->_edit_set_state(se->undo_state);
}
}
void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones) {
List<CanvasItem *> modified_canvas_items;
- for (CanvasItem *canvas_item : p_canvas_items) {
- Dictionary old_state = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item)->undo_state;
- Dictionary new_state = canvas_item->_edit_get_state();
+ for (CanvasItem *ci : p_canvas_items) {
+ Dictionary old_state = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci)->undo_state;
+ Dictionary new_state = ci->_edit_get_state();
if (old_state.hash() != new_state.hash()) {
- modified_canvas_items.push_back(canvas_item);
+ modified_canvas_items.push_back(ci);
}
}
@@ -861,16 +869,16 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
}
undo_redo->create_action(action_name);
- for (CanvasItem *canvas_item : modified_canvas_items) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ for (CanvasItem *ci : modified_canvas_items) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
if (se) {
- undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
- undo_redo->add_undo_method(canvas_item, "_edit_set_state", se->undo_state);
+ undo_redo->add_do_method(ci, "_edit_set_state", ci->_edit_get_state());
+ undo_redo->add_undo_method(ci, "_edit_set_state", se->undo_state);
if (commit_bones) {
for (const Dictionary &F : se->pre_drag_bones_undo_state) {
- canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent());
- undo_redo->add_do_method(canvas_item, "_edit_set_state", canvas_item->_edit_get_state());
- undo_redo->add_undo_method(canvas_item, "_edit_set_state", F);
+ ci = Object::cast_to<CanvasItem>(ci->get_parent());
+ undo_redo->add_do_method(ci, "_edit_set_state", ci->_edit_get_state());
+ undo_redo->add_undo_method(ci, "_edit_set_state", F);
}
}
}
@@ -1318,9 +1326,9 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
// Filters the selection with nodes that allow setting the pivot
drag_selection = List<CanvasItem *>();
- for (CanvasItem *canvas_item : selection) {
- if (canvas_item->_edit_use_pivot()) {
- drag_selection.push_back(canvas_item);
+ for (CanvasItem *ci : selection) {
+ if (ci->_edit_use_pivot()) {
+ drag_selection.push_back(ci);
}
}
@@ -1334,8 +1342,8 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
} else {
new_pos = snap_point(drag_from, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, nullptr, drag_selection);
}
- for (CanvasItem *canvas_item : drag_selection) {
- canvas_item->_edit_set_pivot(canvas_item->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
+ for (CanvasItem *ci : drag_selection) {
+ ci->_edit_set_pivot(ci->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
}
drag_type = DRAG_PIVOT;
@@ -1355,8 +1363,8 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) {
} else {
new_pos = snap_point(drag_to, SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL);
}
- for (CanvasItem *canvas_item : drag_selection) {
- canvas_item->_edit_set_pivot(canvas_item->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
+ for (CanvasItem *ci : drag_selection) {
+ ci->_edit_set_pivot(ci->get_global_transform_with_canvas().affine_inverse().xform(new_pos));
}
return true;
}
@@ -1408,11 +1416,11 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
if (drag_selection.size() > 0) {
drag_type = DRAG_ROTATE;
drag_from = transform.affine_inverse().xform(b->get_position());
- CanvasItem *canvas_item = drag_selection[0];
- if (canvas_item->_edit_use_pivot()) {
- drag_rotation_center = canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_pivot());
+ CanvasItem *ci = drag_selection[0];
+ if (ci->_edit_use_pivot()) {
+ drag_rotation_center = ci->get_global_transform_with_canvas().xform(ci->_edit_get_pivot());
} else {
- drag_rotation_center = canvas_item->get_global_transform_with_canvas().get_origin();
+ drag_rotation_center = ci->get_global_transform_with_canvas().get_origin();
}
_save_canvas_item_state(drag_selection);
return true;
@@ -1425,11 +1433,11 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
// Rotate the node
if (m.is_valid()) {
_restore_canvas_item_state(drag_selection);
- for (CanvasItem *canvas_item : drag_selection) {
+ for (CanvasItem *ci : drag_selection) {
drag_to = transform.affine_inverse().xform(m->get_position());
//Rotate the opposite way if the canvas item's compounded scale has an uneven number of negative elements
- bool opposite = (canvas_item->get_global_transform().get_scale().sign().dot(canvas_item->get_transform().get_scale().sign()) == 0);
- canvas_item->_edit_set_rotation(snap_angle(canvas_item->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), canvas_item->_edit_get_rotation()));
+ bool opposite = (ci->get_global_transform().get_scale().sign().dot(ci->get_transform().get_scale().sign()) == 0);
+ ci->_edit_set_rotation(snap_angle(ci->_edit_get_rotation() + (opposite ? -1 : 1) * (drag_from - drag_rotation_center).angle_to(drag_to - drag_rotation_center), ci->_edit_get_rotation()));
viewport->queue_redraw();
}
return true;
@@ -1477,9 +1485,9 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && b->is_double_click() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
- CanvasItem *canvas_item = selection[0];
- if (!canvas_item->get_scene_file_path().is_empty() && canvas_item != EditorNode::get_singleton()->get_edited_scene()) {
- EditorNode::get_singleton()->open_request(canvas_item->get_scene_file_path());
+ CanvasItem *ci = selection[0];
+ if (!ci->get_scene_file_path().is_empty() && ci != EditorNode::get_singleton()->get_edited_scene()) {
+ EditorNode::get_singleton()->open_request(ci->get_scene_file_path());
return true;
}
}
@@ -1641,10 +1649,10 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
- CanvasItem *canvas_item = selection[0];
- if (canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
- Rect2 rect = canvas_item->_edit_get_rect();
- Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
+ CanvasItem *ci = selection[0];
+ if (ci->_edit_use_rect() && _is_node_movable(ci)) {
+ Rect2 rect = ci->_edit_get_rect();
+ Transform2D xform = transform * ci->get_global_transform_with_canvas();
const Vector2 endpoints[4] = {
xform.xform(rect.position),
@@ -1689,7 +1697,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
drag_type = resize_drag;
drag_from = transform.affine_inverse().xform(b->get_position());
drag_selection = List<CanvasItem *>();
- drag_selection.push_back(canvas_item);
+ drag_selection.push_back(ci);
_save_canvas_item_state(drag_selection);
return true;
}
@@ -1702,36 +1710,36 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
drag_type == DRAG_TOP_LEFT || drag_type == DRAG_TOP_RIGHT || drag_type == DRAG_BOTTOM_LEFT || drag_type == DRAG_BOTTOM_RIGHT) {
// Resize the node
if (m.is_valid()) {
- CanvasItem *canvas_item = drag_selection[0];
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ CanvasItem *ci = drag_selection[0];
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
//Reset state
- canvas_item->_edit_set_state(se->undo_state);
+ ci->_edit_set_state(se->undo_state);
bool uniform = m->is_shift_pressed();
bool symmetric = m->is_alt_pressed();
- Rect2 local_rect = canvas_item->_edit_get_rect();
+ Rect2 local_rect = ci->_edit_get_rect();
real_t aspect = local_rect.get_size().y / local_rect.get_size().x;
Point2 current_begin = local_rect.get_position();
Point2 current_end = local_rect.get_position() + local_rect.get_size();
- Point2 max_begin = (symmetric) ? (current_begin + current_end - canvas_item->_edit_get_minimum_size()) / 2.0 : current_end - canvas_item->_edit_get_minimum_size();
- Point2 min_end = (symmetric) ? (current_begin + current_end + canvas_item->_edit_get_minimum_size()) / 2.0 : current_begin + canvas_item->_edit_get_minimum_size();
+ Point2 max_begin = (symmetric) ? (current_begin + current_end - ci->_edit_get_minimum_size()) / 2.0 : current_end - ci->_edit_get_minimum_size();
+ Point2 min_end = (symmetric) ? (current_begin + current_end + ci->_edit_get_minimum_size()) / 2.0 : current_begin + ci->_edit_get_minimum_size();
Point2 center = (current_begin + current_end) / 2.0;
drag_to = transform.affine_inverse().xform(m->get_position());
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse();
+ Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse();
Point2 drag_to_snapped_begin;
Point2 drag_to_snapped_end;
// last call decides which snapping lines are drawn
if (drag_type == DRAG_LEFT || drag_type == DRAG_TOP || drag_type == DRAG_TOP_LEFT) {
- drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
- drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
+ drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
+ drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
} else {
- drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
- drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, canvas_item);
+ drag_to_snapped_begin = snap_point(xform.affine_inverse().xform(current_begin) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
+ drag_to_snapped_end = snap_point(xform.affine_inverse().xform(current_end) + (drag_to - drag_from), SNAP_NODE_ANCHORS | SNAP_NODE_PARENT | SNAP_OTHER_NODES | SNAP_GRID | SNAP_PIXEL, 0, ci);
}
Point2 drag_begin = xform.xform(drag_to_snapped_begin);
@@ -1787,7 +1795,7 @@ bool CanvasItemEditor::_gui_input_resize(const Ref<InputEvent> &p_event) {
current_begin.y = 2.0 * center.y - current_end.y;
}
}
- canvas_item->_edit_set_rect(Rect2(current_begin, current_end - current_begin));
+ ci->_edit_set_rect(Rect2(current_begin, current_end - current_begin));
return true;
}
@@ -1850,11 +1858,11 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
- CanvasItem *canvas_item = selection[0];
+ CanvasItem *ci = selection[0];
- if (_is_node_movable(canvas_item)) {
- Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ if (_is_node_movable(ci)) {
+ Transform2D xform = transform * ci->get_global_transform_with_canvas();
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
drag_type = DRAG_SCALE_BOTH;
@@ -1873,7 +1881,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
drag_from = transform.affine_inverse().xform(b->get_position());
drag_selection = List<CanvasItem *>();
- drag_selection.push_back(canvas_item);
+ drag_selection.push_back(ci);
_save_canvas_item_state(drag_selection);
return true;
}
@@ -1885,12 +1893,12 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Resize the node
if (m.is_valid()) {
_restore_canvas_item_state(drag_selection);
- CanvasItem *canvas_item = drag_selection[0];
+ CanvasItem *ci = drag_selection[0];
drag_to = transform.affine_inverse().xform(m->get_position());
- Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse();
- Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized();
+ Transform2D parent_xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse();
+ Transform2D unscaled_transform = (transform * parent_xform * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->is_shift_pressed();
@@ -1900,7 +1908,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Point2 drag_to_local = simple_xform.xform(drag_to);
Point2 offset = drag_to_local - drag_from_local;
- Size2 scale = canvas_item->_edit_get_scale();
+ Size2 scale = ci->_edit_get_scale();
Size2 original_scale = scale;
real_t ratio = scale.y / scale.x;
if (drag_type == DRAG_SCALE_BOTH) {
@@ -1938,7 +1946,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
}
}
- canvas_item->_edit_set_scale(scale);
+ ci->_edit_set_scale(scale);
return true;
}
@@ -1999,9 +2007,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (selection.size() > 0) {
drag_type = DRAG_MOVE;
- CanvasItem *canvas_item = selection[0];
- Transform2D parent_xform = canvas_item->get_global_transform_with_canvas() * canvas_item->get_transform().affine_inverse();
- Transform2D unscaled_transform = (transform * parent_xform * canvas_item->_edit_get_transform()).orthonormalized();
+ CanvasItem *ci = selection[0];
+ Transform2D parent_xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse();
+ Transform2D unscaled_transform = (transform * parent_xform * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
if (show_transformation_gizmos) {
@@ -2058,10 +2066,10 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
int index = 0;
- for (CanvasItem *canvas_item : drag_selection) {
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+ for (CanvasItem *ci : drag_selection) {
+ Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform();
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
index++;
}
return true;
@@ -2181,10 +2189,10 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
int index = 0;
- for (CanvasItem *canvas_item : drag_selection) {
- Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform();
+ for (CanvasItem *ci : drag_selection) {
+ Transform2D xform = ci->get_global_transform_with_canvas().affine_inverse() * ci->get_transform();
- canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
+ ci->_edit_set_position(ci->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos));
index++;
}
}
@@ -2263,8 +2271,8 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
Node *node = item;
while (node && node != scene->get_parent()) {
- CanvasItem *canvas_item_tmp = Object::cast_to<CanvasItem>(node);
- if (canvas_item_tmp && node->has_meta("_edit_group_")) {
+ CanvasItem *ci_tmp = Object::cast_to<CanvasItem>(node);
+ if (ci_tmp && node->has_meta("_edit_group_")) {
locked = 2;
}
node = node->get_parent();
@@ -2325,16 +2333,16 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
// Find the item to select
- CanvasItem *canvas_item = nullptr;
+ CanvasItem *ci = nullptr;
Vector<_SelectResult> selection = Vector<_SelectResult>();
// Retrieve the canvas items
_get_canvas_items_at_pos(click, selection);
if (!selection.is_empty()) {
- canvas_item = selection[0].item;
+ ci = selection[0].item;
}
- if (!canvas_item) {
+ if (!ci) {
// Start a box selection
if (!b->is_shift_pressed()) {
// Clear the selection if not additive
@@ -2348,7 +2356,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
box_selecting_to = drag_from;
return true;
} else {
- bool still_selected = _select_click_on_item(canvas_item, click, b->is_shift_pressed());
+ bool still_selected = _select_click_on_item(ci, click, b->is_shift_pressed());
// Start dragging
if (still_selected) {
// Drag the node(s) if requested
@@ -2488,16 +2496,16 @@ bool CanvasItemEditor::_gui_input_hover(const Ref<InputEvent> &p_event) {
// Compute the nodes names and icon position
Vector<_HoverResult> hovering_results_tmp;
for (int i = 0; i < hovering_results_items.size(); i++) {
- CanvasItem *canvas_item = hovering_results_items[i].item;
+ CanvasItem *ci = hovering_results_items[i].item;
- if (canvas_item->_edit_use_rect()) {
+ if (ci->_edit_use_rect()) {
continue;
}
_HoverResult hover_result;
- hover_result.position = canvas_item->get_global_transform_with_canvas().get_origin();
- hover_result.icon = EditorNode::get_singleton()->get_object_icon(canvas_item);
- hover_result.name = canvas_item->get_name();
+ hover_result.position = ci->get_global_transform_with_canvas().get_origin();
+ hover_result.icon = EditorNode::get_singleton()->get_object_icon(ci);
+ hover_result.name = ci->get_name();
hovering_results_tmp.push_back(hover_result);
}
@@ -2534,7 +2542,7 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
bool release_lmb = (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT); // Required to properly release some stuff (e.g. selection box) while panning.
- if (EditorSettings::get_singleton()->get("editors/panning/simple_panning") || !pan_pressed || release_lmb) {
+ if (EDITOR_GET("editors/panning/simple_panning") || !pan_pressed || release_lmb) {
accepted = true;
if (_gui_input_rulers_and_guides(p_event)) {
// print_line("Rulers and guides");
@@ -2722,7 +2730,7 @@ void CanvasItemEditor::_draw_focus() {
}
void CanvasItemEditor::_draw_guides() {
- Color guide_color = EditorSettings::get_singleton()->get("editors/2d/guides_color");
+ Color guide_color = EDITOR_GET("editors/2d/guides_color");
Transform2D xform = viewport_scrollable->get_transform() * transform;
// Guides already there.
@@ -2771,7 +2779,7 @@ void CanvasItemEditor::_draw_guides() {
}
void CanvasItemEditor::_draw_smart_snapping() {
- Color line_color = EditorSettings::get_singleton()->get("editors/2d/smart_snapping_line_color");
+ Color line_color = EDITOR_GET("editors/2d/smart_snapping_line_color");
if (snap_target[0] != SNAP_TARGET_NONE && snap_target[0] != SNAP_TARGET_GRID) {
viewport->draw_set_transform_matrix(viewport->get_transform() * transform * snap_transform);
viewport->draw_line(Point2(0, -1.0e+10F), Point2(0, 1.0e+10F), line_color);
@@ -2889,7 +2897,7 @@ void CanvasItemEditor::_draw_grid() {
// Draw a "primary" line every several lines to make measurements easier.
// The step is configurable in the Configure Snap dialog.
- const Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/2d/grid_color");
+ const Color secondary_grid_color = EDITOR_GET("editors/2d/grid_color");
const Color primary_grid_color =
Color(secondary_grid_color.r, secondary_grid_color.g, secondary_grid_color.b, secondary_grid_color.a * 2.5);
@@ -3312,16 +3320,16 @@ void CanvasItemEditor::_draw_selection() {
Ref<Texture2D> position_icon = get_theme_icon(SNAME("EditorPosition"), SNAME("EditorIcons"));
Ref<Texture2D> previous_position_icon = get_theme_icon(SNAME("EditorPositionPrevious"), SNAME("EditorIcons"));
- RID ci = viewport->get_canvas_item();
+ RID vp_ci = viewport->get_canvas_item();
List<CanvasItem *> selection = _get_edited_canvas_items(true, false);
bool single = selection.size() == 1;
for (CanvasItem *E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E);
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E);
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
- bool item_locked = canvas_item->has_meta("_edit_lock_");
+ bool item_locked = ci->has_meta("_edit_lock_");
// Draw the previous position if we are dragging the node
if (show_helpers &&
@@ -3331,7 +3339,7 @@ void CanvasItemEditor::_draw_selection() {
const Transform2D pre_drag_xform = transform * se->pre_drag_xform;
const Color pre_drag_color = Color(0.4, 0.6, 1, 0.7);
- if (canvas_item->_edit_use_rect()) {
+ if (ci->_edit_use_rect()) {
Vector2 pre_drag_endpoints[4] = {
pre_drag_xform.xform(se->pre_drag_rect.position),
pre_drag_xform.xform(se->pre_drag_rect.position + Vector2(se->pre_drag_rect.size.x, 0)),
@@ -3347,11 +3355,11 @@ void CanvasItemEditor::_draw_selection() {
}
}
- Transform2D xform = transform * canvas_item->get_global_transform_with_canvas();
+ Transform2D xform = transform * ci->get_global_transform_with_canvas();
// Draw the selected items position / surrounding boxes
- if (canvas_item->_edit_use_rect()) {
- Rect2 rect = canvas_item->_edit_get_rect();
+ if (ci->_edit_use_rect()) {
+ Rect2 rect = ci->_edit_get_rect();
const Vector2 endpoints[4] = {
xform.xform(rect.position),
xform.xform(rect.position + Vector2(rect.size.x, 0)),
@@ -3369,7 +3377,7 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_line(endpoints[i], endpoints[(i + 1) % 4], c, Math::round(2 * EDSCALE));
}
} else {
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
viewport->draw_texture(position_icon, -(position_icon->get_size() / 2));
@@ -3378,9 +3386,9 @@ void CanvasItemEditor::_draw_selection() {
if (single && !item_locked && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
// Draw the pivot
- if (canvas_item->_edit_use_pivot()) {
+ if (ci->_edit_use_pivot()) {
// Draw the node's pivot
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
@@ -3389,15 +3397,15 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw control-related helpers
- Control *control = Object::cast_to<Control>(canvas_item);
+ Control *control = Object::cast_to<Control>(ci);
if (control && _is_node_movable(control)) {
_draw_control_anchors(control);
_draw_control_helpers(control);
}
// Draw the resize handles
- if (tool == TOOL_SELECT && canvas_item->_edit_use_rect() && _is_node_movable(canvas_item)) {
- Rect2 rect = canvas_item->_edit_get_rect();
+ if (tool == TOOL_SELECT && ci->_edit_use_rect() && _is_node_movable(ci)) {
+ Rect2 rect = ci->_edit_get_rect();
const Vector2 endpoints[4] = {
xform.xform(rect.position),
xform.xform(rect.position + Vector2(rect.size.x, 0)),
@@ -3411,12 +3419,12 @@ void CanvasItemEditor::_draw_selection() {
Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
ofs *= Math_SQRT2 * (select_handle->get_size().width / 2);
- select_handle->draw(ci, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor());
+ select_handle->draw(vp_ci, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor());
ofs = (endpoints[i] + endpoints[next]) / 2;
ofs += (endpoints[next] - endpoints[i]).orthogonal().normalized() * (select_handle->get_size().width / 2);
- select_handle->draw(ci, (ofs - (select_handle->get_size() / 2)).floor());
+ select_handle->draw(vp_ci, (ofs - (select_handle->get_size() / 2)).floor());
}
}
@@ -3424,8 +3432,8 @@ void CanvasItemEditor::_draw_selection() {
bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
- if (_is_node_movable(canvas_item)) {
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ if (_is_node_movable(ci)) {
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE);
@@ -3454,8 +3462,8 @@ void CanvasItemEditor::_draw_selection() {
// Draw the rescale handles
if (show_transformation_gizmos && ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y)) {
- if (_is_node_movable(canvas_item)) {
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ if (_is_node_movable(ci)) {
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
@@ -3565,9 +3573,9 @@ void CanvasItemEditor::_draw_axis() {
if (show_viewport) {
RID ci = viewport->get_canvas_item();
- Color area_axis_color = EditorSettings::get_singleton()->get("editors/2d/viewport_border_color");
+ Color area_axis_color = EDITOR_GET("editors/2d/viewport_border_color");
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
Vector2 screen_endpoints[4] = {
transform.xform(Vector2(0, 0)),
@@ -3589,16 +3597,16 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
return;
}
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- if (canvas_item && !canvas_item->is_visible_in_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
+ if (ci && !ci->is_visible_in_tree()) {
return;
}
Transform2D parent_xform = p_parent_xform;
Transform2D canvas_xform = p_canvas_xform;
- if (canvas_item && !canvas_item->is_set_as_top_level()) {
- parent_xform = parent_xform * canvas_item->get_transform();
+ if (ci && !ci->is_set_as_top_level()) {
+ parent_xform = parent_xform * ci->get_transform();
} else {
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
parent_xform = Transform2D();
@@ -3609,12 +3617,12 @@ void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Trans
_draw_invisible_nodes_positions(p_node->get_child(i), parent_xform, canvas_xform);
}
- if (canvas_item && !canvas_item->_edit_use_rect() && (!editor_selection->is_selected(canvas_item) || _is_node_locked(canvas_item))) {
+ if (ci && !ci->_edit_use_rect() && (!editor_selection->is_selected(ci) || _is_node_locked(ci))) {
Transform2D xform = transform * canvas_xform * parent_xform;
// Draw the node's position
Ref<Texture2D> position_icon = get_theme_icon(SNAME("EditorPositionUnselected"), SNAME("EditorIcons"));
- Transform2D unscaled_transform = (xform * canvas_item->get_transform().affine_inverse() * canvas_item->_edit_get_transform()).orthonormalized();
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
viewport->draw_set_transform_matrix(simple_xform);
viewport->draw_texture(position_icon, -position_icon->get_size() / 2, Color(1.0, 1.0, 1.0, 0.5));
@@ -3720,16 +3728,16 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
return;
}
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node);
- if (canvas_item && !canvas_item->is_visible_in_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
+ if (ci && !ci->is_visible_in_tree()) {
return;
}
Transform2D parent_xform = p_parent_xform;
Transform2D canvas_xform = p_canvas_xform;
- if (canvas_item && !canvas_item->is_set_as_top_level()) {
- parent_xform = parent_xform * canvas_item->get_transform();
+ if (ci && !ci->is_set_as_top_level()) {
+ parent_xform = parent_xform * ci->get_transform();
} else {
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
parent_xform = Transform2D();
@@ -3740,19 +3748,19 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p
_draw_locks_and_groups(p_node->get_child(i), parent_xform, canvas_xform);
}
- RID viewport_canvas_item = viewport->get_canvas_item();
- if (canvas_item) {
+ RID viewport_ci = viewport->get_canvas_item();
+ if (ci) {
real_t offset = 0;
Ref<Texture2D> lock = get_theme_icon(SNAME("LockViewport"), SNAME("EditorIcons"));
if (p_node->has_meta("_edit_lock_") && show_edit_locks) {
- lock->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
+ lock->draw(viewport_ci, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
offset += lock->get_size().x;
}
Ref<Texture2D> group = get_theme_icon(SNAME("GroupViewport"), SNAME("EditorIcons"));
- if (canvas_item->has_meta("_edit_group_") && show_edit_locks) {
- group->draw(viewport_canvas_item, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
+ if (ci->has_meta("_edit_group_") && show_edit_locks) {
+ group->draw(viewport_ci, (transform * canvas_xform * parent_xform).xform(Point2(0, 0)) + Point2(offset, 0));
//offset += group->get_size().x;
}
}
@@ -3871,9 +3879,9 @@ void CanvasItemEditor::_update_editor_settings() {
context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), SNAME("EditorStyles")));
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- pan_speed = int(EditorSettings::get_singleton()->get("editors/panning/2d_editor_pan_speed"));
- warped_panning = bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning"));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
+ pan_speed = int(EDITOR_GET("editors/panning/2d_editor_pan_speed"));
+ warped_panning = bool(EDITOR_GET("editors/panning/warped_mouse_panning"));
}
void CanvasItemEditor::_notification(int p_what) {
@@ -3885,16 +3893,16 @@ void CanvasItemEditor::_notification(int p_what) {
// Update the viewport if the canvas_item changes
List<CanvasItem *> selection = _get_edited_canvas_items(true);
- for (CanvasItem *canvas_item : selection) {
- CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ for (CanvasItem *ci : selection) {
+ CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
Rect2 rect;
- if (canvas_item->_edit_use_rect()) {
- rect = canvas_item->_edit_get_rect();
+ if (ci->_edit_use_rect()) {
+ rect = ci->_edit_get_rect();
} else {
rect = Rect2();
}
- Transform2D xform = canvas_item->get_transform();
+ Transform2D xform = ci->get_transform();
if (rect != se->prev_rect || xform != se->prev_xform) {
viewport->queue_redraw();
@@ -3902,7 +3910,7 @@ void CanvasItemEditor::_notification(int p_what) {
se->prev_xform = xform;
}
- Control *control = Object::cast_to<Control>(canvas_item);
+ Control *control = Object::cast_to<Control>(ci);
if (control) {
real_t anchors[4];
Vector2 pivot;
@@ -3923,7 +3931,7 @@ void CanvasItemEditor::_notification(int p_what) {
}
}
- if (canvas_item->_edit_use_pivot()) {
+ if (ci->_edit_use_pivot()) {
nb_having_pivot++;
}
}
@@ -4019,7 +4027,7 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 vmin = v_scroll->get_minimum_size();
// Get the visible frame.
- Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ Size2 screen_rect = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height));
// Calculate scrollable area.
@@ -4036,7 +4044,7 @@ void CanvasItemEditor::_update_scrollbars() {
Size2 size = viewport->get_size();
Point2 begin = canvas_item_rect.position;
Point2 end = canvas_item_rect.position + canvas_item_rect.size - local_rect.size / zoom;
- bool constrain_editor_view = bool(EditorSettings::get_singleton()->get("editors/2d/constrain_editor_view"));
+ bool constrain_editor_view = bool(EDITOR_GET("editors/2d/constrain_editor_view"));
if (canvas_item_rect.size.height <= (local_rect.size.y / zoom)) {
real_t centered = -(size.y / 2) / zoom + screen_rect.y / 2;
@@ -4184,17 +4192,17 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
te->make_insert_queue();
for (const KeyValue<Node *, Object *> &E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (!canvas_item || !canvas_item->is_visible_in_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
+ if (!ci || !ci->is_visible_in_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- if (Object::cast_to<Node2D>(canvas_item)) {
- Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
+ if (Object::cast_to<Node2D>(ci)) {
+ Node2D *n2d = Object::cast_to<Node2D>(ci);
if (key_pos && p_location) {
te->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing);
@@ -4241,8 +4249,8 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
}
}
- } else if (Object::cast_to<Control>(canvas_item)) {
- Control *ctrl = Object::cast_to<Control>(canvas_item);
+ } else if (Object::cast_to<Control>(ci)) {
+ Control *ctrl = Object::cast_to<Control>(ci);
if (key_pos) {
te->insert_node_value_key(ctrl, "position", ctrl->get_position(), p_on_existing);
@@ -4390,16 +4398,16 @@ void CanvasItemEditor::_popup_callback(int p_op) {
List<Node *> selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E);
- if (!canvas_item || !canvas_item->is_inside_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E);
+ if (!ci || !ci->is_inside_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- undo_redo->add_do_method(canvas_item, "set_meta", "_edit_lock_", true);
- undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_lock_");
+ undo_redo->add_do_method(ci, "set_meta", "_edit_lock_", true);
+ undo_redo->add_undo_method(ci, "remove_meta", "_edit_lock_");
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
@@ -4412,16 +4420,16 @@ void CanvasItemEditor::_popup_callback(int p_op) {
List<Node *> selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E);
- if (!canvas_item || !canvas_item->is_inside_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E);
+ if (!ci || !ci->is_inside_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_lock_");
- undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_lock_", true);
+ undo_redo->add_do_method(ci, "remove_meta", "_edit_lock_");
+ undo_redo->add_undo_method(ci, "set_meta", "_edit_lock_", true);
undo_redo->add_do_method(this, "emit_signal", "item_lock_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
@@ -4434,16 +4442,16 @@ void CanvasItemEditor::_popup_callback(int p_op) {
List<Node *> selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E);
- if (!canvas_item || !canvas_item->is_inside_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E);
+ if (!ci || !ci->is_inside_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- undo_redo->add_do_method(canvas_item, "set_meta", "_edit_group_", true);
- undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_group_");
+ undo_redo->add_do_method(ci, "set_meta", "_edit_group_", true);
+ undo_redo->add_undo_method(ci, "remove_meta", "_edit_group_");
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
@@ -4456,16 +4464,16 @@ void CanvasItemEditor::_popup_callback(int p_op) {
List<Node *> selection = editor_selection->get_selected_node_list();
for (Node *E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E);
- if (!canvas_item || !canvas_item->is_inside_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E);
+ if (!ci || !ci->is_inside_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- undo_redo->add_do_method(canvas_item, "remove_meta", "_edit_group_");
- undo_redo->add_undo_method(canvas_item, "set_meta", "_edit_group_", true);
+ undo_redo->add_do_method(ci, "remove_meta", "_edit_group_");
+ undo_redo->add_undo_method(ci, "set_meta", "_edit_group_", true);
undo_redo->add_do_method(this, "emit_signal", "item_group_status_changed");
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
@@ -4496,17 +4504,17 @@ void CanvasItemEditor::_popup_callback(int p_op) {
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (!canvas_item || !canvas_item->is_visible_in_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
+ if (!ci || !ci->is_visible_in_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- if (Object::cast_to<Node2D>(canvas_item)) {
- Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
+ if (Object::cast_to<Node2D>(ci)) {
+ Node2D *n2d = Object::cast_to<Node2D>(ci);
PoseClipboard pc;
pc.pos = n2d->get_position();
pc.rot = n2d->get_rotation();
@@ -4542,17 +4550,17 @@ void CanvasItemEditor::_popup_callback(int p_op) {
HashMap<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (!canvas_item || !canvas_item->is_visible_in_tree()) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
+ if (!ci || !ci->is_visible_in_tree()) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
- if (Object::cast_to<Node2D>(canvas_item)) {
- Node2D *n2d = Object::cast_to<Node2D>(canvas_item);
+ if (Object::cast_to<Node2D>(ci)) {
+ Node2D *n2d = Object::cast_to<Node2D>(ci);
if (key_pos) {
n2d->set_position(Vector2());
@@ -4563,8 +4571,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (key_scale) {
n2d->set_scale(Vector2(1, 1));
}
- } else if (Object::cast_to<Control>(canvas_item)) {
- Control *ctrl = Object::cast_to<Control>(canvas_item);
+ } else if (Object::cast_to<Control>(ci)) {
+ Control *ctrl = Object::cast_to<Control>(ci);
if (key_pos) {
ctrl->set_position(Point2());
@@ -4658,28 +4666,28 @@ void CanvasItemEditor::_focus_selection(int p_op) {
const HashMap<Node *, Object *> &selection = editor_selection->get_selection();
for (const KeyValue<Node *, Object *> &E : selection) {
- CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E.key);
- if (!canvas_item) {
+ CanvasItem *ci = Object::cast_to<CanvasItem>(E.key);
+ if (!ci) {
continue;
}
- if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
+ if (ci->get_viewport() != EditorNode::get_singleton()->get_scene_root()) {
continue;
}
// counting invisible items, for now
- //if (!canvas_item->is_visible_in_tree()) continue;
+ //if (!ci->is_visible_in_tree()) continue;
++count;
Rect2 item_rect;
- if (canvas_item->_edit_use_rect()) {
- item_rect = canvas_item->_edit_get_rect();
+ if (ci->_edit_use_rect()) {
+ item_rect = ci->_edit_get_rect();
} else {
item_rect = Rect2();
}
- Vector2 pos = canvas_item->get_global_transform().get_origin();
- Vector2 scale = canvas_item->get_global_transform().get_scale();
- real_t angle = canvas_item->get_global_transform().get_rotation();
+ Vector2 pos = ci->get_global_transform().get_origin();
+ Vector2 scale = ci->get_global_transform().get_scale();
+ real_t angle = ci->get_global_transform().get_rotation();
Transform2D t(angle, Vector2(0.f, 0.f));
item_rect = t.xform(item_rect);
@@ -5060,6 +5068,7 @@ CanvasItemEditor::CanvasItemEditor() {
zoom_widget = memnew(EditorZoomWidget);
controls_vb->add_child(zoom_widget);
zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
+ zoom_widget->set_shortcut_context(this);
zoom_widget->connect("zoom_changed", callable_mp(this, &CanvasItemEditor::_update_zoom));
panner.instantiate();
@@ -5316,7 +5325,7 @@ CanvasItemEditor::CanvasItemEditor() {
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/frame_selection", TTR("Frame Selection"), KeyModifierMask::SHIFT | Key::F), VIEW_FRAME_TO_SELECTION);
p->add_shortcut(ED_SHORTCUT("canvas_item_editor/clear_guides", TTR("Clear Guides")), CLEAR_GUIDES);
p->add_separator();
- p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale"), KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL | Key::P), PREVIEW_CANVAS_SCALE);
+ p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/preview_canvas_scale", TTR("Preview Canvas Scale")), PREVIEW_CANVAS_SCALE);
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5454,6 +5463,15 @@ void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
canvas_item_editor->set_state(p_state);
}
+void CanvasItemEditorPlugin::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ connect("scene_changed", callable_mp((CanvasItem *)canvas_item_editor->get_viewport_control(), &CanvasItem::queue_redraw).unbind(1));
+ connect("scene_closed", callable_mp((CanvasItem *)canvas_item_editor->get_viewport_control(), &CanvasItem::queue_redraw).unbind(1));
+ } break;
+ }
+}
+
CanvasItemEditorPlugin::CanvasItemEditorPlugin() {
canvas_item_editor = memnew(CanvasItemEditor);
canvas_item_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -5533,7 +5551,7 @@ void CanvasItemEditorViewport::_remove_preview() {
if (preview_node->get_parent()) {
for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
Node *node = preview_node->get_child(i);
- node->queue_delete();
+ node->queue_free();
preview_node->remove_child(node);
}
EditorNode::get_singleton()->get_scene_root()->remove_child(preview_node);
@@ -5733,8 +5751,10 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
ResourceLoader::get_recognized_extensions_for_type("Texture2D", &texture_extensions);
for (int i = 0; i < files.size(); i++) {
+ String extension = files[i].get_extension().to_lower();
+
// Check if dragged files with texture or scene extension can be created at least once.
- if (texture_extensions.find(files[i].get_extension()) || scene_extensions.find(files[i].get_extension())) {
+ if (texture_extensions.find(extension) || scene_extensions.find(extension)) {
Ref<Resource> res = ResourceLoader::load(files[i]);
if (res.is_null()) {
continue;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index b731d3cc7d..3ade048e4b 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -563,6 +563,9 @@ class CanvasItemEditorPlugin : public EditorPlugin {
CanvasItemEditor *canvas_item_editor = nullptr;
+protected:
+ void _notification(int p_what);
+
public:
virtual String get_name() const override { return "2D"; }
bool has_main_screen() const override { return true; }
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index e56fd5dfe3..a0e6771768 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -110,8 +110,8 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() {
int vpc = 0;
{
- Vector<uint8_t> data = img->get_data();
- const uint8_t *r = data.ptr();
+ Vector<uint8_t> img_data = img->get_data();
+ const uint8_t *r = img_data.ptr();
for (int i = 0; i < s.width; i++) {
for (int j = 0; j < s.height; j++) {
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 8d1df0b32c..6149127fcc 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -755,10 +755,10 @@ void CurveEditor::_draw() {
float width = view_size.x - 60 * EDSCALE;
if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) {
text_color.a *= 0.4;
- draw_multiline_string(font, Vector2(50 * EDSCALE, font_height), TTR("Hold Shift to edit tangents individually"), HORIZONTAL_ALIGNMENT_LEFT, width, -1, font_size, text_color);
+ draw_multiline_string(font, Vector2(50 * EDSCALE, font_height), TTR("Hold Shift to edit tangents individually"), HORIZONTAL_ALIGNMENT_LEFT, width, font_size, -1, text_color);
} else if (curve.get_point_count() == 0) {
text_color.a *= 0.4;
- draw_multiline_string(font, Vector2(50 * EDSCALE, font_height), TTR("Right click to add point"), HORIZONTAL_ALIGNMENT_LEFT, width, -1, font_size, text_color);
+ draw_multiline_string(font, Vector2(50 * EDSCALE, font_height), TTR("Right click to add point"), HORIZONTAL_ALIGNMENT_LEFT, width, font_size, -1, text_color);
}
}
@@ -799,13 +799,13 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons
Curve &curve = **curve_ref;
// FIXME: Should be ported to use p_size as done in b2633a97
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
Ref<Image> img_ref;
img_ref.instantiate();
Image &im = **img_ref;
- im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8);
+ im.initialize_data(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8);
Color bg_color(0.1, 0.1, 0.1, 1.0);
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 59b8f31720..997dc0b2b5 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -210,9 +210,7 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const Ref<Resource> &p_from,
}
}
- Ref<Image> img;
- img.instantiate();
- img->create(bm->get_size().width, bm->get_size().height, false, Image::FORMAT_L8, data);
+ Ref<Image> img = Image::create_from_data(bm->get_size().width, bm->get_size().height, false, Image::FORMAT_L8, data);
if (img->is_compressed()) {
if (img->decompress() != OK) {
@@ -483,17 +481,15 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
int line = 0;
int col = 0;
- Ref<Image> img;
- img.instantiate();
int thumbnail_size = MAX(p_size.x, p_size.y);
- img->create(thumbnail_size, thumbnail_size, false, Image::FORMAT_RGBA8);
+ Ref<Image> img = Image::create_empty(thumbnail_size, thumbnail_size, false, Image::FORMAT_RGBA8);
- Color bg_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/background_color");
- Color keyword_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/keyword_color");
- Color control_flow_keyword_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/control_flow_keyword_color");
- Color text_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/text_color");
- Color symbol_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/symbol_color");
- Color comment_color = EditorSettings::get_singleton()->get("text_editor/theme/highlighting/comment_color");
+ Color bg_color = EDITOR_GET("text_editor/theme/highlighting/background_color");
+ Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
+ Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
+ Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
+ Color symbol_color = EDITOR_GET("text_editor/theme/highlighting/symbol_color");
+ Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
if (bg_color.a == 0) {
bg_color = Color(0, 0, 0, 0);
@@ -660,9 +656,7 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const Ref<Resource> &p_f
//post_process_preview(img);
- Ref<Image> image;
- image.instantiate();
- image->create(w, h, false, Image::FORMAT_RGB8, img);
+ Ref<Image> image = Image::create_from_data(w, h, false, Image::FORMAT_RGB8, img);
return ImageTexture::create_from_image(image);
}
diff --git a/editor/plugins/editor_resource_conversion_plugin.cpp b/editor/plugins/editor_resource_conversion_plugin.cpp
index 91394dbac7..a5f12d1352 100644
--- a/editor/plugins/editor_resource_conversion_plugin.cpp
+++ b/editor/plugins/editor_resource_conversion_plugin.cpp
@@ -38,27 +38,18 @@ void EditorResourceConversionPlugin::_bind_methods() {
String EditorResourceConversionPlugin::converts_to() const {
String ret;
- if (GDVIRTUAL_CALL(_converts_to, ret)) {
- return ret;
- }
-
- return "";
+ GDVIRTUAL_CALL(_converts_to, ret);
+ return ret;
}
bool EditorResourceConversionPlugin::handles(const Ref<Resource> &p_resource) const {
- bool ret;
- if (GDVIRTUAL_CALL(_handles, p_resource, ret)) {
- return ret;
- }
-
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_handles, p_resource, ret);
+ return ret;
}
Ref<Resource> EditorResourceConversionPlugin::convert(const Ref<Resource> &p_resource) const {
Ref<Resource> ret;
- if (GDVIRTUAL_CALL(_convert, p_resource, ret)) {
- return ret;
- }
-
- return Ref<Resource>();
+ GDVIRTUAL_CALL(_convert, p_resource, ret);
+ return ret;
}
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index ba11479714..33992314b0 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -154,7 +154,7 @@ void EditorPropertyFontMetaOverride::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- if (Object::cast_to<Button>(button_add)) {
+ if (button_add) {
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
} break;
@@ -260,7 +260,7 @@ void EditorPropertyFontMetaOverride::update_property() {
} else {
// Queue children for deletion, deleting immediately might cause errors.
for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
- property_vbox->get_child(i)->queue_delete();
+ property_vbox->get_child(i)->queue_free();
}
button_add = nullptr;
}
@@ -457,7 +457,7 @@ void EditorPropertyOTVariation::update_property() {
} else {
// Queue children for deletion, deleting immediately might cause errors.
for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
- property_vbox->get_child(i)->queue_delete();
+ property_vbox->get_child(i)->queue_free();
}
}
@@ -549,7 +549,7 @@ void EditorPropertyOTFeatures::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
- if (Object::cast_to<Button>(button_add)) {
+ if (button_add) {
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
}
} break;
@@ -662,7 +662,7 @@ void EditorPropertyOTFeatures::update_property() {
} else {
// Queue children for deletion, deleting immediately might cause errors.
for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
- property_vbox->get_child(i)->queue_delete();
+ property_vbox->get_child(i)->queue_free();
}
button_add = nullptr;
}
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index e2d19c34e6..891b9efa4f 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -207,8 +207,8 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
int vpc = 0;
{
- Vector<uint8_t> data = img->get_data();
- const uint8_t *r = data.ptr();
+ Vector<uint8_t> img_data = img->get_data();
+ const uint8_t *r = img_data.ptr();
for (int i = 0; i < s.width; i++) {
for (int j = 0; j < s.height; j++) {
@@ -299,7 +299,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGF, texdata);
+ img->set_data(w, h, false, Image::FORMAT_RGF, texdata);
pm->set_emission_point_texture(ImageTexture::create_from_image(img));
pm->set_emission_point_count(vpc);
@@ -315,7 +315,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGBA8, colordata);
+ img->set_data(w, h, false, Image::FORMAT_RGBA8, colordata);
pm->set_emission_color_texture(ImageTexture::create_from_image(img));
}
@@ -335,7 +335,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGF, normdata);
+ img->set_data(w, h, false, Image::FORMAT_RGF, normdata);
pm->set_emission_normal_texture(ImageTexture::create_from_image(img));
} else {
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index d91cbb6571..db3a46d1f1 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -255,8 +255,8 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
}
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
- Ref<ParticleProcessMaterial> material = node->get_process_material();
- if (material.is_null()) {
+ Ref<ParticleProcessMaterial> mat = node->get_process_material();
+ if (mat.is_null()) {
EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticleProcessMaterial' is required."));
return;
}
@@ -366,13 +366,13 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
Ref<ImageTexture> tex = ImageTexture::create_from_image(image);
- Ref<ParticleProcessMaterial> material = node->get_process_material();
- ERR_FAIL_COND(material.is_null());
+ Ref<ParticleProcessMaterial> mat = node->get_process_material();
+ ERR_FAIL_COND(mat.is_null());
if (normals.size() > 0) {
- material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
- material->set_emission_point_count(point_count);
- material->set_emission_point_texture(tex);
+ mat->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ mat->set_emission_point_count(point_count);
+ mat->set_emission_point_texture(tex);
Vector<uint8_t> point_img2;
point_img2.resize(w * h * 3 * sizeof(float));
@@ -390,11 +390,11 @@ void GPUParticles3DEditor::_generate_emission_points() {
}
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
- material->set_emission_normal_texture(ImageTexture::create_from_image(image2));
+ mat->set_emission_normal_texture(ImageTexture::create_from_image(image2));
} else {
- material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
- material->set_emission_point_count(point_count);
- material->set_emission_point_texture(tex);
+ mat->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
+ mat->set_emission_point_count(point_count);
+ mat->set_emission_point_texture(tex);
}
}
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index c13b162db6..822f303d93 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -90,8 +90,8 @@ void GradientEditor::_gradient_changed() {
}
editing = true;
- Vector<Gradient::Point> points = gradient->get_points();
- set_points(points);
+ Vector<Gradient::Point> grad_points = gradient->get_points();
+ set_points(grad_points);
set_interpolation_mode(gradient->get_interpolation_mode());
queue_redraw();
editing = false;
diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp
index 153eab32d2..b67f0f6ad2 100644
--- a/editor/plugins/input_event_editor_plugin.cpp
+++ b/editor/plugins/input_event_editor_plugin.cpp
@@ -30,6 +30,9 @@
#include "input_event_editor_plugin.h"
+#include "editor/event_listener_line_edit.h"
+#include "editor/input_event_configuration_dialog.h"
+
void InputEventConfigContainer::_bind_methods() {
}
@@ -63,13 +66,13 @@ void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) {
Ref<InputEventJoypadMotion> jm = p_event;
if (k.is_valid()) {
- config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY);
+ config_dialog->set_allowed_input_types(INPUT_KEY);
} else if (m.is_valid()) {
- config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_MOUSE_BUTTON);
+ config_dialog->set_allowed_input_types(INPUT_MOUSE_BUTTON);
} else if (jb.is_valid()) {
- config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_BUTTON);
+ config_dialog->set_allowed_input_types(INPUT_JOY_BUTTON);
} else if (jm.is_valid()) {
- config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_MOTION);
+ config_dialog->set_allowed_input_types(INPUT_JOY_MOTION);
}
input_event = p_event;
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index 31053f90b8..d73761d770 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -51,9 +51,9 @@ void Line2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
}
void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
- Node2D *node = _get_node();
- undo_redo->add_do_method(node, "set_points", p_polygon);
- undo_redo->add_undo_method(node, "set_points", p_previous);
+ Node2D *_node = _get_node();
+ undo_redo->add_do_method(_node, "set_points", p_polygon);
+ undo_redo->add_undo_method(_node, "set_points", p_previous);
}
Line2DEditor::Line2DEditor() {}
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index c502d47669..d5cdb70ccf 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -270,6 +270,24 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
case MENU_OPTION_CREATE_OUTLINE_MESH: {
outline_dialog->popup_centered(Vector2(200, 90));
} break;
+ case MENU_OPTION_CREATE_DEBUG_TANGENTS: {
+ Ref<EditorUndoRedoManager> ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Create Debug Tangents"));
+
+ MeshInstance3D *tangents = node->create_debug_tangents_node();
+
+ if (tangents) {
+ Node *owner = get_tree()->get_edited_scene_root();
+
+ ur->add_do_reference(tangents);
+ ur->add_do_method(node, "add_child", tangents, true);
+ ur->add_do_method(tangents, "set_owner", owner);
+
+ ur->add_undo_method(node, "remove_child", tangents);
+ }
+
+ ur->commit_action();
+ } break;
case MENU_OPTION_CREATE_UV2: {
Ref<ArrayMesh> mesh2 = node->get_mesh();
if (!mesh2.is_valid()) {
@@ -511,6 +529,7 @@ MeshInstance3DEditor::MeshInstance3DEditor() {
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Outline Mesh..."), MENU_OPTION_CREATE_OUTLINE_MESH);
options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a static outline mesh. The outline mesh will have its normals flipped automatically.\nThis can be used instead of the StandardMaterial Grow property when using that property isn't possible."));
+ options->get_popup()->add_item(TTR("Create Debug Tangents"), MENU_OPTION_CREATE_DEBUG_TANGENTS);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
index 7968176744..88800227d1 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.h
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -46,6 +46,7 @@ class MeshInstance3DEditor : public Control {
MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES,
MENU_OPTION_CREATE_NAVMESH,
MENU_OPTION_CREATE_OUTLINE_MESH,
+ MENU_OPTION_CREATE_DEBUG_TANGENTS,
MENU_OPTION_CREATE_UV2,
MENU_OPTION_DEBUG_UV1,
MENU_OPTION_DEBUG_UV2,
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 420ebe5942..6654b03a0d 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -191,7 +191,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library,
}
}
- Vector<Ref<Texture2D>> textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EditorSettings::get_singleton()->get("editors/grid_map/preview_size"));
+ Vector<Ref<Texture2D>> textures = EditorInterface::get_singleton()->make_mesh_previews(meshes, &transforms, EDITOR_GET("editors/grid_map/preview_size"));
int j = 0;
for (int i = 0; i < ids.size(); i++) {
if (mesh_instances.find(ids[i])) {
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index ec6ea7f39b..0af2a13df2 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -110,7 +110,9 @@ void EditorNode3DGizmo::clear() {
collision_mesh = Ref<TriangleMesh>();
instances.clear();
handles.clear();
+ handle_ids.clear();
secondary_handles.clear();
+ secondary_handle_ids.clear();
}
void EditorNode3DGizmo::redraw() {
@@ -231,7 +233,7 @@ void EditorNode3DGizmo::commit_subgizmos(const Vector<int> &p_ids, const Vector<
gizmo_plugin->commit_subgizmos(this, p_ids, p_restore, p_cancel);
}
-void EditorNode3DGizmo::set_spatial_node(Node3D *p_node) {
+void EditorNode3DGizmo::set_node_3d(Node3D *p_node) {
ERR_FAIL_NULL(p_node);
spatial_node = p_node;
}
@@ -406,12 +408,15 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
return;
}
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
+
+ Vector<Vector3> &handle_list = p_secondary ? secondary_handles : handles;
+ Vector<int> &id_list = p_secondary ? secondary_handle_ids : handle_ids;
if (p_ids.is_empty()) {
- ERR_FAIL_COND_MSG((!handles.is_empty() && !handle_ids.is_empty()) || (!secondary_handles.is_empty() && !secondary_handle_ids.is_empty()), "Fail");
+ ERR_FAIL_COND_MSG(!id_list.is_empty(), "IDs must be provided for all handles, as handles with IDs already exist.");
} else {
- ERR_FAIL_COND_MSG(handles.size() != handle_ids.size() || secondary_handles.size() != secondary_handle_ids.size(), "Fail");
+ ERR_FAIL_COND_MSG(p_handles.size() != p_ids.size(), "The number of IDs should be the same as the number of handles.");
}
bool is_current_hover_gizmo = Node3DEditor::get_singleton()->get_current_hover_gizmo() == this;
@@ -464,19 +469,17 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
}
instances.push_back(ins);
- Vector<Vector3> &h = p_secondary ? secondary_handles : handles;
- int current_size = h.size();
- h.resize(current_size + p_handles.size());
+ int current_size = handle_list.size();
+ handle_list.resize(current_size + p_handles.size());
for (int i = 0; i < p_handles.size(); i++) {
- h.write[current_size + i] = p_handles[i];
+ handle_list.write[current_size + i] = p_handles[i];
}
if (!p_ids.is_empty()) {
- Vector<int> &ids = p_secondary ? secondary_handle_ids : handle_ids;
- current_size = ids.size();
- ids.resize(current_size + p_ids.size());
+ current_size = id_list.size();
+ id_list.resize(current_size + p_ids.size());
for (int i = 0; i < p_ids.size(); i++) {
- ids.write[current_size + i] = p_ids[i];
+ id_list.write[current_size + i] = p_ids[i];
}
}
}
@@ -839,8 +842,8 @@ void EditorNode3DGizmo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_collision_triangles", "triangles"), &EditorNode3DGizmo::add_collision_triangles);
ClassDB::bind_method(D_METHOD("add_unscaled_billboard", "material", "default_scale", "modulate"), &EditorNode3DGizmo::add_unscaled_billboard, DEFVAL(1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("add_handles", "handles", "material", "ids", "billboard", "secondary"), &EditorNode3DGizmo::add_handles, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorNode3DGizmo::_set_spatial_node);
- ClassDB::bind_method(D_METHOD("get_spatial_node"), &EditorNode3DGizmo::get_spatial_node);
+ ClassDB::bind_method(D_METHOD("set_node_3d", "node"), &EditorNode3DGizmo::_set_node_3d);
+ ClassDB::bind_method(D_METHOD("get_node_3d"), &EditorNode3DGizmo::get_node_3d);
ClassDB::bind_method(D_METHOD("get_plugin"), &EditorNode3DGizmo::get_plugin);
ClassDB::bind_method(D_METHOD("clear"), &EditorNode3DGizmo::clear);
ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorNode3DGizmo::set_hidden);
@@ -1039,7 +1042,7 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) {
}
ref->set_plugin(this);
- ref->set_spatial_node(p_spatial);
+ ref->set_node_3d(p_spatial);
ref->set_hidden(current_state == HIDDEN);
current_gizmos.push_back(ref.ptr());
@@ -1078,11 +1081,9 @@ void EditorNode3DGizmoPlugin::_bind_methods() {
}
bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- bool success;
- if (GDVIRTUAL_CALL(_has_gizmo, p_spatial, success)) {
- return success;
- }
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_has_gizmo, p_spatial, success);
+ return success;
}
Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial) {
@@ -1099,19 +1100,15 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial)
}
bool EditorNode3DGizmoPlugin::can_be_hidden() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_be_hidden, ret)) {
- return ret;
- }
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_can_be_hidden, ret);
+ return ret;
}
bool EditorNode3DGizmoPlugin::is_selectable_when_hidden() const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_selectable_when_hidden, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_is_selectable_when_hidden, ret);
+ return ret;
}
void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
@@ -1119,27 +1116,21 @@ void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_handle_highlighted, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_is_handle_highlighted, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
+ return ret;
}
String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
String ret;
- if (GDVIRTUAL_CALL(_get_handle_name, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
- return ret;
- }
- return "";
+ GDVIRTUAL_CALL(_get_handle_name, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
+ return ret;
}
Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
Variant ret;
- if (GDVIRTUAL_CALL(_get_handle_value, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret)) {
- return ret;
- }
- return Variant();
+ GDVIRTUAL_CALL(_get_handle_value, Ref<EditorNode3DGizmo>(p_gizmo), p_id, p_secondary, ret);
+ return ret;
}
void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -1151,34 +1142,26 @@ void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, in
}
int EditorNode3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
- int ret;
- if (GDVIRTUAL_CALL(_subgizmos_intersect_ray, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, p_point, ret)) {
- return ret;
- }
- return -1;
+ int ret = -1;
+ GDVIRTUAL_CALL(_subgizmos_intersect_ray, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, p_point, ret);
+ return ret;
}
Vector<int> EditorNode3DGizmoPlugin::subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const {
- TypedArray<Transform3D> frustum;
+ TypedArray<Plane> frustum;
frustum.resize(p_frustum.size());
for (int i = 0; i < p_frustum.size(); i++) {
frustum[i] = p_frustum[i];
}
Vector<int> ret;
- if (GDVIRTUAL_CALL(_subgizmos_intersect_frustum, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, frustum, ret)) {
- return ret;
- }
-
- return Vector<int>();
+ GDVIRTUAL_CALL(_subgizmos_intersect_frustum, Ref<EditorNode3DGizmo>(p_gizmo), p_camera, frustum, ret);
+ return ret;
}
Transform3D EditorNode3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
Transform3D ret;
- if (GDVIRTUAL_CALL(_get_subgizmo_transform, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret)) {
- return ret;
- }
-
- return Transform3D();
+ GDVIRTUAL_CALL(_get_subgizmo_transform, Ref<EditorNode3DGizmo>(p_gizmo), p_id, ret);
+ return ret;
}
void EditorNode3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
@@ -1217,7 +1200,7 @@ EditorNode3DGizmoPlugin::EditorNode3DGizmoPlugin() {
EditorNode3DGizmoPlugin::~EditorNode3DGizmoPlugin() {
for (int i = 0; i < current_gizmos.size(); ++i) {
current_gizmos[i]->set_plugin(nullptr);
- current_gizmos[i]->get_spatial_node()->remove_gizmo(current_gizmos[i]);
+ current_gizmos[i]->get_node_3d()->remove_gizmo(current_gizmos[i]);
}
if (Node3DEditor::get_singleton()) {
Node3DEditor::get_singleton()->update_all_gizmos();
@@ -1261,7 +1244,7 @@ String Light3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
}
Variant Light3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_node_3d());
if (p_id == 0) {
return light->get_param(Light3D::PARAM_RANGE);
}
@@ -1300,7 +1283,7 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
}
void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_node_3d());
Transform3D gt = light->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -1344,7 +1327,7 @@ void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_node_3d());
if (p_cancel) {
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1364,7 +1347,7 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
}
void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node());
+ Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_node_3d());
Color color = light->get_color().srgb_to_linear() * light->get_correlated_color().srgb_to_linear();
color = color.linear_to_srgb();
@@ -1526,12 +1509,12 @@ String AudioStreamPlayer3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *
}
Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
return player->get_emission_angle();
}
void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
Transform3D gt = player->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -1568,7 +1551,7 @@ void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo
}
void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+ AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
if (p_cancel) {
player->set_emission_angle(p_restore);
@@ -1583,7 +1566,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
}
void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node());
+ const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -1762,7 +1745,7 @@ int Camera3DGizmoPlugin::get_priority() const {
}
String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_node_3d());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
return "FOV";
@@ -1772,7 +1755,7 @@ String Camera3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, in
}
Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_node_3d());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
return camera->get_fov();
@@ -1782,7 +1765,7 @@ Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo,
}
void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_node_3d());
Transform3D gt = camera->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -1811,7 +1794,7 @@ void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_node_3d());
if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) {
if (p_cancel) {
@@ -1838,7 +1821,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
}
void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node());
+ Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -1937,6 +1920,7 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
#undef ADD_QUAD
p_gizmo->add_lines(lines, material);
+ p_gizmo->add_collision_segments(lines);
p_gizmo->add_handles(handles, get_material("handles"));
}
@@ -1962,7 +1946,7 @@ bool MeshInstance3DGizmoPlugin::can_be_hidden() const {
}
void MeshInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- MeshInstance3D *mesh = Object::cast_to<MeshInstance3D>(p_gizmo->get_spatial_node());
+ MeshInstance3D *mesh = Object::cast_to<MeshInstance3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -1998,7 +1982,7 @@ int OccluderInstance3DGizmoPlugin::get_priority() const {
}
String OccluderInstance3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- const OccluderInstance3D *cs = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+ const OccluderInstance3D *cs = Object::cast_to<OccluderInstance3D>(p_gizmo->get_node_3d());
Ref<Occluder3D> o = cs->get_occluder();
if (o.is_null()) {
@@ -2017,7 +2001,7 @@ String OccluderInstance3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p
}
Variant OccluderInstance3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_node_3d());
Ref<Occluder3D> o = oi->get_occluder();
if (o.is_null()) {
@@ -2043,7 +2027,7 @@ Variant OccluderInstance3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo
}
void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_node_3d());
Ref<Occluder3D> o = oi->get_occluder();
if (o.is_null()) {
@@ -2130,7 +2114,7 @@ void OccluderInstance3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo,
}
void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+ OccluderInstance3D *oi = Object::cast_to<OccluderInstance3D>(p_gizmo->get_node_3d());
Ref<Occluder3D> o = oi->get_occluder();
if (o.is_null()) {
@@ -2181,7 +2165,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
}
void OccluderInstance3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- OccluderInstance3D *occluder_instance = Object::cast_to<OccluderInstance3D>(p_gizmo->get_spatial_node());
+ OccluderInstance3D *occluder_instance = Object::cast_to<OccluderInstance3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2250,7 +2234,7 @@ bool Sprite3DGizmoPlugin::can_be_hidden() const {
}
void Sprite3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node());
+ Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2282,7 +2266,7 @@ bool Label3DGizmoPlugin::can_be_hidden() const {
}
void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Label3D *label = Object::cast_to<Label3D>(p_gizmo->get_spatial_node());
+ Label3D *label = Object::cast_to<Label3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2296,10 +2280,10 @@ void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
- cursor_points = Vector<Vector3>();
+ Vector<Vector3> cursor_points;
Vector<Color> cursor_colors;
- const float cs = 0.25;
+ const float cs = 1.0;
// Add more points to create a "hard stop" in the color gradient.
cursor_points.push_back(Vector3(+cs, 0, 0));
cursor_points.push_back(Vector3());
@@ -2367,9 +2351,22 @@ int Marker3DGizmoPlugin::get_priority() const {
}
void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ const Marker3D *marker = Object::cast_to<Marker3D>(p_gizmo->get_node_3d());
+ const real_t extents = marker->get_gizmo_extents();
+ const Transform3D xform(Basis::from_scale(Vector3(extents, extents, extents)));
+
p_gizmo->clear();
- p_gizmo->add_mesh(pos3d_mesh);
- p_gizmo->add_collision_segments(cursor_points);
+ p_gizmo->add_mesh(pos3d_mesh, Ref<Material>(), xform);
+
+ const Vector<Vector3> points = {
+ Vector3(-extents, 0, 0),
+ Vector3(+extents, 0, 0),
+ Vector3(0, -extents, 0),
+ Vector3(0, +extents, 0),
+ Vector3(0, 0, -extents),
+ Vector3(0, 0, +extents),
+ };
+ p_gizmo->add_collision_segments(points);
}
////
@@ -2393,7 +2390,7 @@ int PhysicalBone3DGizmoPlugin::get_priority() const {
void PhysicalBone3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
- PhysicalBone3D *physical_bone = Object::cast_to<PhysicalBone3D>(p_gizmo->get_spatial_node());
+ PhysicalBone3D *physical_bone = Object::cast_to<PhysicalBone3D>(p_gizmo->get_node_3d());
if (!physical_bone) {
return;
@@ -2528,7 +2525,7 @@ int RayCast3DGizmoPlugin::get_priority() const {
}
void RayCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- RayCast3D *raycast = Object::cast_to<RayCast3D>(p_gizmo->get_spatial_node());
+ RayCast3D *raycast = Object::cast_to<RayCast3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2566,7 +2563,7 @@ int ShapeCast3DGizmoPlugin::get_priority() const {
}
void ShapeCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- ShapeCast3D *shapecast = Object::cast_to<ShapeCast3D>(p_gizmo->get_spatial_node());
+ ShapeCast3D *shapecast = Object::cast_to<ShapeCast3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2584,7 +2581,7 @@ void ShapeCast3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
/////
void SpringArm3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- SpringArm3D *spring_arm = Object::cast_to<SpringArm3D>(p_gizmo->get_spatial_node());
+ SpringArm3D *spring_arm = Object::cast_to<SpringArm3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2636,7 +2633,7 @@ int VehicleWheel3DGizmoPlugin::get_priority() const {
}
void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- VehicleWheel3D *car_wheel = Object::cast_to<VehicleWheel3D>(p_gizmo->get_spatial_node());
+ VehicleWheel3D *car_wheel = Object::cast_to<VehicleWheel3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2712,7 +2709,7 @@ bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const {
}
void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -2753,17 +2750,17 @@ String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo,
}
Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_node_3d());
return Variant(soft_body->is_point_pinned(p_id));
}
void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_node_3d());
soft_body->pin_point_toggle(p_id);
}
bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_node_3d());
return soft_body->is_point_pinned(p_id);
}
@@ -2809,12 +2806,12 @@ String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DG
}
Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
+ VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
return notifier->get_aabb();
}
void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
+ VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
Transform3D gt = notifier->get_global_transform();
@@ -2866,7 +2863,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p
}
void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
+ VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
if (p_cancel) {
notifier->set_aabb(p_restore);
@@ -2881,7 +2878,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo
}
void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node());
+ VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -3001,12 +2998,12 @@ String GPUParticles3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_giz
}
Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
return particles->get_visibility_aabb();
}
void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
Transform3D gt = particles->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -3057,7 +3054,7 @@ void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int
}
void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
if (p_cancel) {
particles->set_visibility_aabb(p_restore);
@@ -3072,7 +3069,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
}
void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node());
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -3148,7 +3145,7 @@ int GPUParticlesCollision3DGizmoPlugin::get_priority() const {
}
String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- const Node3D *cs = p_gizmo->get_spatial_node();
+ const Node3D *cs = p_gizmo->get_node_3d();
if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
return "Radius";
@@ -3162,21 +3159,21 @@ String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGiz
}
Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- const Node3D *cs = p_gizmo->get_spatial_node();
+ const Node3D *cs = p_gizmo->get_node_3d();
if (Object::cast_to<GPUParticlesCollisionSphere3D>(cs) || Object::cast_to<GPUParticlesAttractorSphere3D>(cs)) {
- return p_gizmo->get_spatial_node()->call("get_radius");
+ return p_gizmo->get_node_3d()->call("get_radius");
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
- return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
+ return Vector3(p_gizmo->get_node_3d()->call("get_extents"));
}
return Variant();
}
void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- Node3D *sn = p_gizmo->get_spatial_node();
+ Node3D *sn = p_gizmo->get_node_3d();
Transform3D gt = sn->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -3222,7 +3219,7 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
}
void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Node3D *sn = p_gizmo->get_spatial_node();
+ Node3D *sn = p_gizmo->get_node_3d();
if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
if (p_cancel) {
@@ -3252,7 +3249,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
}
void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Node3D *cs = p_gizmo->get_spatial_node();
+ Node3D *cs = p_gizmo->get_node_3d();
p_gizmo->clear();
@@ -3430,12 +3427,12 @@ String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gi
}
Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
return AABB(probe->get_extents(), probe->get_origin_offset());
}
void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
Transform3D gt = probe->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -3492,7 +3489,7 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
}
void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
AABB restore = p_restore;
@@ -3512,7 +3509,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
}
void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node());
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -3609,12 +3606,12 @@ String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p
}
Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
return decal->get_extents();
}
void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
Transform3D gt = decal->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -3645,7 +3642,7 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bo
}
void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
Vector3 restore = p_restore;
@@ -3662,7 +3659,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node());
+ Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -3749,12 +3746,12 @@ String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int
}
Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
return probe->get_extents();
}
void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
Transform3D gt = probe->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -3785,7 +3782,7 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
}
void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
Vector3 restore = p_restore;
@@ -3802,7 +3799,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
}
void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node());
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
Ref<Material> material = get_material("voxel_gi_material", p_gizmo);
Ref<Material> icon = get_material("voxel_gi_icon", p_gizmo);
@@ -3913,7 +3910,7 @@ int LightmapGIGizmoPlugin::get_priority() const {
void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo);
- LightmapGI *baker = Object::cast_to<LightmapGI>(p_gizmo->get_spatial_node());
+ LightmapGI *baker = Object::cast_to<LightmapGI>(p_gizmo->get_node_3d());
Ref<LightmapGIData> data = baker->get_light_data();
p_gizmo->add_unscaled_billboard(icon, 0.05);
@@ -4163,13 +4160,13 @@ int CollisionObject3DGizmoPlugin::get_priority() const {
}
void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_gizmo->get_spatial_node());
+ CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
- List<uint32_t> owners;
- co->get_shape_owners(&owners);
- for (uint32_t &owner_id : owners) {
+ List<uint32_t> owner_ids;
+ co->get_shape_owners(&owner_ids);
+ for (uint32_t &owner_id : owner_ids) {
Transform3D xform = co->shape_owner_get_transform(owner_id);
Object *owner = co->shape_owner_get_owner(owner_id);
// Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo.
@@ -4214,7 +4211,7 @@ int CollisionShape3DGizmoPlugin::get_priority() const {
}
String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- const CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+ const CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d());
Ref<Shape3D> s = cs->get_shape();
if (s.is_null()) {
@@ -4245,7 +4242,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
}
Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d());
Ref<Shape3D> s = cs->get_shape();
if (s.is_null()) {
@@ -4281,7 +4278,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p
}
void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d());
Ref<Shape3D> s = cs->get_shape();
if (s.is_null()) {
@@ -4395,7 +4392,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d());
Ref<Shape3D> s = cs->get_shape();
if (s.is_null()) {
@@ -4499,7 +4496,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
}
void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node());
+ CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -4751,9 +4748,9 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (err == OK) {
Vector<Vector3> points2;
points2.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- points2.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- points2.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ for (uint32_t i = 0; i < md.edges.size(); i++) {
+ points2.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
+ points2.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
p_gizmo->add_lines(points2, material);
@@ -4814,7 +4811,7 @@ int CollisionPolygon3DGizmoPlugin::get_priority() const {
}
void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- CollisionPolygon3D *polygon = Object::cast_to<CollisionPolygon3D>(p_gizmo->get_spatial_node());
+ CollisionPolygon3D *polygon = Object::cast_to<CollisionPolygon3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -4861,7 +4858,7 @@ int NavigationRegion3DGizmoPlugin::get_priority() const {
}
void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- NavigationRegion3D *navigationregion = Object::cast_to<NavigationRegion3D>(p_gizmo->get_spatial_node());
+ NavigationRegion3D *navigationregion = Object::cast_to<NavigationRegion3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
Ref<NavigationMesh> navigationmesh = navigationregion->get_navigation_mesh();
@@ -5021,7 +5018,7 @@ int NavigationLink3DGizmoPlugin::get_priority() const {
}
void NavigationLink3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d());
RID nav_map = link->get_world_3d()->get_navigation_map();
real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map);
@@ -5106,12 +5103,12 @@ String NavigationLink3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
}
Variant NavigationLink3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d());
return p_id == 0 ? link->get_start_location() : link->get_end_location();
}
void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d());
Transform3D gt = link->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -5144,7 +5141,7 @@ void NavigationLink3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_spatial_node());
+ NavigationLink3D *link = Object::cast_to<NavigationLink3D>(p_gizmo->get_node_3d());
if (p_cancel) {
if (p_id == 0) {
@@ -5444,7 +5441,7 @@ int Joint3DGizmoPlugin::get_priority() const {
}
void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Joint3D *joint = Object::cast_to<Joint3D>(p_gizmo->get_spatial_node());
+ Joint3D *joint = Object::cast_to<Joint3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
@@ -5877,11 +5874,11 @@ String FogVolumeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, i
}
Variant FogVolumeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- return Vector3(p_gizmo->get_spatial_node()->call("get_extents"));
+ return Vector3(p_gizmo->get_node_3d()->call("get_extents"));
}
void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- Node3D *sn = p_gizmo->get_spatial_node();
+ Node3D *sn = p_gizmo->get_node_3d();
Transform3D gt = sn->get_global_transform();
Transform3D gi = gt.affine_inverse();
@@ -5910,7 +5907,7 @@ void FogVolumeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id
}
void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Node3D *sn = p_gizmo->get_spatial_node();
+ Node3D *sn = p_gizmo->get_node_3d();
if (p_cancel) {
sn->call("set_extents", p_restore);
@@ -5925,11 +5922,11 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p
}
void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Node3D *cs = p_gizmo->get_spatial_node();
+ Node3D *cs = p_gizmo->get_node_3d();
p_gizmo->clear();
- if (RS::FogVolumeShape(int(p_gizmo->get_spatial_node()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) {
+ if (RS::FogVolumeShape(int(p_gizmo->get_node_3d()->call("get_shape"))) != RS::FOG_VOLUME_SHAPE_WORLD) {
const Ref<Material> material =
get_material("shape_material", p_gizmo);
const Ref<Material> material_internal =
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 5924f8571a..d7e3e03f61 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -72,7 +72,7 @@ class EditorNode3DGizmo : public Node3DGizmo {
Vector<Instance> instances;
Node3D *spatial_node = nullptr;
- void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Node3D>(p_node)); }
+ void _set_node_3d(Node *p_node) { set_node_3d(Object::cast_to<Node3D>(p_node)); }
protected:
static void _bind_methods();
@@ -116,8 +116,8 @@ public:
void set_selected(bool p_selected) { selected = p_selected; }
bool is_selected() const { return selected; }
- void set_spatial_node(Node3D *p_node);
- Node3D *get_spatial_node() const { return spatial_node; }
+ void set_node_3d(Node3D *p_node);
+ Node3D *get_node_3d() const { return spatial_node; }
Ref<EditorNode3DGizmoPlugin> get_plugin() const { return gizmo_plugin; }
bool intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum);
void handles_intersect_ray(Camera3D *p_camera, const Vector2 &p_point, bool p_shift_pressed, int &r_id, bool &r_secondary);
@@ -338,7 +338,6 @@ class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin);
Ref<ArrayMesh> pos3d_mesh;
- Vector<Vector3> cursor_points;
public:
bool has_gizmo(Node3D *p_spatial) override;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 33aad0ac61..6a9568b2a2 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -939,7 +939,7 @@ void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
}
static Key _get_key_modifier_setting(const String &p_property) {
- switch (EditorSettings::get_singleton()->get(p_property).operator int()) {
+ switch (EDITOR_GET(p_property).operator int()) {
case 0:
return Key::NONE;
case 1:
@@ -1356,7 +1356,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
EditorNode *en = EditorNode::get_singleton();
EditorPluginList *force_input_forwarding_list = en->get_editor_plugins_force_input_forwarding();
if (!force_input_forwarding_list->is_empty()) {
- EditorPlugin::AfterGUIInput discard = force_input_forwarding_list->forward_spatial_gui_input(camera, p_event, true);
+ EditorPlugin::AfterGUIInput discard = force_input_forwarding_list->forward_3d_gui_input(camera, p_event, true);
if (discard == EditorPlugin::AFTER_GUI_INPUT_STOP) {
return;
}
@@ -1369,7 +1369,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
EditorNode *en = EditorNode::get_singleton();
EditorPluginList *over_plugin_list = en->get_editor_plugins_over();
if (!over_plugin_list->is_empty()) {
- EditorPlugin::AfterGUIInput discard = over_plugin_list->forward_spatial_gui_input(camera, p_event, false);
+ EditorPlugin::AfterGUIInput discard = over_plugin_list->forward_3d_gui_input(camera, p_event, false);
if (discard == EditorPlugin::AFTER_GUI_INPUT_STOP) {
return;
}
@@ -1401,7 +1401,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
} break;
case MouseButton::RIGHT: {
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
if (b->is_pressed() && _edit.gizmo.is_valid()) {
//restore
@@ -1481,7 +1481,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
commit_transform();
break; // just commit the edit, stop processing the event so we don't deselect the object
}
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == NAVIGATION_MAYA || nav_scheme == NAVIGATION_MODO) && b->is_alt_pressed()) {
break;
}
@@ -1650,12 +1650,12 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
se->gizmo->commit_subgizmos(ids, restore, false);
- spatial_editor->update_transform_gizmo();
} else {
commit_transform();
}
_edit.mode = TRANSFORM_NONE;
set_message("");
+ spatial_editor->update_transform_gizmo();
}
surface->queue_redraw();
}
@@ -1709,7 +1709,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_transform_gizmo_select(_edit.mouse_pos, true);
}
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
NavigationMode nav_mode = NAVIGATION_NONE;
if (_edit.gizmo.is_valid()) {
@@ -1782,7 +1782,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_PAN;
}
}
- } else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) {
+ } else if (EDITOR_GET("editors/3d/navigation/emulate_3_button_mouse")) {
// Handle trackpad (no external mouse) use case
const Key mod = _get_key_modifier(m);
@@ -1835,7 +1835,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid()) {
- NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
NavigationMode nav_mode = NAVIGATION_NONE;
if (nav_scheme == NAVIGATION_GODOT) {
@@ -1889,7 +1889,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
return;
}
- if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_numpad")) {
+ if (EDITOR_GET("editors/3d/navigation/emulate_numpad")) {
const Key code = k->get_physical_keycode();
if (code >= Key::KEY_0 && code <= Key::KEY_9) {
k->set_keycode(code - Key::KEY_0 + Key::KP_0);
@@ -2086,7 +2086,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
- const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ const NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
real_t pan_speed = 1 / 150.0;
if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
@@ -2098,8 +2098,8 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const
camera_transform.translate_local(cursor.pos);
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
- const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
- const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ const bool invert_x_axis = EDITOR_GET("editors/3d/navigation/invert_x_axis");
+ const bool invert_y_axis = EDITOR_GET("editors/3d/navigation/invert_y_axis");
Vector3 translation(
(invert_x_axis ? -1 : 1) * -p_relative.x * pan_speed,
(invert_y_axis ? -1 : 1) * p_relative.y * pan_speed,
@@ -2110,14 +2110,14 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const
}
void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
- const NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ const NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
real_t zoom_speed = 1 / 80.0;
if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) {
zoom_speed *= 10;
}
- NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/navigation/zoom_style").operator int();
+ NavigationZoomStyle zoom_style = (NavigationZoomStyle)EDITOR_GET("editors/3d/navigation/zoom_style").operator int();
if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) {
if (p_relative.x > 0) {
scale_cursor_distance(1 - p_relative.x * zoom_speed);
@@ -2143,10 +2143,10 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
_menu_option(VIEW_PERSPECTIVE);
}
- const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ const real_t degrees_per_pixel = EDITOR_GET("editors/3d/navigation_feel/orbit_sensitivity");
const real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
- const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
- const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
+ const bool invert_y_axis = EDITOR_GET("editors/3d/navigation/invert_y_axis");
+ const bool invert_x_axis = EDITOR_GET("editors/3d/navigation/invert_x_axis");
if (invert_y_axis) {
cursor.x_rot -= p_relative.y * radians_per_pixel;
@@ -2176,9 +2176,9 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
}
// Scale mouse sensitivity with camera FOV scale when zoomed in to make it easier to point at things.
- const real_t degrees_per_pixel = real_t(EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity")) * MIN(1.0, cursor.fov_scale);
+ const real_t degrees_per_pixel = real_t(EDITOR_GET("editors/3d/freelook/freelook_sensitivity")) * MIN(1.0, cursor.fov_scale);
const real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
- const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
+ const bool invert_y_axis = EDITOR_GET("editors/3d/navigation/invert_y_axis");
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
const Transform3D prev_camera_transform = to_camera_transform(cursor);
@@ -2215,9 +2215,9 @@ void Node3DEditorViewport::set_freelook_active(bool active_now) {
// Also sync the camera cursor, otherwise switching to freelook will be trippy if inertia is active
camera_cursor.eye_pos = cursor.eye_pos;
- if (EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_speed_zoom_link")) {
+ if (EDITOR_GET("editors/3d/freelook/freelook_speed_zoom_link")) {
// Re-adjust freelook speed from the current zoom level
- real_t base_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
+ real_t base_speed = EDITOR_GET("editors/3d/freelook/freelook_base_speed");
freelook_speed = base_speed * cursor.distance;
}
@@ -2299,7 +2299,7 @@ void Node3DEditorViewport::_update_freelook(real_t delta) {
return;
}
- const FreelookNavigationScheme navigation_scheme = (FreelookNavigationScheme)EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_navigation_scheme").operator int();
+ const FreelookNavigationScheme navigation_scheme = (FreelookNavigationScheme)EDITOR_GET("editors/3d/freelook/freelook_navigation_scheme").operator int();
Vector3 forward;
if (navigation_scheme == FREELOOK_FULLY_AXIS_LOCKED) {
@@ -2375,12 +2375,12 @@ void Node3DEditorPlugin::edited_scene_changed() {
void Node3DEditorViewport::_project_settings_changed() {
//update shadow atlas if changed
- int shadowmap_size = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_size");
- bool shadowmap_16_bits = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
- int atlas_q0 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv");
- int atlas_q1 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv");
- int atlas_q2 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv");
- int atlas_q3 = ProjectSettings::get_singleton()->get("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv");
+ int shadowmap_size = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_size");
+ bool shadowmap_16_bits = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
+ int atlas_q0 = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv");
+ int atlas_q1 = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv");
+ int atlas_q2 = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv");
+ int atlas_q3 = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv");
viewport->set_positional_shadow_atlas_size(shadowmap_size);
viewport->set_positional_shadow_atlas_16_bits(shadowmap_16_bits);
@@ -2393,13 +2393,16 @@ void Node3DEditorViewport::_project_settings_changed() {
// Update MSAA, screen-space AA and debanding if changed
- const int msaa_mode = ProjectSettings::get_singleton()->get("rendering/anti_aliasing/quality/msaa_3d");
+ const int msaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_3d");
viewport->set_msaa_3d(Viewport::MSAA(msaa_mode));
const int ssaa_mode = GLOBAL_GET("rendering/anti_aliasing/quality/screen_space_aa");
viewport->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
const bool use_taa = GLOBAL_GET("rendering/anti_aliasing/quality/use_taa");
viewport->set_use_taa(use_taa);
+ const bool transparent_background = GLOBAL_GET("rendering/transparent_background");
+ viewport->set_transparent_background(transparent_background);
+
const bool use_debanding = GLOBAL_GET("rendering/anti_aliasing/quality/use_debanding");
viewport->set_use_debanding(use_debanding);
@@ -2429,11 +2432,12 @@ void Node3DEditorViewport::_notification(int p_what) {
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- bool visible = is_visible_in_tree();
+ bool vp_visible = is_visible_in_tree();
- set_process(visible);
+ set_process(vp_visible);
+ set_physics_process(vp_visible);
- if (visible) {
+ if (vp_visible) {
orthogonal = view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(VIEW_ORTHOGONAL));
_update_name();
_update_camera(0);
@@ -2441,7 +2445,7 @@ void Node3DEditorViewport::_notification(int p_what) {
set_freelook_active(false);
}
call_deferred(SNAME("update_transform_gizmo_view"));
- rotation_control->set_visible(EditorSettings::get_singleton()->get("editors/3d/navigation/show_viewport_rotation_gizmo"));
+ rotation_control->set_visible(EDITOR_GET("editors/3d/navigation/show_viewport_rotation_gizmo"));
} break;
case NOTIFICATION_RESIZED: {
@@ -2655,6 +2659,21 @@ void Node3DEditorViewport::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (!update_preview_node) {
+ return;
+ }
+ if (preview_node->is_inside_tree()) {
+ preview_node_pos = spatial_editor->snap_point(_get_instance_position(preview_node_viewport_pos));
+ Transform3D preview_gl_transform = Transform3D(Basis(), preview_node_pos);
+ preview_node->set_global_transform(preview_gl_transform);
+ if (!preview_node->is_visible()) {
+ preview_node->show();
+ }
+ }
+ update_preview_node = false;
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
surface->connect("draw", callable_mp(this, &Node3DEditorViewport::_draw));
surface->connect("gui_input", callable_mp(this, &Node3DEditorViewport::_sinput));
@@ -2735,12 +2754,12 @@ static void draw_indicator_bar(Control &p_surface, real_t p_fill, const Ref<Text
void Node3DEditorViewport::_draw() {
EditorPluginList *over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_over();
if (!over_plugin_list->is_empty()) {
- over_plugin_list->forward_spatial_draw_over_viewport(surface);
+ over_plugin_list->forward_3d_draw_over_viewport(surface);
}
EditorPluginList *force_over_plugin_list = EditorNode::get_singleton()->get_editor_plugins_force_over();
if (!force_over_plugin_list->is_empty()) {
- force_over_plugin_list->forward_spatial_force_draw_over_viewport(surface);
+ force_over_plugin_list->forward_3d_force_draw_over_viewport(surface);
}
if (surface->has_focus()) {
@@ -2802,7 +2821,7 @@ void Node3DEditorViewport::_draw() {
Math::round(2 * EDSCALE));
}
if (previewing) {
- Size2 ss = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ Size2 ss = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
float aspect = ss.aspect();
Size2 s = get_size();
@@ -2967,7 +2986,7 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Transform3D xform;
if (orthogonal) {
xform = sp->get_global_transform();
- xform.basis.set_euler(camera_transform.basis.get_euler());
+ xform.basis = Basis::from_euler(camera_transform.basis.get_euler());
} else {
xform = camera_transform;
xform.scale_basis(sp->get_scale());
@@ -3445,7 +3464,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
const real_t d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
const real_t dd = MAX(Math::abs(d0 - d1), CMP_EPSILON);
- const real_t gizmo_size = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size");
+ const real_t gizmo_size = EDITOR_GET("editors/3d/manipulator_gizmo_size");
// At low viewport heights, multiply the gizmo scale based on the viewport height.
// This prevents the gizmo from growing very large and going outside the viewport.
const int viewport_base_height = 400 * MAX(1, EDSCALE);
@@ -3729,24 +3748,45 @@ void Node3DEditorViewport::assign_pending_data_pointers(Node3D *p_preview_node,
Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const {
const float MAX_DISTANCE = 50.0;
+ const float FALLBACK_DISTANCE = 5.0;
Vector3 world_ray = _get_ray(p_pos);
Vector3 world_pos = _get_ray_pos(p_pos);
- Vector3 point = world_pos + world_ray * MAX_DISTANCE;
-
PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state();
PhysicsDirectSpaceState3D::RayParameters ray_params;
ray_params.from = world_pos;
- ray_params.to = world_pos + world_ray * MAX_DISTANCE;
+ ray_params.to = world_pos + world_ray * camera->get_far();
PhysicsDirectSpaceState3D::RayResult result;
if (ss->intersect_ray(ray_params, result)) {
- point = result.position;
+ return result.position;
+ }
+
+ const bool is_orthogonal = camera->get_projection() == Camera3D::PROJECTION_ORTHOGONAL;
+
+ // The XZ plane.
+ Vector3 intersection;
+ Plane plane(Vector3(0, 1, 0));
+ if (plane.intersects_ray(world_pos, world_ray, &intersection)) {
+ if (is_orthogonal || world_pos.distance_to(intersection) <= MAX_DISTANCE) {
+ return intersection;
+ }
}
- return point;
+ // Plane facing the camera using fallback distance.
+ if (is_orthogonal) {
+ plane = Plane(world_ray, cursor.pos - world_ray * (cursor.distance - FALLBACK_DISTANCE));
+ } else {
+ plane = Plane(world_ray, world_pos + world_ray * FALLBACK_DISTANCE);
+ }
+ if (plane.intersects_ray(world_pos, world_ray, &intersection)) {
+ return intersection;
+ }
+
+ // Not likely, but just in case...
+ return world_pos + world_ray * FALLBACK_DISTANCE;
}
AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform) {
@@ -3762,7 +3802,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
if (child) {
AABB child_bounds = _calculate_spatial_bounds(child, false);
- if (bounds.size == Vector3() && Object::cast_to<Node3D>(p_parent)) {
+ if (bounds.size == Vector3() && p_parent) {
bounds = child_bounds;
} else {
bounds.merge_with(child_bounds);
@@ -3770,7 +3810,7 @@ AABB Node3DEditorViewport::_calculate_spatial_bounds(const Node3D *p_parent, boo
}
}
- if (bounds.size == Vector3() && !Object::cast_to<Node3D>(p_parent)) {
+ if (bounds.size == Vector3() && !p_parent) {
bounds = AABB(Vector3(-0.2, -0.2, -0.2), Vector3(0.4, 0.4, 0.4));
}
@@ -3843,7 +3883,7 @@ void Node3DEditorViewport::_remove_preview_node() {
if (preview_node->get_parent()) {
for (int i = preview_node->get_child_count() - 1; i >= 0; i--) {
Node *node = preview_node->get_child(i);
- node->queue_delete();
+ node->queue_free();
preview_node->remove_child(node);
}
EditorNode::get_singleton()->get_scene_root()->remove_child(preview_node);
@@ -3880,8 +3920,8 @@ bool Node3DEditorViewport::_apply_preview_material(ObjectID p_target, const Poin
Vector3 xform_ray = ai.basis.xform(world_ray).normalized();
Vector3 xform_pos = ai.xform(world_pos);
- for (int surface = 0; surface < surface_count; surface++) {
- Ref<TriangleMesh> surface_mesh = mesh->generate_surface_triangle_mesh(surface);
+ for (int surface_idx = 0; surface_idx < surface_count; surface_idx++) {
+ Ref<TriangleMesh> surface_mesh = mesh->generate_surface_triangle_mesh(surface_idx);
Vector3 rpos, rnorm;
if (surface_mesh->intersect_ray(xform_pos, xform_ray, rpos, rnorm)) {
@@ -3894,7 +3934,7 @@ bool Node3DEditorViewport::_apply_preview_material(ObjectID p_target, const Poin
}
if (dist < closest_dist) {
- closest_surface = surface;
+ closest_surface = surface_idx;
closest_dist = dist;
}
}
@@ -4020,16 +4060,16 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene);
if (node3d) {
- Transform3D global_transform;
+ Transform3D gl_transform;
Node3D *parent_node3d = Object::cast_to<Node3D>(parent);
if (parent_node3d) {
- global_transform = parent_node3d->get_global_gizmo_transform();
+ gl_transform = parent_node3d->get_global_gizmo_transform();
}
- global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
- global_transform.basis *= node3d->get_transform().basis;
+ gl_transform.origin = preview_node_pos;
+ gl_transform.basis *= node3d->get_transform().basis;
- editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", global_transform);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", gl_transform);
}
return true;
@@ -4090,7 +4130,9 @@ void Node3DEditorViewport::_perform_drop_data() {
}
}
-bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ preview_node_viewport_pos = p_point;
+
bool can_instantiate = false;
if (!preview_node->is_inside_tree() && spatial_editor->get_preview_material().is_null()) {
@@ -4108,11 +4150,13 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
ResourceLoader::get_recognized_extensions_for_type("Texture", &texture_extensions);
for (int i = 0; i < files.size(); i++) {
+ String extension = files[i].get_extension().to_lower();
+
// Check if dragged files with mesh or scene extension can be created at least once.
- if (mesh_extensions.find(files[i].get_extension()) ||
- scene_extensions.find(files[i].get_extension()) ||
- material_extensions.find(files[i].get_extension()) ||
- texture_extensions.find(files[i].get_extension())) {
+ if (mesh_extensions.find(extension) ||
+ scene_extensions.find(extension) ||
+ material_extensions.find(extension) ||
+ texture_extensions.find(extension)) {
Ref<Resource> res = ResourceLoader::load(files[i]);
if (res.is_null()) {
continue;
@@ -4154,6 +4198,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
_create_preview_node(files);
+ preview_node->hide();
}
}
} else {
@@ -4163,8 +4208,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
}
if (can_instantiate) {
- Transform3D global_transform = Transform3D(Basis(), _get_instance_position(p_point));
- preview_node->set_global_transform(global_transform);
+ update_preview_node = true;
return true;
}
@@ -4773,10 +4817,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->get_popup()->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option));
display_submenu->connect("id_pressed", callable_mp(this, &Node3DEditorViewport::_menu_option));
view_menu->set_disable_shortcuts(true);
-#ifndef _MSC_VER
-#warning this needs to be fixed
-#endif
- //if (OS::get_singleton()->get_current_video_driver() == OS::VIDEO_DRIVER_GLES2) {
+
+ // TODO: Re-evaluate with new OpenGL3 renderer, and implement.
+ //if (OS::get_singleton()->get_current_video_driver() == OS::RENDERING_DRIVER_OPENGL3) {
if (false) {
// Alternate display modes only work when using the Vulkan renderer; make this explicit.
const int normal_idx = view_menu->get_popup()->get_item_index(VIEW_DISPLAY_NORMAL);
@@ -4918,7 +4961,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
accept = nullptr;
freelook_active = false;
- freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
+ freelook_speed = EDITOR_GET("editors/3d/freelook/freelook_base_speed");
selection_menu = memnew(PopupMenu);
add_child(selection_menu);
@@ -6171,9 +6214,9 @@ void fragment() {
grid_mat[i]->set_shader(grid_shader);
}
- grid_enable[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
- grid_enable[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
- grid_enable[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
+ grid_enable[0] = EDITOR_GET("editors/3d/grid_xy_plane");
+ grid_enable[1] = EDITOR_GET("editors/3d/grid_yz_plane");
+ grid_enable[2] = EDITOR_GET("editors/3d/grid_xz_plane");
grid_visible[0] = grid_enable[0];
grid_visible[1] = grid_enable[1];
grid_visible[2] = grid_enable[2];
@@ -6223,7 +6266,7 @@ void fragment() {
break;
}
- col.a = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_opacity");
+ col.a = EDITOR_GET("editors/3d/manipulator_gizmo_opacity");
move_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
move_plane_gizmo[i] = Ref<ArrayMesh>(memnew(ArrayMesh));
@@ -6639,23 +6682,23 @@ void Node3DEditor::_init_grid() {
Vector<Vector3> grid_points[3];
Vector<Vector3> grid_normals[3];
- Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color");
- Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color");
- int grid_size = EditorSettings::get_singleton()->get("editors/3d/grid_size");
- int primary_grid_steps = EditorSettings::get_singleton()->get("editors/3d/primary_grid_steps");
+ Color primary_grid_color = EDITOR_GET("editors/3d/primary_grid_color");
+ Color secondary_grid_color = EDITOR_GET("editors/3d/secondary_grid_color");
+ int grid_size = EDITOR_GET("editors/3d/grid_size");
+ int primary_grid_steps = EDITOR_GET("editors/3d/primary_grid_steps");
// Which grid planes are enabled? Which should we generate?
- grid_enable[0] = grid_visible[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
- grid_enable[1] = grid_visible[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
- grid_enable[2] = grid_visible[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
+ grid_enable[0] = grid_visible[0] = EDITOR_GET("editors/3d/grid_xy_plane");
+ grid_enable[1] = grid_visible[1] = EDITOR_GET("editors/3d/grid_yz_plane");
+ grid_enable[2] = grid_visible[2] = EDITOR_GET("editors/3d/grid_xz_plane");
// Offsets division_level for bigger or smaller grids.
// Default value is -0.2. -1.0 gives Blender-like behavior, 0.5 gives huge grids.
- real_t division_level_bias = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_bias");
+ real_t division_level_bias = EDITOR_GET("editors/3d/grid_division_level_bias");
// Default largest grid size is 8^2 when primary_grid_steps is 8 (64m apart, so primary grid lines are 512m apart).
- int division_level_max = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_max");
+ int division_level_max = EDITOR_GET("editors/3d/grid_division_level_max");
// Default smallest grid size is 1cm, 10^-2 (default value is -2).
- int division_level_min = EditorSettings::get_singleton()->get("editors/3d/grid_division_level_min");
+ int division_level_min = EDITOR_GET("editors/3d/grid_division_level_min");
ERR_FAIL_COND_MSG(division_level_max < division_level_min, "The 3D grid's maximum division level cannot be lower than its minimum division level.");
if (primary_grid_steps != 10) { // Log10 of 10 is 1.
@@ -6930,6 +6973,10 @@ HashSet<RID> _get_physics_bodies_rid(Node *node) {
}
void Node3DEditor::snap_selected_nodes_to_floor() {
+ do_snap_selected_nodes_to_floor = true;
+}
+
+void Node3DEditor::_snap_selected_nodes_to_floor() {
const List<Node *> &selection = editor_selection->get_selected_node_list();
Dictionary snap_data;
@@ -6967,9 +7014,10 @@ void Node3DEditor::snap_selected_nodes_to_floor() {
}
}
if (!found_valid_shape && vi.size()) {
- AABB aabb = (*vi.begin())->get_transformed_aabb();
+ VisualInstance3D *begin = *vi.begin();
+ AABB aabb = begin->get_global_transform().xform(begin->get_aabb());
for (const VisualInstance3D *I : vi) {
- aabb.merge_with(I->get_transformed_aabb());
+ aabb.merge_with(I->get_global_transform().xform(I->get_aabb()));
}
Vector3 size = aabb.size * Vector3(0.5, 0.0, 0.5);
from = aabb.position + size;
@@ -7227,6 +7275,13 @@ void Node3DEditor::_notification(int p_what) {
tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
}
} break;
+
+ case NOTIFICATION_PHYSICS_PROCESS: {
+ if (do_snap_selected_nodes_to_floor) {
+ _snap_selected_nodes_to_floor();
+ do_snap_selected_nodes_to_floor = false;
+ }
+ }
}
}
@@ -7583,7 +7638,7 @@ void Node3DEditor::_preview_settings_changed() {
{ // preview sun
Transform3D t;
- t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0));
+ t.basis = Basis::from_euler(Vector3(sun_rotation.x, sun_rotation.y, 0));
preview_sun->set_transform(t);
sun_direction->queue_redraw();
preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value());
@@ -8014,12 +8069,15 @@ Node3DEditor::Node3DEditor() {
snap_dialog->add_child(snap_dialog_vbc);
snap_translate = memnew(LineEdit);
+ snap_translate->set_select_all_on_focus(true);
snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
snap_rotate = memnew(LineEdit);
+ snap_rotate->set_select_all_on_focus(true);
snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
snap_scale = memnew(LineEdit);
+ snap_scale->set_select_all_on_focus(true);
snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
_snap_update();
@@ -8038,6 +8096,7 @@ Node3DEditor::Node3DEditor() {
settings_fov->set_min(MIN_FOV);
settings_fov->set_step(0.1);
settings_fov->set_value(EDITOR_GET("editors/3d/default_fov"));
+ settings_fov->set_select_all_on_focus(true);
settings_vbc->add_margin_child(TTR("Perspective FOV (deg.):"), settings_fov);
settings_znear = memnew(SpinBox);
@@ -8045,6 +8104,7 @@ Node3DEditor::Node3DEditor() {
settings_znear->set_min(MIN_Z);
settings_znear->set_step(0.01);
settings_znear->set_value(EDITOR_GET("editors/3d/default_z_near"));
+ settings_znear->set_select_all_on_focus(true);
settings_vbc->add_margin_child(TTR("View Z-Near:"), settings_znear);
settings_zfar = memnew(SpinBox);
@@ -8052,6 +8112,7 @@ Node3DEditor::Node3DEditor() {
settings_zfar->set_min(MIN_Z);
settings_zfar->set_step(0.1);
settings_zfar->set_value(EDITOR_GET("editors/3d/default_z_far"));
+ settings_zfar->set_select_all_on_focus(true);
settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
@@ -8077,6 +8138,7 @@ Node3DEditor::Node3DEditor() {
for (int i = 0; i < 3; i++) {
xform_translate[i] = memnew(LineEdit);
xform_translate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_translate[i]->set_select_all_on_focus(true);
xform_hbc->add_child(xform_translate[i]);
}
@@ -8090,6 +8152,7 @@ Node3DEditor::Node3DEditor() {
for (int i = 0; i < 3; i++) {
xform_rotate[i] = memnew(LineEdit);
xform_rotate[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_rotate[i]->set_select_all_on_focus(true);
xform_hbc->add_child(xform_rotate[i]);
}
@@ -8103,6 +8166,7 @@ Node3DEditor::Node3DEditor() {
for (int i = 0; i < 3; i++) {
xform_scale[i] = memnew(LineEdit);
xform_scale[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ xform_scale[i]->set_select_all_on_focus(true);
xform_hbc->add_child(xform_scale[i]);
}
@@ -8347,10 +8411,12 @@ void Node3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
spatial_editor->show();
spatial_editor->set_process(true);
+ spatial_editor->set_physics_process(true);
} else {
spatial_editor->hide();
spatial_editor->set_process(false);
+ spatial_editor->set_physics_process(false);
}
}
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index c76f534c22..7dbe153efd 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -193,6 +193,9 @@ private:
void _menu_option(int p_option);
void _set_auto_orthogonal();
Node3D *preview_node = nullptr;
+ bool update_preview_node = false;
+ Point2 preview_node_viewport_pos;
+ Vector3 preview_node_pos;
AABB *preview_bounds = nullptr;
Vector<String> selected_files;
AcceptDialog *accept = nullptr;
@@ -413,7 +416,7 @@ private:
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
void _project_settings_changed();
@@ -720,6 +723,9 @@ private:
void _selection_changed();
void _refresh_menu_icons();
+ bool do_snap_selected_nodes_to_floor = false;
+ void _snap_selected_nodes_to_floor();
+
// Preview Sun and Environment
uint32_t world_env_count = 0;
@@ -767,7 +773,7 @@ private:
WorldEnvironment *preview_environment = nullptr;
bool preview_env_dangling = false;
Ref<Environment> environment;
- Ref<CameraAttributesPhysical> camera_attributes;
+ Ref<CameraAttributesPractical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
bool sun_environ_updating = false;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index adfaf11264..d7953bf4e0 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -264,45 +264,45 @@ void Path3DGizmo::redraw() {
if (Path3DEditorPlugin::singleton->get_edited_path() == path) {
v3p.clear();
- Vector<Vector3> handles;
- Vector<Vector3> sec_handles;
+ Vector<Vector3> handle_points;
+ Vector<Vector3> sec_handle_points;
for (int i = 0; i < c->get_point_count(); i++) {
Vector3 p = c->get_point_position(i);
- handles.push_back(p);
+ handle_points.push_back(p);
// push Out points first so they get selected if the In and Out points are on top of each other.
if (i < c->get_point_count() - 1) {
v3p.push_back(p);
v3p.push_back(p + c->get_point_out(i));
- sec_handles.push_back(p + c->get_point_out(i));
+ sec_handle_points.push_back(p + c->get_point_out(i));
}
if (i > 0) {
v3p.push_back(p);
v3p.push_back(p + c->get_point_in(i));
- sec_handles.push_back(p + c->get_point_in(i));
+ sec_handle_points.push_back(p + c->get_point_in(i));
}
}
if (v3p.size() > 1) {
add_lines(v3p, path_thin_material);
}
- if (handles.size()) {
- add_handles(handles, handles_material);
+ if (handle_points.size()) {
+ add_handles(handle_points, handles_material);
}
- if (sec_handles.size()) {
- add_handles(sec_handles, sec_handles_material, Vector<int>(), false, true);
+ if (sec_handle_points.size()) {
+ add_handles(sec_handle_points, sec_handles_material, Vector<int>(), false, true);
}
}
}
Path3DGizmo::Path3DGizmo(Path3D *p_path) {
path = p_path;
- set_spatial_node(p_path);
+ set_node_3d(p_path);
orig_in_length = 0;
orig_out_length = 0;
}
-EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!path) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 53e4e2efa8..11a640b79f 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -101,7 +101,7 @@ public:
Path3D *get_edited_path() { return path; }
static Path3DEditorPlugin *singleton;
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
virtual String get_name() const override { return "Path3D"; }
bool has_main_screen() const override { return false; }
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 58a3a07c43..3f8ca825c0 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -67,7 +67,7 @@ void Polygon2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- uv_panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ uv_panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_READY: {
@@ -299,7 +299,7 @@ void Polygon2DEditor::_menu_option(int p_option) {
}
if (EditorSettings::get_singleton()->has_setting("interface/dialogs/uv_editor_bounds")) {
- uv_edit->popup(EditorSettings::get_singleton()->get("interface/dialogs/uv_editor_bounds"));
+ uv_edit->popup(EDITOR_GET("interface/dialogs/uv_editor_bounds"));
} else {
uv_edit->popup_centered_ratio(0.85);
}
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 2b3a5c3e23..dc6ae6be96 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -109,7 +109,7 @@ void Polygon3DEditor::_wip_close() {
undo_redo->commit_action();
}
-EditorPlugin::AfterGUIInput Polygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h
index 0eb02a39e2..918072b429 100644
--- a/editor/plugins/polygon_3d_editor_plugin.h
+++ b/editor/plugins/polygon_3d_editor_plugin.h
@@ -90,7 +90,7 @@ protected:
static void _bind_methods();
public:
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
void edit(Node *p_node);
Polygon3DEditor();
~Polygon3DEditor();
@@ -102,7 +102,7 @@ class Polygon3DEditorPlugin : public EditorPlugin {
Polygon3DEditor *polygon_editor = nullptr;
public:
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return polygon_editor->forward_spatial_gui_input(p_camera, p_event); }
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return polygon_editor->forward_3d_gui_input(p_camera, p_event); }
virtual String get_name() const override { return "Polygon3DEditor"; }
bool has_main_screen() const override { return false; }
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index f70f0dc0aa..e4f0192c64 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -59,19 +59,15 @@
/*** SYNTAX HIGHLIGHTER ****/
String EditorSyntaxHighlighter::_get_name() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_name, ret)) {
- return ret;
- }
- return "Unnamed";
+ String ret = "Unnamed";
+ GDVIRTUAL_CALL(_get_name, ret);
+ return ret;
}
PackedStringArray EditorSyntaxHighlighter::_get_supported_languages() const {
PackedStringArray ret;
- if (GDVIRTUAL_CALL(_get_supported_languages, ret)) {
- return ret;
- }
- return PackedStringArray();
+ GDVIRTUAL_CALL(_get_supported_languages, ret);
+ return ret;
}
Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const {
@@ -128,12 +124,12 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
}
}
- const Ref<Script> script = _get_edited_resource();
- if (script.is_valid()) {
+ const Ref<Script> scr = _get_edited_resource();
+ if (scr.is_valid()) {
/* Core types. */
const Color basetype_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
List<String> core_types;
- script->get_language()->get_core_type_words(&core_types);
+ scr->get_language()->get_core_type_words(&core_types);
for (const String &E : core_types) {
highlighter->add_keyword_color(E, basetype_color);
}
@@ -142,9 +138,9 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color");
const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color");
List<String> keywords;
- script->get_language()->get_reserved_words(&keywords);
+ scr->get_language()->get_reserved_words(&keywords);
for (const String &E : keywords) {
- if (script->get_language()->is_control_flow_keyword(E)) {
+ if (scr->get_language()->is_control_flow_keyword(E)) {
highlighter->add_keyword_color(E, control_flow_keyword_color);
} else {
highlighter->add_keyword_color(E, keyword_color);
@@ -153,19 +149,19 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Member types. */
const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
- StringName instance_base = script->get_instance_base_type();
+ StringName instance_base = scr->get_instance_base_type();
if (instance_base != StringName()) {
List<PropertyInfo> plist;
ClassDB::get_property_list(instance_base, &plist);
for (const PropertyInfo &E : plist) {
- String name = E.name;
+ String prop_name = E.name;
if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) {
continue;
}
- if (name.contains("/")) {
+ if (prop_name.contains("/")) {
continue;
}
- highlighter->add_member_keyword_color(name, member_variable_color);
+ highlighter->add_member_keyword_color(prop_name, member_variable_color);
}
List<String> clist;
@@ -178,7 +174,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Comments */
const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
- script->get_language()->get_comment_delimiters(&comments);
+ scr->get_language()->get_comment_delimiters(&comments);
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
@@ -188,7 +184,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() {
/* Strings */
const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
- script->get_language()->get_string_delimiters(&strings);
+ scr->get_language()->get_string_delimiters(&strings);
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
@@ -405,7 +401,7 @@ String ScriptEditor::_get_debug_tooltip(const String &p_text, Node *_se) {
}
void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
- if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) {
+ if (bool(EDITOR_GET("text_editor/external/use_external_editor"))) {
return;
}
@@ -431,8 +427,8 @@ void ScriptEditor::_goto_script_line2(int p_line) {
}
void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) {
- Ref<Script> script = Object::cast_to<Script>(*p_script);
- if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ Ref<Script> scr = Object::cast_to<Script>(*p_script);
+ if (scr.is_valid() && (scr->has_source_code() || scr->get_path().is_resource_file())) {
if (edit(p_script, p_line, 0)) {
EditorNode::get_singleton()->push_item(p_script.ptr());
@@ -447,15 +443,15 @@ void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) {
}
void ScriptEditor::_set_execution(Ref<RefCounted> p_script, int p_line) {
- Ref<Script> script = Object::cast_to<Script>(*p_script);
- if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ Ref<Script> scr = Object::cast_to<Script>(*p_script);
+ if (scr.is_valid() && (scr->has_source_code() || scr->get_path().is_resource_file())) {
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) {
continue;
}
- if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ if ((scr != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == scr->get_path()) {
se->set_executing_line(p_line);
}
}
@@ -463,15 +459,15 @@ void ScriptEditor::_set_execution(Ref<RefCounted> p_script, int p_line) {
}
void ScriptEditor::_clear_execution(Ref<RefCounted> p_script) {
- Ref<Script> script = Object::cast_to<Script>(*p_script);
- if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ Ref<Script> scr = Object::cast_to<Script>(*p_script);
+ if (scr.is_valid() && (scr->has_source_code() || scr->get_path().is_resource_file())) {
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) {
continue;
}
- if ((script != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == script->get_path()) {
+ if ((scr != nullptr && se->get_edited_resource() == p_script) || se->get_edited_resource()->get_path() == scr->get_path()) {
se->clear_executing_line();
}
}
@@ -479,19 +475,19 @@ void ScriptEditor::_clear_execution(Ref<RefCounted> p_script) {
}
void ScriptEditor::_set_breakpoint(Ref<RefCounted> p_script, int p_line, bool p_enabled) {
- Ref<Script> script = Object::cast_to<Script>(*p_script);
- if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
+ Ref<Script> scr = Object::cast_to<Script>(*p_script);
+ if (scr.is_valid() && (scr->has_source_code() || scr->get_path().is_resource_file())) {
// Update if open.
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 && se->get_edited_resource()->get_path() == script->get_path()) {
+ if (se && se->get_edited_resource()->get_path() == scr->get_path()) {
se->set_breakpoint(p_line, p_enabled);
return;
}
}
// Handle closed.
- Dictionary state = script_editor_cache->get_value(script->get_path(), "state");
+ Dictionary state = script_editor_cache->get_value(scr->get_path(), "state");
Array breakpoints;
if (state.has("breakpoints")) {
breakpoints = state["breakpoints"];
@@ -505,8 +501,8 @@ void ScriptEditor::_set_breakpoint(Ref<RefCounted> p_script, int p_line, bool p_
breakpoints.push_back(p_line);
}
state["breakpoints"] = breakpoints;
- script_editor_cache->set_value(script->get_path(), "state", state);
- EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), p_line + 1, false);
+ script_editor_cache->set_value(scr->get_path(), "state", state);
+ EditorDebuggerNode::get_singleton()->set_breakpoint(scr->get_path(), p_line + 1, false);
}
}
@@ -566,7 +562,7 @@ void ScriptEditor::_save_history() {
Node *n = tab_container->get_current_tab_control();
if (Object::cast_to<ScriptEditorBase>(n)) {
- history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state();
+ history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_navigation_state();
}
if (Object::cast_to<EditorHelp>(n)) {
history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll();
@@ -601,7 +597,7 @@ void ScriptEditor::_go_to_tab(int p_idx) {
Node *n = tab_container->get_current_tab_control();
if (Object::cast_to<ScriptEditorBase>(n)) {
- history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state();
+ history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_navigation_state();
}
if (Object::cast_to<EditorHelp>(n)) {
history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll();
@@ -627,9 +623,9 @@ void ScriptEditor::_go_to_tab(int p_idx) {
Object::cast_to<ScriptEditorBase>(c)->ensure_focus();
}
- Ref<Script> script = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource();
- if (script != nullptr) {
- notify_script_changed(script);
+ Ref<Script> scr = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource();
+ if (scr != nullptr) {
+ notify_script_changed(scr);
}
Object::cast_to<ScriptEditorBase>(c)->validate();
@@ -705,9 +701,9 @@ void ScriptEditor::_open_recent_script(int p_idx) {
ResourceLoader::get_recognized_extensions_for_type("Script", &extensions);
if (extensions.find(path.get_extension())) {
- Ref<Script> script = ResourceLoader::load(path);
- if (script.is_valid()) {
- edit(script, true);
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_valid()) {
+ edit(scr, true);
return;
}
}
@@ -729,9 +725,9 @@ void ScriptEditor::_open_recent_script(int p_idx) {
} else {
EditorNode::get_singleton()->load_resource(res_path);
}
- Ref<Script> script = ResourceLoader::load(path);
- if (script.is_valid()) {
- edit(script, true);
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_valid()) {
+ edit(scr, true);
return;
}
} else if (!path.is_resource_file()) {
@@ -774,9 +770,9 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
previous_scripts.push_back(file->get_path());
}
- Ref<Script> script = file;
- if (script.is_valid()) {
- notify_script_close(script);
+ Ref<Script> scr = file;
+ if (scr.is_valid()) {
+ notify_script_close(scr);
}
}
}
@@ -851,8 +847,8 @@ void ScriptEditor::_close_docs_tab() {
void ScriptEditor::_copy_script_path() {
ScriptEditorBase *se = _get_current_editor();
if (se) {
- Ref<Resource> script = se->get_edited_resource();
- DisplayServer::get_singleton()->clipboard_set(script->get_path());
+ Ref<Resource> scr = se->get_edited_resource();
+ DisplayServer::get_singleton()->clipboard_set(scr->get_path());
}
}
@@ -908,9 +904,9 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
continue;
}
- Ref<Resource> script = se->get_edited_resource();
+ Ref<Resource> scr = se->get_edited_resource();
- if (script->is_built_in()) {
+ if (scr->is_built_in()) {
continue; //internal script, who cares
}
@@ -928,13 +924,13 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
}
}
- Ref<TextFile> text_file = script;
+ Ref<TextFile> text_file = scr;
if (text_file != nullptr) {
se->apply_code();
_save_text_file(text_file, text_file->get_path());
break;
} else {
- EditorNode::get_singleton()->save_resource(script);
+ EditorNode::get_singleton()->save_resource(scr);
}
se->tag_saved_version();
}
@@ -949,9 +945,9 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
continue;
}
- Ref<Resource> script = se->get_edited_resource();
+ Ref<Resource> scr = se->get_edited_resource();
- if (script == p_res) {
+ if (scr == p_res) {
se->tag_saved_version();
}
}
@@ -1106,8 +1102,8 @@ Ref<Script> ScriptEditor::_get_current_script() {
ScriptEditorBase *current = _get_current_editor();
if (current) {
- Ref<Script> script = current->get_edited_resource();
- return script != nullptr ? script : nullptr;
+ Ref<Script> scr = current->get_edited_resource();
+ return scr != nullptr ? scr : nullptr;
} else {
return nullptr;
}
@@ -1284,7 +1280,7 @@ void ScriptEditor::_menu_option(int p_option) {
Ref<Resource> resource = current->get_edited_resource();
Ref<TextFile> text_file = resource;
- Ref<Script> script = resource;
+ Ref<Script> scr = resource;
if (text_file != nullptr) {
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
@@ -1301,26 +1297,15 @@ void ScriptEditor::_menu_option(int p_option) {
break;
}
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
- EditorHelp::get_doc_data()->remove_doc(doc.name);
- }
- }
+ if (scr.is_valid()) {
+ clear_docs_from_script(scr);
}
EditorNode::get_singleton()->push_item(resource.ptr());
EditorNode::get_singleton()->save_resource_as(resource);
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- EditorHelp::get_doc_data()->add_doc(doc);
- update_doc(doc.name);
- }
+ if (scr.is_valid()) {
+ update_docs_from_script(scr);
}
} break;
@@ -1378,18 +1363,18 @@ void ScriptEditor::_menu_option(int p_option) {
_copy_script_path();
} break;
case SHOW_IN_FILE_SYSTEM: {
- const Ref<Resource> script = current->get_edited_resource();
- String path = script->get_path();
+ const Ref<Resource> scr = current->get_edited_resource();
+ String path = scr->get_path();
if (!path.is_empty()) {
- if (script->is_built_in()) {
+ if (scr->is_built_in()) {
path = path.get_slice("::", 0); // Show the scene instead.
}
FileSystemDock *file_system_dock = FileSystemDock::get_singleton();
file_system_dock->navigate_to_path(path);
// Ensure that the FileSystem dock is visible.
- TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(tab_container->get_tab_idx_from_control(file_system_dock));
+ TabContainer *dock_tab_container = (TabContainer *)file_system_dock->get_parent_control();
+ dock_tab_container->set_current_tab(dock_tab_container->get_tab_idx_from_control(file_system_dock));
}
} break;
case CLOSE_DOCS: {
@@ -1499,7 +1484,7 @@ void ScriptEditor::_show_save_theme_as_dialog() {
file_dialog_option = THEME_SAVE_AS;
file_dialog->clear_filters();
file_dialog->add_filter("*.tet");
- file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
+ file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EDITOR_GET("text_editor/theme/color_theme")));
file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Save Theme As..."));
}
@@ -1646,12 +1631,12 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (se) {
- Ref<Script> script = se->get_edited_resource();
- if (script == nullptr || !script.is_valid()) {
+ Ref<Script> scr = se->get_edited_resource();
+ if (scr == nullptr || !scr.is_valid()) {
continue;
}
- if (script->is_built_in() && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
+ if (scr->is_built_in() && scr->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
_close_tab(i, false);
i--;
}
@@ -1679,12 +1664,12 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
continue;
}
- Ref<Script> script = se->get_edited_resource();
- if (script == nullptr) {
+ Ref<Script> scr = se->get_edited_resource();
+ if (scr == nullptr) {
continue;
}
- String base = script->get_path();
+ String base = scr->get_path();
loaded_scripts.insert(base);
if (base.begins_with("local://") || base.is_empty()) {
continue;
@@ -1745,7 +1730,7 @@ void ScriptEditor::ensure_select_current() {
if (tab_container->get_tab_count() && tab_container->get_current_tab() >= 0) {
ScriptEditorBase *se = _get_current_editor();
if (se) {
- se->enable_editor();
+ se->enable_editor(this);
if (!grab_focus_block && is_visible_in_tree()) {
se->ensure_focus();
@@ -1834,7 +1819,7 @@ void ScriptEditor::_update_members_overview() {
}
Vector<String> functions = se->get_functions();
- if (EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically")) {
+ if (EDITOR_GET("text_editor/script_list/sort_members_outline_alphabetically")) {
functions.sort();
}
@@ -1901,9 +1886,9 @@ void ScriptEditor::_update_help_overview() {
}
void ScriptEditor::_update_script_colors() {
- bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_enabled");
+ bool script_temperature_enabled = EDITOR_GET("text_editor/script_list/script_temperature_enabled");
- int hist_size = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_history_size");
+ int hist_size = EDITOR_GET("text_editor/script_list/script_temperature_history_size");
Color hot_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
hot_color.set_s(hot_color.get_s() * 0.9);
Color cold_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
@@ -1947,9 +1932,9 @@ void ScriptEditor::_update_script_names() {
}
script_list->clear();
- bool split_script_help = EditorSettings::get_singleton()->get("text_editor/script_list/group_help_pages");
- ScriptSortBy sort_by = (ScriptSortBy)(int)EditorSettings::get_singleton()->get("text_editor/script_list/sort_scripts_by");
- ScriptListName display_as = (ScriptListName)(int)EditorSettings::get_singleton()->get("text_editor/script_list/list_script_names_as");
+ bool split_script_help = EDITOR_GET("text_editor/script_list/group_help_pages");
+ ScriptSortBy sort_by = (ScriptSortBy)(int)EDITOR_GET("text_editor/script_list/sort_scripts_by");
+ ScriptListName display_as = (ScriptListName)(int)EDITOR_GET("text_editor/script_list/list_script_names_as");
Vector<_ScriptEditorItemData> sedata;
@@ -2017,7 +2002,7 @@ void ScriptEditor::_update_script_names() {
Vector<String> full_script_paths;
for (int j = 0; j < sedata.size(); j++) {
String name = sedata[j].name.replace("(*)", "");
- ScriptListName script_display = (ScriptListName)(int)EditorSettings::get_singleton()->get("text_editor/script_list/list_script_names_as");
+ ScriptListName script_display = (ScriptListName)(int)EDITOR_GET("text_editor/script_list/list_script_names_as");
switch (script_display) {
case DISPLAY_NAME: {
name = name.get_file();
@@ -2119,7 +2104,7 @@ void ScriptEditor::_update_script_names() {
ScriptEditorBase *se = _get_current_editor();
if (se) {
- se->enable_editor();
+ se->enable_editor(this);
_update_selected_editor_menu();
}
}
@@ -2195,20 +2180,20 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
return false;
}
- Ref<Script> script = p_resource;
+ Ref<Script> scr = p_resource;
// Don't open dominant script if using an external editor.
bool use_external_editor =
- EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") ||
- (script.is_valid() && script->get_language()->overrides_external_editor());
- use_external_editor = use_external_editor && !(script.is_valid() && script->is_built_in()); // Ignore external editor for built-in scripts.
- const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/behavior/files/open_dominant_script_on_scene_change");
+ EDITOR_GET("text_editor/external/use_external_editor") ||
+ (scr.is_valid() && scr->get_language()->overrides_external_editor());
+ use_external_editor = use_external_editor && !(scr.is_valid() && scr->is_built_in()); // Ignore external editor for built-in scripts.
+ const bool open_dominant = EDITOR_GET("text_editor/behavior/files/open_dominant_script_on_scene_change");
const bool should_open = (open_dominant && !use_external_editor) || !EditorNode::get_singleton()->is_changing_scene();
- if (script.is_valid() && script->get_language()->overrides_external_editor()) {
+ if (scr.is_valid() && scr->get_language()->overrides_external_editor()) {
if (should_open) {
- Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col);
+ Error err = scr->get_language()->open_in_external_editor(scr, p_line >= 0 ? p_line : 0, p_col);
if (err != OK) {
ERR_PRINT("Couldn't open script in the overridden external text editor");
}
@@ -2220,8 +2205,8 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
(EditorDebuggerNode::get_singleton()->get_dump_stack_script() != p_resource || EditorDebuggerNode::get_singleton()->get_debug_with_external_editor()) &&
p_resource->get_path().is_resource_file() &&
!p_resource->is_class("VisualScript")) {
- String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path");
- String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
+ String path = EDITOR_GET("text_editor/external/exec_path");
+ String flags = EDITOR_GET("text_editor/external/exec_flags");
List<String> args;
bool has_file_flag = false;
@@ -2282,9 +2267,9 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
continue;
}
- if ((script != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) {
+ if ((scr != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) {
if (should_open) {
- se->enable_editor();
+ se->enable_editor(this);
if (tab_container->get_current_tab() != i) {
_go_to_tab(i);
@@ -2327,9 +2312,9 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
}
se->add_syntax_highlighter(highlighter);
- if (script != nullptr && !highlighter_set) {
+ if (scr != nullptr && !highlighter_set) {
PackedStringArray languages = highlighter->_get_supported_languages();
- if (languages.has(script->get_language()->get_name())) {
+ if (languages.has(scr->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
@@ -2340,7 +2325,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
tab_container->add_child(se);
if (p_grab_focus) {
- se->enable_editor();
+ se->enable_editor(this);
}
// If we delete a script within the filesystem, the original resource path
@@ -2410,7 +2395,7 @@ void ScriptEditor::save_current_script() {
Ref<Resource> resource = current->get_edited_resource();
Ref<TextFile> text_file = resource;
- Ref<Script> script = resource;
+ Ref<Script> scr = resource;
if (text_file != nullptr) {
current->apply_code();
@@ -2418,14 +2403,8 @@ void ScriptEditor::save_current_script() {
return;
}
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
- EditorHelp::get_doc_data()->remove_doc(doc.name);
- }
- }
+ if (scr.is_valid()) {
+ clear_docs_from_script(scr);
}
if (resource->is_built_in()) {
@@ -2440,13 +2419,8 @@ void ScriptEditor::save_current_script() {
EditorNode::get_singleton()->save_resource(resource);
}
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- EditorHelp::get_doc_data()->add_doc(doc);
- update_doc(doc.name);
- }
+ if (scr.is_valid()) {
+ update_docs_from_script(scr);
}
}
@@ -2484,32 +2458,21 @@ void ScriptEditor::save_all_scripts() {
if (!edited_res->is_built_in()) {
Ref<TextFile> text_file = edited_res;
- Ref<Script> script = edited_res;
+ Ref<Script> scr = edited_res;
if (text_file != nullptr) {
_save_text_file(text_file, text_file->get_path());
continue;
}
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
- EditorHelp::get_doc_data()->remove_doc(doc.name);
- }
- }
+ if (scr.is_valid()) {
+ clear_docs_from_script(scr);
}
EditorNode::get_singleton()->save_resource(edited_res); //external script, save it
- if (script != nullptr) {
- Vector<DocData::ClassDoc> documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- EditorHelp::get_doc_data()->add_doc(doc);
- update_doc(doc.name);
- }
+ if (scr.is_valid()) {
+ update_docs_from_script(scr);
}
} else {
// For built-in scripts, save their scenes instead.
@@ -2559,13 +2522,13 @@ void ScriptEditor::reload_scripts(bool p_refresh_only) {
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> scr = edited_res;
+ if (scr != nullptr) {
+ Ref<Script> rel_scr = ResourceLoader::load(scr->get_path(), scr->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_scr.is_valid());
+ scr->set_source_code(rel_scr->get_source_code());
+ scr->set_last_modified_time(rel_scr->get_last_modified_time());
+ scr->reload(true);
}
Ref<TextFile> text_file = edited_res;
@@ -2638,17 +2601,17 @@ void ScriptEditor::_editor_stop() {
void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args) {
ERR_FAIL_COND(!p_obj);
- Ref<Script> script = p_obj->get_script();
- ERR_FAIL_COND(!script.is_valid());
+ Ref<Script> scr = p_obj->get_script();
+ ERR_FAIL_COND(!scr.is_valid());
- EditorNode::get_singleton()->push_item(script.ptr());
+ EditorNode::get_singleton()->push_item(scr.ptr());
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) {
continue;
}
- if (se->get_edited_resource() != script) {
+ if (se->get_edited_resource() != scr) {
continue;
}
@@ -2659,7 +2622,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
script_list->select(script_list->find_metadata(i));
// Save the current script so the changes can be picked up by an external editor.
- if (!script.ptr()->is_built_in()) { // But only if it's not built-in script.
+ if (!scr.ptr()->is_built_in()) { // But only if it's not built-in script.
save_current_script();
}
@@ -2691,26 +2654,26 @@ void ScriptEditor::_save_layout() {
void ScriptEditor::_editor_settings_changed() {
textfile_extensions.clear();
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
textfile_extensions.insert(E);
}
- trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/trim_trailing_whitespace_on_save");
- convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/convert_indent_on_save");
- use_space_indentation = EditorSettings::get_singleton()->get("text_editor/behavior/indent/type");
+ trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
+ convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
+ use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type");
- members_overview_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/show_members_overview");
- help_overview_enabled = EditorSettings::get_singleton()->get("text_editor/help/show_help_index");
+ members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
+ help_overview_enabled = EDITOR_GET("text_editor/help/show_help_index");
_update_members_overview_visibility();
_update_help_overview_visibility();
_update_autosave_timer();
if (current_theme.is_empty()) {
- current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
- } else if (current_theme != String(EditorSettings::get_singleton()->get("text_editor/theme/color_theme"))) {
- current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
+ current_theme = EDITOR_GET("text_editor/theme/color_theme");
+ } else if (current_theme != String(EDITOR_GET("text_editor/theme/color_theme"))) {
+ current_theme = EDITOR_GET("text_editor/theme/color_theme");
EditorSettings::get_singleton()->load_text_editor_theme();
}
@@ -2793,7 +2756,7 @@ void ScriptEditor::_update_autosave_timer() {
return;
}
- float autosave_time = EditorSettings::get_singleton()->get("text_editor/behavior/files/autosave_interval_secs");
+ float autosave_time = EDITOR_GET("text_editor/behavior/files/autosave_interval_secs");
if (autosave_time > 0) {
autosave_timer->set_wait_time(autosave_time);
autosave_timer->start();
@@ -3331,6 +3294,29 @@ void ScriptEditor::update_doc(const String &p_name) {
}
}
+void ScriptEditor::clear_docs_from_script(const Ref<Script> &p_script) {
+ ERR_FAIL_COND(p_script.is_null());
+
+ Vector<DocData::ClassDoc> documentations = p_script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
+ EditorHelp::get_doc_data()->remove_doc(doc.name);
+ }
+ }
+}
+
+void ScriptEditor::update_docs_from_script(const Ref<Script> &p_script) {
+ ERR_FAIL_COND(p_script.is_null());
+
+ Vector<DocData::ClassDoc> documentations = p_script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ EditorHelp::get_doc_data()->add_doc(doc);
+ update_doc(doc.name);
+ }
+}
+
void ScriptEditor::_update_selected_editor_menu() {
for (int i = 0; i < tab_container->get_tab_count(); i++) {
bool current = tab_container->get_current_tab() == i;
@@ -3370,7 +3356,7 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
Node *n = tab_container->get_current_tab_control();
if (Object::cast_to<ScriptEditorBase>(n)) {
- history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_edit_state();
+ history.write[history_pos].state = Object::cast_to<ScriptEditorBase>(n)->get_navigation_state();
}
if (Object::cast_to<EditorHelp>(n)) {
history.write[history_pos].state = Object::cast_to<EditorHelp>(n)->get_scroll();
@@ -3381,13 +3367,14 @@ void ScriptEditor::_update_history_pos(int p_new_pos) {
n = history[history_pos].control;
- if (Object::cast_to<ScriptEditorBase>(n)) {
- Object::cast_to<ScriptEditorBase>(n)->set_edit_state(history[history_pos].state);
- Object::cast_to<ScriptEditorBase>(n)->ensure_focus();
+ ScriptEditorBase *seb = Object::cast_to<ScriptEditorBase>(n);
+ if (seb) {
+ seb->set_edit_state(history[history_pos].state);
+ seb->ensure_focus();
- Ref<Script> script = Object::cast_to<ScriptEditorBase>(n)->get_edited_resource();
- if (script != nullptr) {
- notify_script_changed(script);
+ Ref<Script> scr = seb->get_edited_resource();
+ if (scr != nullptr) {
+ notify_script_changed(scr);
}
}
@@ -3423,9 +3410,9 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
continue;
}
- Ref<Script> script = se->get_edited_resource();
- if (script != nullptr) {
- out_scripts.push_back(script);
+ Ref<Script> scr = se->get_edited_resource();
+ if (scr != nullptr) {
+ out_scripts.push_back(scr);
}
}
@@ -3447,10 +3434,10 @@ TypedArray<ScriptEditorBase> ScriptEditor::_get_open_script_editors() const {
void ScriptEditor::set_scene_root_script(Ref<Script> p_script) {
// Don't open dominant script if using an external editor.
bool use_external_editor =
- EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") ||
+ EDITOR_GET("text_editor/external/use_external_editor") ||
(p_script.is_valid() && p_script->get_language()->overrides_external_editor());
use_external_editor = use_external_editor && !(p_script.is_valid() && p_script->is_built_in()); // Ignore external editor for built-in scripts.
- const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/behavior/files/open_dominant_script_on_scene_change");
+ const bool open_dominant = EDITOR_GET("text_editor/behavior/files/open_dominant_script_on_scene_change");
if (open_dominant && !use_external_editor && p_script.is_valid()) {
edit(p_script);
@@ -3476,9 +3463,9 @@ void ScriptEditor::_help_search(String p_text) {
}
void ScriptEditor::_open_script_request(const String &p_path) {
- Ref<Script> script = ResourceLoader::load(p_path);
- if (script.is_valid()) {
- script_editor->edit(script, false);
+ Ref<Script> scr = ResourceLoader::load(p_path);
+ if (scr.is_valid()) {
+ script_editor->edit(scr, false);
return;
}
@@ -3543,9 +3530,9 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb
EditorNode::get_singleton()->load_scene(fpath);
return;
} else {
- Ref<Script> script = res;
- if (script.is_valid()) {
- edit(script);
+ Ref<Script> scr = res;
+ if (scr.is_valid()) {
+ edit(scr);
ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor());
if (ste) {
@@ -3641,8 +3628,8 @@ ScriptEditor::ScriptEditor() {
waiting_update_names = false;
pending_auto_reload = false;
auto_reload_running_scripts = true;
- members_overview_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/show_members_overview");
- help_overview_enabled = EditorSettings::get_singleton()->get("text_editor/help/show_help_index");
+ members_overview_enabled = EDITOR_GET("text_editor/script_list/show_members_overview");
+ help_overview_enabled = EDITOR_GET("text_editor/help/show_help_index");
VBoxContainer *main_container = memnew(VBoxContainer);
add_child(main_container);
@@ -3701,7 +3688,7 @@ ScriptEditor::ScriptEditor() {
members_overview_alphabeta_sort_button->set_flat(true);
members_overview_alphabeta_sort_button->set_tooltip_text(TTR("Toggle alphabetical sorting of the method list."));
members_overview_alphabeta_sort_button->set_toggle_mode(true);
- members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically"));
+ members_overview_alphabeta_sort_button->set_pressed(EDITOR_GET("text_editor/script_list/sort_members_outline_alphabetically"));
members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort));
buttons_hbox->add_child(members_overview_alphabeta_sort_button);
@@ -3815,12 +3802,12 @@ ScriptEditor::ScriptEditor() {
script_search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option));
menu_hb->add_child(script_search_menu);
- MenuButton *debug_menu = memnew(MenuButton);
- menu_hb->add_child(debug_menu);
- debug_menu->hide(); // Handled by EditorDebuggerNode below.
+ MenuButton *debug_menu_btn = memnew(MenuButton);
+ menu_hb->add_child(debug_menu_btn);
+ debug_menu_btn->hide(); // Handled by EditorDebuggerNode below.
EditorDebuggerNode *debugger = EditorDebuggerNode::get_singleton();
- debugger->set_script_debug_button(debug_menu);
+ debugger->set_script_debug_button(debug_menu_btn);
debugger->connect("goto_script_line", callable_mp(this, &ScriptEditor::_goto_script_line));
debugger->connect("set_execution", callable_mp(this, &ScriptEditor::_set_execution));
debugger->connect("clear_execution", callable_mp(this, &ScriptEditor::_clear_execution));
@@ -3943,9 +3930,9 @@ ScriptEditor::ScriptEditor() {
history_pos = -1;
edit_pass = 0;
- trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/trim_trailing_whitespace_on_save");
- convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/convert_indent_on_save");
- use_space_indentation = EditorSettings::get_singleton()->get("text_editor/behavior/indent/type");
+ trim_trailing_whitespace_on_save = EDITOR_GET("text_editor/behavior/files/trim_trailing_whitespace_on_save");
+ convert_indent_on_save = EDITOR_GET("text_editor/behavior/files/convert_indent_on_save");
+ use_space_indentation = EDITOR_GET("text_editor/behavior/indent/type");
ScriptServer::edit_request_func = _open_script_request;
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 233baa9bd3..a45ce4cc22 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -139,13 +139,14 @@ public:
virtual Ref<Resource> get_edited_resource() const = 0;
virtual Vector<String> get_functions() = 0;
virtual void set_edited_resource(const Ref<Resource> &p_res) = 0;
- virtual void enable_editor() = 0;
+ virtual void enable_editor(Control *p_shortcut_context = nullptr) = 0;
virtual void reload_text() = 0;
virtual String get_name() = 0;
virtual Ref<Texture2D> get_theme_icon() = 0;
virtual bool is_unsaved() = 0;
virtual Variant get_edit_state() = 0;
virtual void set_edit_state(const Variant &p_state) = 0;
+ virtual Variant get_navigation_state() = 0;
virtual void goto_line(int p_line, bool p_with_error = false) = 0;
virtual void set_executing_line(int p_line) = 0;
virtual void clear_executing_line() = 0;
@@ -508,6 +509,8 @@ public:
void goto_help(const String &p_desc) { _help_class_goto(p_desc); }
void update_doc(const String &p_name);
+ void clear_docs_from_script(const Ref<Script> &p_script);
+ void update_docs_from_script(const Ref<Script> &p_script);
bool can_take_away_focus() const;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index a1d24907e5..0d12d07aa7 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -151,7 +151,7 @@ void ScriptTextEditor::set_edited_resource(const Ref<Resource> &p_res) {
code_editor->update_line_and_column();
}
-void ScriptTextEditor::enable_editor() {
+void ScriptTextEditor::enable_editor(Control *p_shortcut_context) {
if (editor_enabled) {
return;
}
@@ -161,6 +161,15 @@ void ScriptTextEditor::enable_editor() {
_enable_code_editor();
_validate_script();
+
+ if (p_shortcut_context) {
+ for (int i = 0; i < edit_hb->get_child_count(); ++i) {
+ Control *c = cast_to<Control>(edit_hb->get_child(i));
+ if (c) {
+ c->set_shortcut_context(p_shortcut_context);
+ }
+ }
+ }
}
void ScriptTextEditor::_load_theme_settings() {
@@ -267,6 +276,7 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) {
void ScriptTextEditor::_error_clicked(Variant p_line) {
if (p_line.get_type() == Variant::INT) {
+ code_editor->get_text_editor()->remove_secondary_carets();
code_editor->get_text_editor()->set_caret_line(p_line.operator int64_t());
}
}
@@ -295,6 +305,7 @@ void ScriptTextEditor::reload_text() {
void ScriptTextEditor::add_callback(const String &p_function, PackedStringArray p_args) {
String code = code_editor->get_text_editor()->get_text();
int pos = script->get_language()->find_function(p_function, code);
+ code_editor->get_text_editor()->remove_secondary_carets();
if (pos == -1) {
//does not exist
code_editor->get_text_editor()->deselect();
@@ -314,7 +325,7 @@ bool ScriptTextEditor::show_members_overview() {
}
void ScriptTextEditor::update_settings() {
- code_editor->get_text_editor()->set_gutter_draw(connection_gutter, EditorSettings::get_singleton()->get("text_editor/appearance/gutters/show_info_gutter"));
+ code_editor->get_text_editor()->set_gutter_draw(connection_gutter, EDITOR_GET("text_editor/appearance/gutters/show_info_gutter"));
code_editor->update_editor_settings();
}
@@ -347,6 +358,10 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) {
}
}
+Variant ScriptTextEditor::get_navigation_state() {
+ return code_editor->get_navigation_state();
+}
+
void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
code_editor->convert_case(p_case);
}
@@ -683,7 +698,7 @@ static void _find_changed_scripts_for_external_editor(Node *p_base, Node *p_curr
}
void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_for_script) {
- if (!bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) {
+ if (!bool(EDITOR_GET("text_editor/external/use_external_editor"))) {
return;
}
@@ -697,25 +712,25 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo
}
for (const Ref<Script> &E : scripts) {
- Ref<Script> script = E;
+ Ref<Script> scr = E;
- if (p_for_script.is_valid() && p_for_script != script) {
+ if (p_for_script.is_valid() && p_for_script != scr) {
continue;
}
- if (script->is_built_in()) {
+ if (scr->is_built_in()) {
continue; //internal script, who cares, though weird
}
- uint64_t last_date = script->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(script->get_path());
+ uint64_t last_date = scr->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(scr->get_path());
if (last_date != date) {
- 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->update_exports();
+ Ref<Script> rel_scr = ResourceLoader::load(scr->get_path(), scr->get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+ ERR_CONTINUE(!rel_scr.is_valid());
+ scr->set_source_code(rel_scr->get_source_code());
+ scr->set_last_modified_time(rel_scr->get_last_modified_time());
+ scr->update_exports();
_trigger_live_script_reload();
}
@@ -976,10 +991,10 @@ void ScriptTextEditor::_update_connected_methods() {
Vector<Node *> nodes = _find_all_node_for_script(base, base, script);
HashSet<StringName> methods_found;
for (int i = 0; i < nodes.size(); i++) {
- List<Connection> connections;
- nodes[i]->get_signals_connected_to_this(&connections);
+ List<Connection> signal_connections;
+ nodes[i]->get_signals_connected_to_this(&signal_connections);
- for (const Connection &connection : connections) {
+ for (const Connection &connection : signal_connections) {
if (!(connection.flags & CONNECT_PERSIST)) {
continue;
}
@@ -1363,6 +1378,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
+ tx->remove_secondary_carets();
int line = tx->get_caret_line();
// wrap around
@@ -1389,6 +1405,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
return;
}
+ tx->remove_secondary_carets();
int line = tx->get_caret_line();
// wrap around
if (line <= (int)bpoints[0]) {
@@ -1409,21 +1426,21 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case HELP_CONTEXTUAL: {
- String text = tx->get_selected_text();
+ String text = tx->get_selected_text(0);
if (text.is_empty()) {
- text = tx->get_word_under_caret();
+ text = tx->get_word_under_caret(0);
}
if (!text.is_empty()) {
emit_signal(SNAME("request_help"), text);
}
} break;
case LOOKUP_SYMBOL: {
- String text = tx->get_word_under_caret();
+ String text = tx->get_word_under_caret(0);
if (text.is_empty()) {
- text = tx->get_selected_text();
+ text = tx->get_selected_text(0);
}
if (!text.is_empty()) {
- _lookup_symbol(text, tx->get_caret_line(), tx->get_caret_column());
+ _lookup_symbol(text, tx->get_caret_line(0), tx->get_caret_column(0));
}
} break;
}
@@ -1590,9 +1607,24 @@ static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const
return nullptr;
}
-void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
+static String _quote_drop_data(const String &str) {
+ // This function prepares a string for being "dropped" into the script editor.
+ // The string can be a resource path, node path or property name.
+
+ const bool using_single_quotes = EDITOR_GET("text_editor/completion/use_single_quotes");
+
+ String escaped = str.c_escape();
+
+ // If string is double quoted, there is no need to escape single quotes.
+ // We can revert the extra escaping added in c_escape().
+ if (!using_single_quotes) {
+ escaped = escaped.replace("\\'", "\'");
+ }
+ return escaped.quote(using_single_quotes ? "'" : "\"");
+}
+
+void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
Dictionary d = p_data;
CodeEdit *te = code_editor->get_text_editor();
@@ -1601,6 +1633,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
int col = pos.x;
if (d.has("type") && String(d["type"]) == "resource") {
+ te->remove_secondary_carets();
Ref<Resource> res = d["resource"];
if (!res.is_valid()) {
return;
@@ -1618,6 +1651,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) {
+ te->remove_secondary_carets();
Array files = d["files"];
String text_to_drop;
@@ -1628,9 +1662,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (preload) {
- text_to_drop += "preload(" + String(files[i]).c_escape().quote(quote_style) + ")";
+ text_to_drop += "preload(" + _quote_drop_data(String(files[i])) + ")";
} else {
- text_to_drop += String(files[i]).c_escape().quote(quote_style);
+ text_to_drop += _quote_drop_data(String(files[i]));
}
}
@@ -1641,6 +1675,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (d.has("type") && String(d["type"]) == "nodes") {
+ te->remove_secondary_carets();
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."));
@@ -1675,7 +1710,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
for (const String &segment : path.split("/")) {
if (!segment.is_valid_identifier()) {
- path = path.c_escape().quote(quote_style);
+ path = _quote_drop_data(path);
break;
}
}
@@ -1710,7 +1745,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
for (const String &segment : path.split("/")) {
if (!segment.is_valid_identifier()) {
- path = path.c_escape().quote(quote_style);
+ path = _quote_drop_data(path);
break;
}
}
@@ -1725,7 +1760,10 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
}
if (d.has("type") && String(d["type"]) == "obj_property") {
- const String text_to_drop = String(d["property"]).c_escape().quote(quote_style);
+ te->remove_secondary_carets();
+ // It is unclear whether properties may contain single or double quotes.
+ // Assume here that double-quotes may not exist. We are escaping single-quotes if necessary.
+ const String text_to_drop = _quote_drop_data(String(d["property"]));
te->set_caret_line(row);
te->set_caret_column(col);
@@ -1745,8 +1783,8 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
local_pos = mb->get_global_position() - tx->get_global_position();
create_menu = true;
} else if (k.is_valid() && k->is_action("ui_menu", true)) {
- tx->adjust_viewport_to_caret();
- local_pos = tx->get_caret_draw_pos();
+ tx->adjust_viewport_to_caret(0);
+ local_pos = tx->get_caret_draw_pos(0);
create_menu = true;
}
@@ -1755,8 +1793,9 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
int row = pos.y;
int col = pos.x;
- tx->set_move_caret_on_right_click_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/move_caret_on_right_click"));
+ tx->set_move_caret_on_right_click_enabled(EDITOR_GET("text_editor/behavior/navigation/move_caret_on_right_click"));
if (tx->is_move_caret_on_right_click_enabled()) {
+ tx->remove_secondary_carets();
if (tx->has_selection()) {
int from_line = tx->get_selection_from_line();
int to_line = tx->get_selection_to_line();
@@ -1776,10 +1815,10 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
String word_at_pos = tx->get_word_at_pos(local_pos);
if (word_at_pos.is_empty()) {
- word_at_pos = tx->get_word_under_caret();
+ word_at_pos = tx->get_word_under_caret(0);
}
if (word_at_pos.is_empty()) {
- word_at_pos = tx->get_selected_text();
+ word_at_pos = tx->get_selected_text(0);
}
bool has_color = (word_at_pos == "Color");
@@ -1965,18 +2004,6 @@ void ScriptTextEditor::_enable_code_editor() {
add_child(connection_info_dialog);
- edit_hb->add_child(search_menu);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
- search_menu->get_popup()->add_separator();
- search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
- search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
edit_hb->add_child(edit_menu);
edit_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_prepare_edit_menu));
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO);
@@ -1987,38 +2014,73 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE);
edit_menu->get_popup()->add_separator();
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_select_all"), EDIT_SELECT_ALL);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("line_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent"), EDIT_INDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unindent"), EDIT_UNINDENT);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Line"), "line_menu");
+ }
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("folding_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Folding"), "folding_menu");
+ }
edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("indent_menu");
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Indentation"), "indent_menu");
+ }
edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_separator();
-
- edit_menu->get_popup()->add_child(convert_case);
- edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
- convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
-
+ {
+ PopupMenu *sub_menu = memnew(PopupMenu);
+ sub_menu->set_name("convert_case");
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
+ sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
+ sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+ edit_menu->get_popup()->add_child(sub_menu);
+ edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case");
+ }
edit_menu->get_popup()->add_child(highlighter_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu");
highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter));
+ edit_hb->add_child(search_menu);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES);
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES);
+ search_menu->get_popup()->add_separator();
+ search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL);
+ search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
+
_load_theme_settings();
edit_hb->add_child(goto_menu);
@@ -2077,7 +2139,7 @@ ScriptTextEditor::ScriptTextEditor() {
update_settings();
- code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
+ code_editor->get_text_editor()->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
code_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true);
code_editor->get_text_editor()->set_context_menu_enabled(false);
@@ -2093,9 +2155,6 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->set_switch_on_hover(true);
edit_menu->set_shortcut_context(this);
- convert_case = memnew(PopupMenu);
- convert_case->set_name("convert_case");
-
highlighter_menu = memnew(PopupMenu);
highlighter_menu->set_name("highlighter_menu");
@@ -2140,7 +2199,6 @@ ScriptTextEditor::~ScriptTextEditor() {
memdelete(color_panel);
memdelete(edit_hb);
memdelete(edit_menu);
- memdelete(convert_case);
memdelete(highlighter_menu);
memdelete(search_menu);
memdelete(goto_menu);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 99fafb2192..5fd12674b3 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -79,7 +79,6 @@ class ScriptTextEditor : public ScriptEditorBase {
PopupMenu *breakpoints_menu = nullptr;
PopupMenu *highlighter_menu = nullptr;
PopupMenu *context_menu = nullptr;
- PopupMenu *convert_case = nullptr;
GotoLineDialog *goto_line_dialog = nullptr;
ScriptEditorQuickOpen *quick_open = nullptr;
@@ -207,7 +206,7 @@ public:
virtual void apply_code() override;
virtual Ref<Resource> get_edited_resource() const override;
virtual void set_edited_resource(const Ref<Resource> &p_res) override;
- virtual void enable_editor() override;
+ virtual void enable_editor(Control *p_shortcut_context = nullptr) override;
virtual Vector<String> get_functions() override;
virtual void reload_text() override;
virtual String get_name() override;
@@ -215,6 +214,7 @@ public:
virtual bool is_unsaved() override;
virtual Variant get_edit_state() override;
virtual void set_edit_state(const Variant &p_state) override;
+ virtual Variant get_navigation_state() override;
virtual void ensure_focus() override;
virtual void trim_trailing_whitespace() override;
virtual void insert_final_newline() override;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index de1a807721..456c28d887 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -264,6 +264,9 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
} else {
EditorNode::get_singleton()->save_resource(edited_shaders[index].shader_inc);
}
+ if (edited_shaders[index].shader_editor) {
+ edited_shaders[index].shader_editor->tag_saved_version();
+ }
} break;
case FILE_SAVE_AS: {
int index = shader_tabs->get_current_tab();
@@ -282,6 +285,9 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
}
EditorNode::get_singleton()->save_resource_as(edited_shaders[index].shader_inc, path);
}
+ if (edited_shaders[index].shader_editor) {
+ edited_shaders[index].shader_editor->tag_saved_version();
+ }
} break;
case FILE_INSPECT: {
int index = shader_tabs->get_current_tab();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 2478ac9514..7922a768ec 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -587,25 +587,25 @@ void Skeleton3DEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx) {
Node *node = get_node_or_null(p_skeleton_path);
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
- ERR_FAIL_NULL(skeleton);
+ Skeleton3D *skeleton_node = Object::cast_to<Skeleton3D>(node);
+ ERR_FAIL_NULL(skeleton_node);
Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Parentage"));
// If the target is a child of ourselves, we move only *us* and not our children.
- if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
- const BoneId parent_idx = skeleton->get_bone_parent(p_selected_boneidx);
- const int bone_count = skeleton->get_bone_count();
+ if (skeleton_node->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
+ const BoneId parent_idx = skeleton_node->get_bone_parent(p_selected_boneidx);
+ const int bone_count = skeleton_node->get_bone_count();
for (BoneId i = 0; i < bone_count; ++i) {
- if (skeleton->get_bone_parent(i) == p_selected_boneidx) {
- ur->add_undo_method(skeleton, "set_bone_parent", i, skeleton->get_bone_parent(i));
- ur->add_do_method(skeleton, "set_bone_parent", i, parent_idx);
- skeleton->set_bone_parent(i, parent_idx);
+ if (skeleton_node->get_bone_parent(i) == p_selected_boneidx) {
+ ur->add_undo_method(skeleton_node, "set_bone_parent", i, skeleton_node->get_bone_parent(i));
+ ur->add_do_method(skeleton_node, "set_bone_parent", i, parent_idx);
+ skeleton_node->set_bone_parent(i, parent_idx);
}
}
}
- ur->add_undo_method(skeleton, "set_bone_parent", p_selected_boneidx, skeleton->get_bone_parent(p_selected_boneidx));
- ur->add_do_method(skeleton, "set_bone_parent", p_selected_boneidx, p_target_boneidx);
- skeleton->set_bone_parent(p_selected_boneidx, p_target_boneidx);
+ ur->add_undo_method(skeleton_node, "set_bone_parent", p_selected_boneidx, skeleton_node->get_bone_parent(p_selected_boneidx));
+ ur->add_do_method(skeleton_node, "set_bone_parent", p_selected_boneidx, p_target_boneidx);
+ skeleton_node->set_bone_parent(p_selected_boneidx, p_target_boneidx);
update_joint_tree();
ur->commit_action();
@@ -1082,7 +1082,7 @@ void Skeleton3DEditor::select_bone(int p_idx) {
Skeleton3DEditor::~Skeleton3DEditor() {
singleton = nullptr;
- handles_mesh_instance->queue_delete();
+ handles_mesh_instance->queue_free();
Node3DEditor *ne = Node3DEditor::get_singleton();
@@ -1128,7 +1128,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin() {
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
-EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput Skeleton3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
if (se && se->is_edit_mode()) {
@@ -1234,7 +1234,7 @@ int Skeleton3DGizmoPlugin::get_priority() const {
}
int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
ERR_FAIL_COND_V(!skeleton, -1);
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
@@ -1277,14 +1277,14 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi
}
Transform3D Skeleton3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
ERR_FAIL_COND_V(!skeleton, Transform3D());
return skeleton->get_bone_global_pose(p_id);
}
void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
ERR_FAIL_COND(!skeleton);
// Prepare for global to local.
@@ -1313,7 +1313,7 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
}
void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
ERR_FAIL_COND(!skeleton);
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
@@ -1346,7 +1346,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
}
void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_spatial_node());
+ Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
p_gizmo->clear();
int selected = -1;
@@ -1355,10 +1355,10 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
selected = se->get_selected_bone();
}
- Color bone_color = EditorSettings::get_singleton()->get("editors/3d_gizmos/gizmo_colors/skeleton");
- Color selected_bone_color = EditorSettings::get_singleton()->get("editors/3d_gizmos/gizmo_colors/selected_bone");
- real_t bone_axis_length = EditorSettings::get_singleton()->get("editors/3d_gizmos/gizmo_settings/bone_axis_length");
- int bone_shape = EditorSettings::get_singleton()->get("editors/3d_gizmos/gizmo_settings/bone_shape");
+ Color bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton");
+ Color selected_bone_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/selected_bone");
+ real_t bone_axis_length = EDITOR_GET("editors/3d_gizmos/gizmo_settings/bone_axis_length");
+ int bone_shape = EDITOR_GET("editors/3d_gizmos/gizmo_settings/bone_shape");
LocalVector<Color> axis_colors;
axis_colors.push_back(Node3DEditor::get_singleton()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor")));
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 9747ed8374..9f02d144ed 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -238,7 +238,7 @@ class Skeleton3DEditorPlugin : public EditorPlugin {
EditorInspectorPluginSkeleton *skeleton_plugin = nullptr;
public:
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
bool has_main_screen() const override { return false; }
virtual bool handles(Object *p_object) const override;
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index d0a1ddafa1..d3ab5b6f77 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -67,14 +67,18 @@ int SpriteFramesEditor::_sheet_preview_position_to_frame_index(const Point2 &p_p
const Size2i block_size = frame_size + separation;
const Point2i position = p_position / sheet_zoom - offset;
- if (position.x % block_size.x > frame_size.x || position.y % block_size.y > frame_size.y) {
+ if (position.x < 0 || position.y < 0) {
+ return -1; // Out of bounds.
+ }
+
+ if (position.x % block_size.x >= frame_size.x || position.y % block_size.y >= frame_size.y) {
return -1; // Gap between frames.
}
const Point2i frame = position / block_size;
const Size2i frame_count = _get_frame_count();
- if (frame.x < 0 || frame.y < 0 || frame.x >= frame_count.x || frame.y >= frame_count.y) {
- return -1; // Out of bound.
+ if (frame.x >= frame_count.x || frame.y >= frame_count.y) {
+ return -1; // Out of bounds.
}
return frame_count.x * frame.y + frame.x;
@@ -414,16 +418,16 @@ void SpriteFramesEditor::_notification(int p_what) {
load_sheet->set_icon(get_theme_icon(SNAME("SpriteSheet"), SNAME("EditorIcons")));
copy->set_icon(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")));
paste->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
- empty->set_icon(get_theme_icon(SNAME("InsertBefore"), SNAME("EditorIcons")));
- empty2->set_icon(get_theme_icon(SNAME("InsertAfter"), SNAME("EditorIcons")));
+ empty_before->set_icon(get_theme_icon(SNAME("InsertBefore"), SNAME("EditorIcons")));
+ empty_after->set_icon(get_theme_icon(SNAME("InsertAfter"), SNAME("EditorIcons")));
move_up->set_icon(get_theme_icon(SNAME("MoveLeft"), SNAME("EditorIcons")));
move_down->set_icon(get_theme_icon(SNAME("MoveRight"), SNAME("EditorIcons")));
- _delete->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ delete_frame->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
zoom_in->set_icon(get_theme_icon(SNAME("ZoomMore"), SNAME("EditorIcons")));
- new_anim->set_icon(get_theme_icon(SNAME("New"), SNAME("EditorIcons")));
- remove_anim->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ add_anim->set_icon(get_theme_icon(SNAME("New"), SNAME("EditorIcons")));
+ delete_anim->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
anim_search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
split_sheet_zoom_out->set_icon(get_theme_icon(SNAME("ZoomLess"), SNAME("EditorIcons")));
split_sheet_zoom_reset->set_icon(get_theme_icon(SNAME("ZoomReset"), SNAME("EditorIcons")));
@@ -1016,19 +1020,19 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
hide();
}
- new_anim->set_disabled(read_only);
- remove_anim->set_disabled(read_only);
+ add_anim->set_disabled(read_only);
+ delete_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);
+ empty_before->set_disabled(read_only);
+ empty_after->set_disabled(read_only);
move_up->set_disabled(read_only);
move_down->set_disabled(read_only);
- _delete->set_disabled(read_only);
+ delete_frame->set_disabled(read_only);
}
void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
@@ -1095,8 +1099,8 @@ bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &
}
for (int i = 0; i < files.size(); i++) {
- String file = files[i];
- String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
+ String f = files[i];
+ String ftype = EditorFileSystem::get_singleton()->get_file_type(f);
if (!ClassDB::is_parent_class(ftype, "Texture2D")) {
return false;
@@ -1187,18 +1191,16 @@ SpriteFramesEditor::SpriteFramesEditor() {
HBoxContainer *hbc_animlist = memnew(HBoxContainer);
sub_vb->add_child(hbc_animlist);
- new_anim = memnew(Button);
- new_anim->set_flat(true);
- new_anim->set_tooltip_text(TTR("New Animation"));
- hbc_animlist->add_child(new_anim);
- new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add));
+ add_anim = memnew(Button);
+ add_anim->set_flat(true);
+ hbc_animlist->add_child(add_anim);
+ add_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add));
- remove_anim = memnew(Button);
- 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));
+ delete_anim = memnew(Button);
+ delete_anim->set_flat(true);
+ hbc_animlist->add_child(delete_anim);
+ delete_anim->set_disabled(true);
+ delete_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
anim_search_box = memnew(LineEdit);
hbc_animlist->add_child(anim_search_box);
@@ -1215,6 +1217,11 @@ SpriteFramesEditor::SpriteFramesEditor() {
animations->connect("item_edited", callable_mp(this, &SpriteFramesEditor::_animation_name_edited));
animations->set_allow_reselect(true);
+ add_anim->set_shortcut_context(animations);
+ add_anim->set_shortcut(ED_SHORTCUT("sprite_frames/new_animation", TTR("Add Animation"), KeyModifierMask::CMD_OR_CTRL | Key::N));
+ delete_anim->set_shortcut_context(animations);
+ delete_anim->set_shortcut(ED_SHORTCUT("sprite_frames/delete_animation", TTR("Delete Animation"), Key::KEY_DELETE));
+
HBoxContainer *hbc_anim_speed = memnew(HBoxContainer);
hbc_anim_speed->add_child(memnew(Label(TTR("Speed:"))));
vbc_animlist->add_child(hbc_anim_speed);
@@ -1244,54 +1251,45 @@ SpriteFramesEditor::SpriteFramesEditor() {
load = memnew(Button);
load->set_flat(true);
- load->set_tooltip_text(TTR("Add a Texture from File"));
hbc->add_child(load);
load_sheet = memnew(Button);
load_sheet->set_flat(true);
- load_sheet->set_tooltip_text(TTR("Add Frames from a Sprite Sheet"));
hbc->add_child(load_sheet);
hbc->add_child(memnew(VSeparator));
copy = memnew(Button);
copy->set_flat(true);
- copy->set_tooltip_text(TTR("Copy"));
hbc->add_child(copy);
paste = memnew(Button);
paste->set_flat(true);
- paste->set_tooltip_text(TTR("Paste"));
hbc->add_child(paste);
hbc->add_child(memnew(VSeparator));
- empty = memnew(Button);
- empty->set_flat(true);
- empty->set_tooltip_text(TTR("Insert Empty (Before)"));
- hbc->add_child(empty);
+ empty_before = memnew(Button);
+ empty_before->set_flat(true);
+ hbc->add_child(empty_before);
- empty2 = memnew(Button);
- empty2->set_flat(true);
- empty2->set_tooltip_text(TTR("Insert Empty (After)"));
- hbc->add_child(empty2);
+ empty_after = memnew(Button);
+ empty_after->set_flat(true);
+ hbc->add_child(empty_after);
hbc->add_child(memnew(VSeparator));
move_up = memnew(Button);
move_up->set_flat(true);
- move_up->set_tooltip_text(TTR("Move (Before)"));
hbc->add_child(move_up);
move_down = memnew(Button);
move_down->set_flat(true);
- move_down->set_tooltip_text(TTR("Move (After)"));
hbc->add_child(move_down);
- _delete = memnew(Button);
- _delete->set_flat(true);
- _delete->set_tooltip_text(TTR("Delete"));
- hbc->add_child(_delete);
+ delete_frame = memnew(Button);
+ delete_frame->set_flat(true);
+ hbc->add_child(delete_frame);
hbc->add_spacer();
@@ -1333,13 +1331,40 @@ SpriteFramesEditor::SpriteFramesEditor() {
load->connect("pressed", callable_mp(this, &SpriteFramesEditor::_load_pressed));
load_sheet->connect("pressed", callable_mp(this, &SpriteFramesEditor::_open_sprite_sheet));
- _delete->connect("pressed", callable_mp(this, &SpriteFramesEditor::_delete_pressed));
+ delete_frame->connect("pressed", callable_mp(this, &SpriteFramesEditor::_delete_pressed));
copy->connect("pressed", callable_mp(this, &SpriteFramesEditor::_copy_pressed));
paste->connect("pressed", callable_mp(this, &SpriteFramesEditor::_paste_pressed));
- empty->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty_pressed));
- empty2->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty2_pressed));
+ empty_before->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty_pressed));
+ empty_after->connect("pressed", callable_mp(this, &SpriteFramesEditor::_empty2_pressed));
move_up->connect("pressed", callable_mp(this, &SpriteFramesEditor::_up_pressed));
move_down->connect("pressed", callable_mp(this, &SpriteFramesEditor::_down_pressed));
+
+ load->set_shortcut_context(tree);
+ load->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_file", TTR("Add frame from file"), KeyModifierMask::CMD_OR_CTRL | Key::O));
+ load_sheet->set_shortcut_context(tree);
+ load_sheet->set_shortcut(ED_SHORTCUT("sprite_frames/load_from_sheet", TTR("Add frames from sprite sheet"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::O));
+ delete_frame->set_shortcut_context(tree);
+ delete_frame->set_shortcut(ED_SHORTCUT("sprite_frames/delete", TTR("Delete Frame"), Key::KEY_DELETE));
+ copy->set_shortcut_context(tree);
+ copy->set_shortcut(ED_SHORTCUT("sprite_frames/copy", TTR("Copy Frame"), KeyModifierMask::CMD_OR_CTRL | Key::C));
+ paste->set_shortcut_context(tree);
+ paste->set_shortcut(ED_SHORTCUT("sprite_frames/paste", TTR("Paste Frame"), KeyModifierMask::CMD_OR_CTRL | Key::V));
+ empty_before->set_shortcut_context(tree);
+ empty_before->set_shortcut(ED_SHORTCUT("sprite_frames/empty_before", TTR("Insert Empty (Before Selected)"), KeyModifierMask::ALT | Key::LEFT));
+ empty_after->set_shortcut_context(tree);
+ empty_after->set_shortcut(ED_SHORTCUT("sprite_frames/empty_after", TTR("Insert Empty (After Selected)"), KeyModifierMask::ALT | Key::RIGHT));
+ move_up->set_shortcut_context(tree);
+ move_up->set_shortcut(ED_SHORTCUT("sprite_frames/move_left", TTR("Move Frame Left"), KeyModifierMask::CMD_OR_CTRL | Key::LEFT));
+ move_down->set_shortcut_context(tree);
+ move_down->set_shortcut(ED_SHORTCUT("sprite_frames/move_right", TTR("Move Frame Right"), KeyModifierMask::CMD_OR_CTRL | Key::RIGHT));
+
+ zoom_out->set_shortcut_context(tree);
+ zoom_out->set_shortcut(ED_SHORTCUT_ARRAY("sprite_frames/zoom_out", TTR("Zoom Out"),
+ { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::MINUS), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_SUBTRACT) }));
+ zoom_in->set_shortcut_context(tree);
+ zoom_in->set_shortcut(ED_SHORTCUT_ARRAY("sprite_frames/zoom_in", TTR("Zoom In"),
+ { int32_t(KeyModifierMask::CMD_OR_CTRL | Key::EQUAL), int32_t(KeyModifierMask::CMD_OR_CTRL | Key::KP_ADD) }));
+
file->connect("files_selected", callable_mp(this, &SpriteFramesEditor::_file_load_request).bind(-1));
loading_scene = false;
sel = -1;
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 092f556c63..5fc3fe4481 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -61,11 +61,11 @@ class SpriteFramesEditor : public HSplitContainer {
Button *load = nullptr;
Button *load_sheet = nullptr;
- Button *_delete = nullptr;
+ Button *delete_frame = nullptr;
Button *copy = nullptr;
Button *paste = nullptr;
- Button *empty = nullptr;
- Button *empty2 = nullptr;
+ Button *empty_before = nullptr;
+ Button *empty_after = nullptr;
Button *move_up = nullptr;
Button *move_down = nullptr;
Button *zoom_out = nullptr;
@@ -75,8 +75,8 @@ class SpriteFramesEditor : public HSplitContainer {
bool loading_scene;
int sel;
- Button *new_anim = nullptr;
- Button *remove_anim = nullptr;
+ Button *add_anim = nullptr;
+ Button *delete_anim = nullptr;
LineEdit *anim_search_box = nullptr;
Tree *animations = nullptr;
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 9846cd4a84..03cff74bdb 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -108,7 +108,7 @@ void TextEditor::set_edited_resource(const Ref<Resource> &p_res) {
code_editor->update_line_and_column();
}
-void TextEditor::enable_editor() {
+void TextEditor::enable_editor(Control *p_shortcut_context) {
if (editor_enabled) {
return;
}
@@ -116,6 +116,15 @@ void TextEditor::enable_editor() {
editor_enabled = true;
_load_theme_settings();
+
+ if (p_shortcut_context) {
+ for (int i = 0; i < edit_hb->get_child_count(); ++i) {
+ Control *c = cast_to<Control>(edit_hb->get_child(i));
+ if (c) {
+ c->set_shortcut_context(p_shortcut_context);
+ }
+ }
+ }
}
void TextEditor::add_callback(const String &p_function, PackedStringArray p_args) {
@@ -222,6 +231,10 @@ void TextEditor::set_edit_state(const Variant &p_state) {
ensure_focus();
}
+Variant TextEditor::get_navigation_state() {
+ return code_editor->get_navigation_state();
+}
+
void TextEditor::trim_trailing_whitespace() {
code_editor->trim_trailing_whitespace();
}
@@ -436,11 +449,12 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
int row = pos.y;
int col = pos.x;
- tx->set_move_caret_on_right_click_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/move_caret_on_right_click"));
+ tx->set_move_caret_on_right_click_enabled(EDITOR_GET("text_editor/behavior/navigation/move_caret_on_right_click"));
bool can_fold = tx->can_fold_line(row);
bool is_folded = tx->is_line_folded(row);
if (tx->is_move_caret_on_right_click_enabled()) {
+ tx->remove_secondary_carets();
if (tx->has_selection()) {
int from_line = tx->get_selection_from_line();
int to_line = tx->get_selection_to_line();
@@ -467,9 +481,9 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Ref<InputEventKey> k = ev;
if (k.is_valid() && k->is_pressed() && k->is_action("ui_menu", true)) {
CodeEdit *tx = code_editor->get_text_editor();
- int line = tx->get_caret_line();
- tx->adjust_viewport_to_caret();
- _make_context_menu(tx->has_selection(), tx->can_fold_line(line), tx->is_line_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->get_caret_draw_pos()));
+ int line = tx->get_caret_line(0);
+ tx->adjust_viewport_to_caret(0);
+ _make_context_menu(tx->has_selection(0), tx->can_fold_line(line), tx->is_line_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->get_caret_draw_pos(0)));
context_menu->grab_focus();
}
}
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 9ee6a39b2e..486a0f2c23 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -111,12 +111,13 @@ public:
virtual Ref<Texture2D> get_theme_icon() override;
virtual Ref<Resource> get_edited_resource() const override;
virtual void set_edited_resource(const Ref<Resource> &p_res) override;
- virtual void enable_editor() override;
+ virtual void enable_editor(Control *p_shortcut_context = nullptr) override;
virtual void reload_text() override;
virtual void apply_code() override;
virtual bool is_unsaved() override;
virtual Variant get_edit_state() override;
virtual void set_edit_state(const Variant &p_state) override;
+ virtual Variant get_navigation_state() override;
virtual Vector<String> get_functions() override;
virtual PackedInt32Array get_breakpoints() override;
virtual void set_breakpoint(int p_line, bool p_enabled) override{};
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp
index dfd5e76ba6..767eeaefc5 100644
--- a/editor/plugins/text_shader_editor.cpp
+++ b/editor/plugins/text_shader_editor.cpp
@@ -202,12 +202,12 @@ void ShaderTextEditor::set_warnings_panel(RichTextLabel *p_warnings_panel) {
}
void ShaderTextEditor::_load_theme_settings() {
- CodeEdit *text_editor = get_text_editor();
+ CodeEdit *te = get_text_editor();
Color updated_marked_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");
if (updated_marked_line_color != marked_line_color) {
- for (int i = 0; i < text_editor->get_line_count(); i++) {
- if (text_editor->get_line_background_color(i) == marked_line_color) {
- text_editor->set_line_background_color(i, updated_marked_line_color);
+ for (int i = 0; i < te->get_line_count(); i++) {
+ if (te->get_line_background_color(i) == marked_line_color) {
+ te->set_line_background_color(i, updated_marked_line_color);
}
}
marked_line_color = updated_marked_line_color;
@@ -257,14 +257,14 @@ void ShaderTextEditor::_load_theme_settings() {
const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(i));
for (int j = 0; j < modes.size(); j++) {
- const ShaderLanguage::ModeInfo &info = modes[j];
+ const ShaderLanguage::ModeInfo &mode_info = modes[j];
- if (!info.options.is_empty()) {
- for (int k = 0; k < info.options.size(); k++) {
- built_ins.push_back(String(info.name) + "_" + String(info.options[k]));
+ if (!mode_info.options.is_empty()) {
+ for (int k = 0; k < mode_info.options.size(); k++) {
+ built_ins.push_back(String(mode_info.name) + "_" + String(mode_info.options[k]));
}
} else {
- built_ins.push_back(String(info.name));
+ built_ins.push_back(String(mode_info.name));
}
}
}
@@ -278,14 +278,14 @@ void ShaderTextEditor::_load_theme_settings() {
const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
for (int i = 0; i < modes.size(); i++) {
- const ShaderLanguage::ModeInfo &info = modes[i];
+ const ShaderLanguage::ModeInfo &mode_info = modes[i];
- if (!info.options.is_empty()) {
- for (int j = 0; j < info.options.size(); j++) {
- built_ins.push_back(String(info.name) + "_" + String(info.options[j]));
+ if (!mode_info.options.is_empty()) {
+ for (int j = 0; j < mode_info.options.size(); j++) {
+ built_ins.push_back(String(mode_info.name) + "_" + String(mode_info.options[j]));
}
} else {
- built_ins.push_back(String(info.name));
+ built_ins.push_back(String(mode_info.name));
}
}
}
@@ -303,12 +303,12 @@ void ShaderTextEditor::_load_theme_settings() {
syntax_highlighter->add_color_region("//", "", comment_color, true);
syntax_highlighter->set_disabled_branch_color(comment_color);
- text_editor->clear_comment_delimiters();
- text_editor->add_comment_delimiter("/*", "*/", false);
- text_editor->add_comment_delimiter("//", "", true);
+ te->clear_comment_delimiters();
+ te->add_comment_delimiter("/*", "*/", false);
+ te->add_comment_delimiter("//", "", true);
- if (!text_editor->has_auto_brace_completion_open_key("/*")) {
- text_editor->add_auto_brace_completion_pair("/*", "*/");
+ if (!te->has_auto_brace_completion_open_key("/*")) {
+ te->add_auto_brace_completion_pair("/*", "*/");
}
// Colorize preprocessor include strings.
@@ -399,22 +399,22 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
ShaderLanguage sl;
String calltip;
- ShaderLanguage::ShaderCompileInfo info;
- info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
+ ShaderLanguage::ShaderCompileInfo comp_info;
+ comp_info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
if (shader.is_null()) {
- info.is_include = true;
+ comp_info.is_include = true;
- sl.complete(code, info, r_options, calltip);
+ sl.complete(code, comp_info, r_options, calltip);
get_text_editor()->set_code_hint(calltip);
return;
}
_check_shader_mode();
- info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()));
- info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
- info.shader_types = ShaderTypes::get_singleton()->get_types();
+ comp_info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode()));
+ comp_info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
+ comp_info.shader_types = ShaderTypes::get_singleton()->get_types();
- sl.complete(code, info, r_options, calltip);
+ sl.complete(code, comp_info, r_options, calltip);
get_text_editor()->set_code_hint(calltip);
}
@@ -464,22 +464,22 @@ void ShaderTextEditor::_validate_script() {
//preprocessor error
ERR_FAIL_COND(err_positions.size() == 0);
- String error_text = error_pp;
- int error_line = err_positions.front()->get().line;
+ String err_text = error_pp;
+ int err_line = err_positions.front()->get().line;
if (err_positions.size() == 1) {
// Error in main file
- error_text = "error(" + itos(error_line) + "): " + error_text;
+ err_text = "error(" + itos(err_line) + "): " + err_text;
} else {
- error_text = "error(" + itos(error_line) + ") in include " + err_positions.back()->get().file.get_file() + ":" + itos(err_positions.back()->get().line) + ": " + error_text;
+ err_text = "error(" + itos(err_line) + ") in include " + err_positions.back()->get().file.get_file() + ":" + itos(err_positions.back()->get().line) + ": " + err_text;
set_error_count(err_positions.size() - 1);
}
- set_error(error_text);
- set_error_pos(error_line - 1, 0);
+ set_error(err_text);
+ set_error_pos(err_line - 1, 0);
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
}
- get_text_editor()->set_line_background_color(error_line - 1, marked_line_color);
+ get_text_editor()->set_line_background_color(err_line - 1, marked_line_color);
set_warning_count(0);
@@ -507,39 +507,39 @@ void ShaderTextEditor::_validate_script() {
}
sl.set_warning_flags(flags);
- ShaderLanguage::ShaderCompileInfo info;
- info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
+ ShaderLanguage::ShaderCompileInfo comp_info;
+ comp_info.global_shader_uniform_type_func = _get_global_shader_uniform_type;
if (shader.is_null()) {
- info.is_include = true;
+ comp_info.is_include = true;
} else {
Shader::Mode mode = shader->get_mode();
- info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(mode));
- info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(mode));
- info.shader_types = ShaderTypes::get_singleton()->get_types();
+ comp_info.functions = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(mode));
+ comp_info.render_modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(mode));
+ comp_info.shader_types = ShaderTypes::get_singleton()->get_types();
}
code = code_pp;
//compiler error
- last_compile_result = sl.compile(code, info);
+ last_compile_result = sl.compile(code, comp_info);
if (last_compile_result != OK) {
- String error_text;
- int error_line;
+ String err_text;
+ int err_line;
Vector<ShaderLanguage::FilePosition> include_positions = sl.get_include_positions();
if (include_positions.size() > 1) {
//error is in an include
- error_line = include_positions[0].line;
- error_text = "error(" + itos(error_line) + ") in include " + include_positions[include_positions.size() - 1].file + ":" + itos(include_positions[include_positions.size() - 1].line) + ": " + sl.get_error_text();
+ err_line = include_positions[0].line;
+ err_text = "error(" + itos(err_line) + ") in include " + include_positions[include_positions.size() - 1].file + ":" + itos(include_positions[include_positions.size() - 1].line) + ": " + sl.get_error_text();
set_error_count(include_positions.size() - 1);
} else {
- error_line = sl.get_error_line();
- error_text = "error(" + itos(error_line) + "): " + sl.get_error_text();
+ err_line = sl.get_error_line();
+ err_text = "error(" + itos(err_line) + "): " + sl.get_error_text();
set_error_count(0);
}
- set_error(error_text);
- set_error_pos(error_line - 1, 0);
- get_text_editor()->set_line_background_color(error_line - 1, marked_line_color);
+ set_error(err_text);
+ set_error_pos(err_line - 1, 0);
+ get_text_editor()->set_line_background_color(err_line - 1, marked_line_color);
} else {
set_error("");
}
@@ -715,7 +715,7 @@ void TextShaderEditor::_notification(int p_what) {
popup->set_item_icon(popup->get_item_index(HELP_DOCS), get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
} break;
- case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ case NOTIFICATION_APPLICATION_FOCUS_IN: {
_check_for_external_edit();
} break;
}
@@ -724,7 +724,7 @@ void TextShaderEditor::_notification(int p_what) {
void TextShaderEditor::_editor_settings_changed() {
shader_editor->update_editor_settings();
- shader_editor->get_text_editor()->add_theme_constant_override("line_spacing", EditorSettings::get_singleton()->get("text_editor/appearance/whitespace/line_spacing"));
+ shader_editor->get_text_editor()->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing"));
shader_editor->get_text_editor()->set_draw_breakpoints_gutter(false);
shader_editor->get_text_editor()->set_draw_executing_lines_gutter(false);
}
@@ -917,6 +917,10 @@ bool TextShaderEditor::is_unsaved() const {
return shader_editor->get_text_editor()->get_saved_version() != shader_editor->get_text_editor()->get_version();
}
+void TextShaderEditor::tag_saved_version() {
+ shader_editor->get_text_editor()->tag_saved_version();
+}
+
void TextShaderEditor::apply_shaders() {
String editor_code = shader_editor->get_text_editor()->get_text();
if (shader.is_valid()) {
@@ -951,9 +955,10 @@ void TextShaderEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
Point2i pos = tx->get_line_column_at_pos(mb->get_global_position() - tx->get_global_position());
int row = pos.y;
int col = pos.x;
- tx->set_move_caret_on_right_click_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/move_caret_on_right_click"));
+ tx->set_move_caret_on_right_click_enabled(EDITOR_GET("text_editor/behavior/navigation/move_caret_on_right_click"));
if (tx->is_move_caret_on_right_click_enabled()) {
+ tx->remove_secondary_carets();
if (tx->has_selection()) {
int from_line = tx->get_selection_from_line();
int to_line = tx->get_selection_to_line();
@@ -1063,7 +1068,7 @@ TextShaderEditor::TextShaderEditor() {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &TextShaderEditor::_editor_settings_changed));
ProjectSettingsEditor::get_singleton()->connect("confirmed", callable_mp(this, &TextShaderEditor::_project_settings_changed));
- shader_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"));
+ shader_editor->get_text_editor()->set_code_hint_draw_below(EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"));
shader_editor->get_text_editor()->set_symbol_lookup_on_click_enabled(true);
shader_editor->get_text_editor()->set_context_menu_enabled(false);
diff --git a/editor/plugins/text_shader_editor.h b/editor/plugins/text_shader_editor.h
index abeaff1fff..c2094342ed 100644
--- a/editor/plugins/text_shader_editor.h
+++ b/editor/plugins/text_shader_editor.h
@@ -190,6 +190,7 @@ public:
void save_external_data(const String &p_str = "");
void validate_script();
bool is_unsaved() const;
+ void tag_saved_version();
virtual Size2 get_minimum_size() const override { return Size2(0, 200); }
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index be382759f5..4aed7a92a2 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "texture_editor_plugin.h"
-
#include "editor/editor_scale.h"
TextureRect *TexturePreview::get_texture_display() {
@@ -123,6 +122,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
add_child(checkerboard);
texture_display = memnew(TextureRect);
+ texture_display->set_texture_filter(TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
texture_display->set_texture(p_texture);
texture_display->set_anchors_preset(TextureRect::PRESET_FULL_RECT);
texture_display->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 8e04391a94..a7a8d526d0 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -86,8 +86,8 @@ void TextureRegionEditor::_region_draw() {
mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
- edit_draw->draw_rect(Rect2(Point2(), base_tex->get_size()), Color(0.5, 0.5, 0.5, 0.5), false);
- edit_draw->draw_texture(base_tex, Point2());
+ edit_draw->draw_rect(Rect2(Point2(), preview_tex->get_size()), Color(0.5, 0.5, 0.5, 0.5), false);
+ edit_draw->draw_texture(preview_tex, Point2());
RS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
const Color color = get_theme_color(SNAME("mono_color"), SNAME("Editor"));
@@ -835,7 +835,7 @@ void TextureRegionEditor::_notification(int p_what) {
[[fallthrough]];
}
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
@@ -905,6 +905,13 @@ void TextureRegionEditor::edit(Object *p_obj) {
if (atlas_tex.is_valid()) {
atlas_tex->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
+
+ node_sprite_2d = nullptr;
+ node_sprite_3d = nullptr;
+ node_ninepatch = nullptr;
+ obj_styleBox = Ref<StyleBoxTexture>(nullptr);
+ atlas_tex = Ref<AtlasTexture>(nullptr);
+
if (p_obj) {
node_sprite_2d = Object::cast_to<Sprite2D>(p_obj);
node_sprite_3d = Object::cast_to<Sprite3D>(p_obj);
@@ -926,13 +933,8 @@ void TextureRegionEditor::edit(Object *p_obj) {
p_obj->connect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed));
}
_edit_region();
- } else {
- node_sprite_2d = nullptr;
- node_sprite_3d = nullptr;
- node_ninepatch = nullptr;
- obj_styleBox = Ref<StyleBoxTexture>(nullptr);
- atlas_tex = Ref<AtlasTexture>(nullptr);
}
+
edit_draw->queue_redraw();
popup_centered_ratio(0.5);
request_center = true;
@@ -946,20 +948,80 @@ void TextureRegionEditor::_texture_changed() {
}
void TextureRegionEditor::_edit_region() {
+ CanvasItem::TextureFilter filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS;
+
Ref<Texture2D> texture = nullptr;
if (atlas_tex.is_valid()) {
texture = atlas_tex->get_atlas();
} else if (node_sprite_2d) {
texture = node_sprite_2d->get_texture();
+ filter = node_sprite_2d->get_texture_filter_in_tree();
} else if (node_sprite_3d) {
texture = node_sprite_3d->get_texture();
+
+ StandardMaterial3D::TextureFilter filter_3d = node_sprite_3d->get_texture_filter();
+
+ switch (filter_3d) {
+ case StandardMaterial3D::TEXTURE_FILTER_NEAREST:
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST;
+ break;
+ case StandardMaterial3D::TEXTURE_FILTER_LINEAR:
+ filter = CanvasItem::TEXTURE_FILTER_LINEAR;
+ break;
+ case StandardMaterial3D::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS;
+ break;
+ case StandardMaterial3D::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
+ filter = CanvasItem::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
+ break;
+ case StandardMaterial3D::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC;
+ break;
+ case StandardMaterial3D::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
+ filter = CanvasItem::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC;
+ break;
+ default:
+ // fallback to project default
+ filter = CanvasItem::TEXTURE_FILTER_PARENT_NODE;
+ break;
+ }
} else if (node_ninepatch) {
texture = node_ninepatch->get_texture();
+ filter = node_ninepatch->get_texture_filter_in_tree();
} else if (obj_styleBox.is_valid()) {
texture = obj_styleBox->get_texture();
}
+ // occurs when get_texture_filter_in_tree reaches the scene root
+ if (filter == CanvasItem::TEXTURE_FILTER_PARENT_NODE) {
+ SubViewport *root = EditorNode::get_singleton()->get_scene_root();
+
+ if (root != nullptr) {
+ Viewport::DefaultCanvasItemTextureFilter filter_default = root->get_default_canvas_item_texture_filter();
+
+ // depending on default filter, set filter to match, otherwise fall back on nearest w/ mipmaps
+ switch (filter_default) {
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST:
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST;
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR:
+ filter = CanvasItem::TEXTURE_FILTER_LINEAR;
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
+ filter = CanvasItem::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
+ default:
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS;
+ break;
+ }
+ } else {
+ filter = CanvasItem::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS;
+ }
+ }
+
if (texture.is_null()) {
+ preview_tex->set_diffuse_texture(nullptr);
_zoom_reset();
hscroll->hide();
vscroll->hide();
@@ -967,6 +1029,9 @@ void TextureRegionEditor::_edit_region() {
return;
}
+ preview_tex->set_texture_filter(filter);
+ preview_tex->set_diffuse_texture(texture);
+
if (cache_map.has(texture->get_rid())) {
autoslice_cache = cache_map[texture->get_rid()];
autoslice_is_dirty = false;
@@ -1002,6 +1067,8 @@ TextureRegionEditor::TextureRegionEditor() {
atlas_tex = Ref<AtlasTexture>(nullptr);
undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ preview_tex = Ref<CanvasTexture>(memnew(CanvasTexture));
+
snap_step = Vector2(10, 10);
snap_separation = Vector2(0, 0);
snap_mode = SNAP_NONE;
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index e3bbaf49fc..7eda4f469f 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -86,6 +86,8 @@ class TextureRegionEditor : public AcceptDialog {
Ref<StyleBoxTexture> obj_styleBox;
Ref<AtlasTexture> atlas_tex;
+ Ref<CanvasTexture> preview_tex;
+
Rect2 rect;
Rect2 rect_prev;
float prev_margin = 0.0f;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index e2ed8e44c4..5d02e4e437 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -2481,7 +2481,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = color_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
color_items_list->remove_child(node);
}
@@ -2510,7 +2510,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = constant_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
constant_items_list->remove_child(node);
}
@@ -2543,7 +2543,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = font_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = font_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
font_items_list->remove_child(node);
}
@@ -2581,7 +2581,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = font_size_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = font_size_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
font_size_items_list->remove_child(node);
}
@@ -2614,7 +2614,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = icon_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
icon_items_list->remove_child(node);
}
@@ -2652,7 +2652,7 @@ void ThemeTypeEditor::_update_type_items() {
{
for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) {
Node *node = stylebox_items_list->get_child(i);
- node->queue_delete();
+ node->queue_free();
stylebox_items_list->remove_child(node);
}
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index 8cc96201e7..fdd8a80ad3 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -459,7 +459,7 @@ void SceneThemeEditorPreview::_reload_scene() {
for (int i = preview_content->get_child_count() - 1; i >= 0; i--) {
Node *node = preview_content->get_child(i);
- node->queue_delete();
+ node->queue_free();
preview_content->remove_child(node);
}
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index d7e08db954..167c6d169b 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -47,9 +47,7 @@ void AtlasMergingDialog::_generate_merged(Vector<Ref<TileSetAtlasSource>> p_atla
merged_mapping.clear();
if (p_atlas_sources.size() >= 2) {
- Ref<Image> output_image;
- output_image.instantiate();
- output_image->create(1, 1, false, Image::FORMAT_RGBA8);
+ Ref<Image> output_image = Image::create_empty(1, 1, false, Image::FORMAT_RGBA8);
// Compute the new texture region size.
Vector2i new_texture_region_size;
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index c823487279..69104cadec 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -298,7 +298,7 @@ void TileAtlasView::_draw_base_tiles_texture_grid() {
void TileAtlasView::_draw_base_tiles_shape_grid() {
// Draw the shapes.
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Vector2i tile_shape_size = tile_set->get_tile_size();
for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
@@ -509,7 +509,7 @@ void TileAtlasView::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
} break;
case NOTIFICATION_READY: {
@@ -533,11 +533,11 @@ TileAtlasView::TileAtlasView() {
panel->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(panel);
- // Scrollingsc
zoom_widget = memnew(EditorZoomWidget);
add_child(zoom_widget);
zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE);
zoom_widget->connect("zoom_changed", callable_mp(this, &TileAtlasView::_zoom_widget_changed).unbind(1));
+ zoom_widget->set_shortcut_context(this);
button_center_view = memnew(Button);
button_center_view->set_icon(get_theme_icon(SNAME("CenterView"), SNAME("EditorIcons")));
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index d0f8e1f32d..a7d90856ac 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -128,7 +128,7 @@ void GenericTilePolygonEditor::_base_control_draw() {
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorPathSharpHandle"), SNAME("EditorIcons"));
const Ref<Texture2D> add_handle = get_theme_icon(SNAME("EditorHandleAdd"), SNAME("EditorIcons"));
const Ref<StyleBox> focus_stylebox = get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"));
@@ -212,8 +212,8 @@ void GenericTilePolygonEditor::_base_control_draw() {
for (int i = 0; i < (int)polygons.size(); i++) {
const Vector<Vector2> &polygon = polygons[i];
for (int j = 0; j < polygon.size(); j++) {
- const Color modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.5, 1, 2) : Color(1, 1, 1);
- base_control->draw_texture(handle, xform.xform(polygon[j]) - handle->get_size() / 2, modulate);
+ const Color poly_modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.5, 1, 2) : Color(1, 1, 1);
+ base_control->draw_texture(handle, xform.xform(polygon[j]) - handle->get_size() / 2, poly_modulate);
}
}
}
@@ -831,6 +831,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
editor_zoom_widget = memnew(EditorZoomWidget);
editor_zoom_widget->set_position(Vector2(5, 5));
editor_zoom_widget->connect("zoom_changed", callable_mp(this, &GenericTilePolygonEditor::_zoom_changed).unbind(1));
+ editor_zoom_widget->set_shortcut_context(this);
root->add_child(editor_zoom_widget);
button_center_view = memnew(Button);
@@ -884,7 +885,7 @@ void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_s
void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) {
if (drag_type == DRAG_TYPE_PAINT_RECT) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
p_canvas_item->draw_set_transform_matrix(p_transform);
@@ -1116,7 +1117,7 @@ void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2
Color color = Color(1, 1, 1);
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
selection_color.set_v(0.9);
color = selection_color;
@@ -1140,7 +1141,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p
// Update everything.
if (property_editor) {
- property_editor->queue_delete();
+ property_editor->queue_free();
}
// Update the dummy object.
@@ -1199,7 +1200,7 @@ TileDataDefaultEditor::TileDataDefaultEditor() {
}
TileDataDefaultEditor::~TileDataDefaultEditor() {
- toolbar->queue_delete();
+ toolbar->queue_free();
memdelete(dummy_object);
}
@@ -1210,7 +1211,7 @@ void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran
Vector2i tile_set_tile_size = tile_set->get_tile_size();
Color color = Color(1.0, 0.0, 0.0);
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
color = selection_color;
}
@@ -1232,7 +1233,7 @@ void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform
Color color = Color(1.0, 1.0, 1.0);
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
color = selection_color;
}
@@ -1246,7 +1247,7 @@ void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D
Color color = Color(1.0, 1.0, 1.0);
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
color = selection_color;
}
@@ -1258,7 +1259,7 @@ void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Tra
TileData *tile_data = _get_tile_data(p_cell);
ERR_FAIL_COND(!tile_data);
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
Color color = grid_color.darkened(0.2);
if (p_selected) {
@@ -1402,11 +1403,11 @@ void TileDataCollisionEditor::_polygons_changed() {
dummy_object->remove_dummy_property(vformat("polygon_%d_one_way_margin", i));
}
for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way", i)); i++) {
- property_editors[vformat("polygon_%d_one_way", i)]->queue_delete();
+ property_editors[vformat("polygon_%d_one_way", i)]->queue_free();
property_editors.erase(vformat("polygon_%d_one_way", i));
}
for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way_margin", i)); i++) {
- property_editors[vformat("polygon_%d_one_way_margin", i)]->queue_delete();
+ property_editors[vformat("polygon_%d_one_way_margin", i)]->queue_free();
property_editors.erase(vformat("polygon_%d_one_way_margin", i));
}
}
@@ -1577,7 +1578,7 @@ void TileDataCollisionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfor
// Draw all shapes.
Vector<Color> color;
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
selection_color.a = 0.7;
color.push_back(selection_color);
@@ -1750,7 +1751,7 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) {
// Draw selection rectangle.
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
p_canvas_item->draw_set_transform_matrix(p_transform);
@@ -2657,32 +2658,32 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() {
}
TileDataTerrainsEditor::~TileDataTerrainsEditor() {
- toolbar->queue_delete();
+ toolbar->queue_free();
memdelete(dummy_object);
}
Variant TileDataNavigationEditor::_get_painted_value() {
- Ref<NavigationPolygon> navigation_polygon;
- navigation_polygon.instantiate();
+ Ref<NavigationPolygon> nav_polygon;
+ nav_polygon.instantiate();
for (int i = 0; i < polygon_editor->get_polygon_count(); i++) {
Vector<Vector2> polygon = polygon_editor->get_polygon(i);
- navigation_polygon->add_outline(polygon);
+ nav_polygon->add_outline(polygon);
}
- navigation_polygon->make_polygons_from_outlines();
- return navigation_polygon;
+ nav_polygon->make_polygons_from_outlines();
+ return nav_polygon;
}
void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
+ Ref<NavigationPolygon> nav_polygon = tile_data->get_navigation_polygon(navigation_layer);
polygon_editor->clear_polygons();
- if (navigation_polygon.is_valid()) {
- for (int i = 0; i < navigation_polygon->get_outline_count(); i++) {
- polygon_editor->add_polygon(navigation_polygon->get_outline(i));
+ if (nav_polygon.is_valid()) {
+ for (int i = 0; i < nav_polygon->get_outline_count(); i++) {
+ polygon_editor->add_polygon(nav_polygon->get_outline(i));
}
}
polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
@@ -2691,8 +2692,8 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set
void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
ERR_FAIL_COND(!tile_data);
- Ref<NavigationPolygon> navigation_polygon = p_value;
- tile_data->set_navigation_polygon(navigation_layer, navigation_polygon);
+ Ref<NavigationPolygon> nav_polygon = p_value;
+ tile_data->set_navigation_polygon(navigation_layer, nav_polygon);
polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
}
@@ -2740,9 +2741,9 @@ void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfo
// Draw all shapes.
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer);
- if (navigation_polygon.is_valid()) {
- Vector<Vector2> verts = navigation_polygon->get_vertices();
+ Ref<NavigationPolygon> nav_polygon = tile_data->get_navigation_polygon(navigation_layer);
+ if (nav_polygon.is_valid()) {
+ Vector<Vector2> verts = nav_polygon->get_vertices();
if (verts.size() < 3) {
return;
}
@@ -2752,16 +2753,16 @@ void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfo
color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
#endif // DEBUG_ENABLED
if (p_selected) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
selection_color.a = 0.7;
color = selection_color;
}
RandomPCG rand;
- for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) {
+ for (int i = 0; i < nav_polygon->get_polygon_count(); i++) {
// An array of vertices for this polygon.
- Vector<int> polygon = navigation_polygon->get_polygon(i);
+ Vector<int> polygon = nav_polygon->get_polygon(i);
Vector<Vector2> vertices;
vertices.resize(polygon.size());
for (int j = 0; j < polygon.size(); j++) {
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index acfa8b3d00..57416ff55f 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -396,7 +396,7 @@ void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
}
// Icon size update.
- int int_size = int(EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
+ int int_size = int(EDITOR_GET("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size));
}
@@ -460,7 +460,7 @@ void TileMapEditorTilesPlugin::_update_theme() {
source_sort_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Sort"), SNAME("EditorIcons")));
select_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
paint_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- line_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
+ line_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Line"), SNAME("EditorIcons")));
rect_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
bucket_tool_button->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
@@ -739,7 +739,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
// Do nothing
} else {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
tile_map->draw_cells_outline(p_overlay, tile_map_selection, selection_color, xform);
}
@@ -844,9 +844,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
const int fading = 5;
// Draw the lines of the grid behind the preview.
- bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ bool display_grid = EDITOR_GET("editors/tiles_editor/display_grid");
if (display_grid) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) {
drawn_grid_rect = drawn_grid_rect.grow(fading);
for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) {
@@ -1682,7 +1682,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
}
// Draw the selection.
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
for (const TileMapCell &E : tile_set_selection) {
if (E.source_id == source_id && E.alternative_tile == 0) {
@@ -2002,6 +2002,7 @@ void TileMapEditorTilesPlugin::_set_source_sort(int p_sort) {
}
TilesEditorPlugin::get_singleton()->set_sorting_option(p_sort);
_update_tile_set_sources_list();
+ EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "tile_source_sort", p_sort);
}
void TileMapEditorTilesPlugin::_bind_methods() {
@@ -2347,27 +2348,27 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_path_o
}
HashMap<Vector2i, TileMapCell> output;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- if (painted_set.has(E.key)) {
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
- bool keep_old = false;
- TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get tile data.
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
- if (tile_data && tile_data->get_terrains_pattern() == E.value) {
- keep_old = true;
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
}
}
}
- if (!keep_old) {
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ if (in_map_terrain_pattern != kv.value) {
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
}
}
}
@@ -2394,24 +2395,28 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTerrainsPlugin::_draw_terrain_patter
}
HashMap<Vector2i, TileMapCell> output;
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- if (painted_set.has(E.key)) {
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
// Paint a random tile with the correct terrain for the painted path.
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
} else {
// Avoids updating the painted path from the output if the new pattern is the same as before.
- TileMapCell cell = tile_map->get_cell(tile_map_layer, E.key);
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = tile_map->get_cell(tile_map_layer, kv.key);
if (cell.source_id != TileSet::INVALID_SOURCE) {
TileSetSource *source = *tile_set->get_source(cell.source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
// Get tile data.
TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
- if (tile_data && !(tile_data->get_terrains_pattern() == E.value)) {
- output[E.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
}
}
}
+ if (in_map_terrain_pattern != kv.value) {
+ output[kv.key] = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ }
}
}
return output;
@@ -3018,9 +3023,9 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
const int fading = 5;
// Draw the lines of the grid behind the preview.
- bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ bool display_grid = EDITOR_GET("editors/tiles_editor/display_grid");
if (display_grid) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
if (drawn_grid_rect.size.x > 0 && drawn_grid_rect.size.y > 0) {
drawn_grid_rect = drawn_grid_rect.grow(fading);
for (int x = drawn_grid_rect.position.x; x < (drawn_grid_rect.position.x + drawn_grid_rect.size.x); x++) {
@@ -3190,10 +3195,10 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
TreeItem *selected_tree_item = terrains_tree->get_selected();
if (selected_tree_item && selected_tree_item->get_metadata(0)) {
Dictionary metadata_dict = selected_tree_item->get_metadata(0);
- int selected_terrain_set = metadata_dict["terrain_set"];
- int selected_terrain_id = metadata_dict["terrain_id"];
- ERR_FAIL_INDEX(selected_terrain_set, tile_set->get_terrain_sets_count());
- ERR_FAIL_INDEX(selected_terrain_id, tile_set->get_terrains_count(selected_terrain_set));
+ int sel_terrain_set = metadata_dict["terrain_set"];
+ int sel_terrain_id = metadata_dict["terrain_id"];
+ ERR_FAIL_INDEX(sel_terrain_set, tile_set->get_terrain_sets_count());
+ ERR_FAIL_INDEX(sel_terrain_id, tile_set->get_terrains_count(sel_terrain_set));
// Add the two first generic modes
int item_index = terrains_tile_list->add_icon_item(main_vbox_container->get_theme_icon(SNAME("TerrainConnect"), SNAME("EditorIcons")));
@@ -3211,13 +3216,13 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
// Sort the items in a map by the number of corresponding terrains.
RBMap<int, RBSet<TileSet::TerrainsPattern>> sorted;
- for (const TileSet::TerrainsPattern &E : per_terrain_terrains_patterns[selected_terrain_set][selected_terrain_id]) {
+ for (const TileSet::TerrainsPattern &E : per_terrain_terrains_patterns[sel_terrain_set][sel_terrain_id]) {
// Count the number of matching sides/terrains.
int count = 0;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
- if (tile_set->is_valid_terrain_peering_bit(selected_terrain_set, bit) && E.get_terrain_peering_bit(bit) == selected_terrain_id) {
+ if (tile_set->is_valid_terrain_peering_bit(sel_terrain_set, bit) && E.get_terrain_peering_bit(bit) == sel_terrain_id) {
count++;
}
}
@@ -3234,7 +3239,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
bool transpose = false;
double max_probability = -1.0;
- for (const TileMapCell &cell : tile_set->get_tiles_for_terrains_pattern(selected_terrain_set, terrains_pattern)) {
+ for (const TileMapCell &cell : tile_set->get_tiles_for_terrains_pattern(sel_terrain_set, terrains_pattern)) {
Ref<TileSetSource> source = tile_set->get_source(cell.source_id);
Ref<TileSetAtlasSource> atlas_source = source;
@@ -3276,7 +3281,7 @@ void TileMapEditorTerrainsPlugin::_update_tiles_list() {
void TileMapEditorTerrainsPlugin::_update_theme() {
paint_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- line_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")));
+ line_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Line"), SNAME("EditorIcons")));
rect_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Rectangle"), SNAME("EditorIcons")));
bucket_tool_button->set_icon(main_vbox_container->get_theme_icon(SNAME("Bucket"), SNAME("EditorIcons")));
@@ -3415,7 +3420,7 @@ void TileMapEditor::_notification(int p_what) {
warning_pattern_texture = get_theme_icon(SNAME("WarningPattern"), SNAME("EditorIcons"));
advanced_menu_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
toggle_grid_button->set_icon(get_theme_icon(SNAME("Grid"), SNAME("EditorIcons")));
- toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
+ toggle_grid_button->set_pressed(EDITOR_GET("editors/tiles_editor/display_grid"));
toggle_highlight_selected_layer_button->set_icon(get_theme_icon(SNAME("TileMapHighlightSelected"), SNAME("EditorIcons")));
} break;
@@ -3430,7 +3435,7 @@ void TileMapEditor::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- toggle_grid_button->set_pressed(EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid"));
+ toggle_grid_button->set_pressed(EDITOR_GET("editors/tiles_editor/display_grid"));
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -3689,8 +3694,8 @@ void TileMapEditor::_update_layers_selection() {
}
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo.is_null());
+ Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo_man.is_null());
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
if (!tile_map) {
@@ -3721,12 +3726,12 @@ void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_
end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
}
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
// Save layers' properties.
if (p_from_index < 0) {
- undo_redo->add_undo_method(tile_map, "remove_layer", p_to_pos < 0 ? tile_map->get_layers_count() : p_to_pos);
+ undo_redo_man->add_undo_method(tile_map, "remove_layer", p_to_pos < 0 ? tile_map->get_layers_count() : p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_undo_method(tile_map, "add_layer", p_from_index);
+ undo_redo_man->add_undo_method(tile_map, "add_layer", p_from_index);
}
List<PropertyInfo> properties;
@@ -3752,11 +3757,11 @@ void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_
#undef ADD_UNDO
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_map, "add_layer", p_to_pos);
+ undo_redo_man->add_do_method(tile_map, "add_layer", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_map, "remove_layer", p_from_index);
+ undo_redo_man->add_do_method(tile_map, "remove_layer", p_from_index);
} else {
- undo_redo->add_do_method(tile_map, "move_layer", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(tile_map, "move_layer", p_from_index, p_to_pos);
}
}
@@ -3873,9 +3878,9 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
// Draw the grid.
- bool display_grid = EditorSettings::get_singleton()->get("editors/tiles_editor/display_grid");
+ bool display_grid = EDITOR_GET("editors/tiles_editor/display_grid");
if (display_grid) {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
for (int x = displayed_rect.position.x; x < (displayed_rect.position.x + displayed_rect.size.x); x++) {
for (int y = displayed_rect.position.y; y < (displayed_rect.position.y + displayed_rect.size.y); y++) {
Vector2i pos_in_rect = Vector2i(x, y) - displayed_rect.position;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 45b2a5eb14..f1dfba6f35 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -561,9 +561,9 @@ void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
void TileSetAtlasSourceEditor::_update_atlas_source_inspector() {
// Update visibility.
- bool visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button;
- atlas_source_inspector_label->set_visible(visible);
- atlas_source_inspector->set_visible(visible);
+ bool inspector_visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button;
+ atlas_source_inspector_label->set_visible(inspector_visible);
+ atlas_source_inspector->set_visible(inspector_visible);
}
void TileSetAtlasSourceEditor::_update_tile_inspector() {
@@ -671,7 +671,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
}
for (int i = tile_set->get_occlusion_layers_count(); tile_data_editors.has(vformat("occlusion_layer_%d", i)); i++) {
- tile_data_editors[vformat("occlusion_layer_%d", i)]->queue_delete();
+ tile_data_editors[vformat("occlusion_layer_%d", i)]->queue_free();
tile_data_editors.erase(vformat("occlusion_layer_%d", i));
}
@@ -710,7 +710,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
}
for (int i = tile_set->get_physics_layers_count(); tile_data_editors.has(vformat("physics_layer_%d", i)); i++) {
- tile_data_editors[vformat("physics_layer_%d", i)]->queue_delete();
+ tile_data_editors[vformat("physics_layer_%d", i)]->queue_free();
tile_data_editors.erase(vformat("physics_layer_%d", i));
}
@@ -728,7 +728,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
}
for (int i = tile_set->get_navigation_layers_count(); tile_data_editors.has(vformat("navigation_layer_%d", i)); i++) {
- tile_data_editors[vformat("navigation_layer_%d", i)]->queue_delete();
+ tile_data_editors[vformat("navigation_layer_%d", i)]->queue_free();
tile_data_editors.erase(vformat("navigation_layer_%d", i));
}
@@ -750,7 +750,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() {
}
}
for (int i = tile_set->get_custom_data_layers_count(); tile_data_editors.has(vformat("custom_data_%d", i)); i++) {
- tile_data_editors[vformat("custom_data_%d", i)]->queue_delete();
+ tile_data_editors[vformat("custom_data_%d", i)]->queue_free();
tile_data_editors.erase(vformat("custom_data_%d", i));
}
@@ -884,7 +884,7 @@ void TileSetAtlasSourceEditor::_update_atlas_view() {
// Create a bunch of buttons to add alternative tiles.
for (int i = 0; i < alternative_tiles_control->get_child_count(); i++) {
- alternative_tiles_control->get_child(i)->queue_delete();
+ alternative_tiles_control->get_child(i)->queue_free();
}
Vector2i pos;
@@ -1667,7 +1667,7 @@ Array TileSetAtlasSourceEditor::_get_selection_as_array() {
void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
// Colors.
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
// Draw the selected tile.
@@ -1958,7 +1958,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() {
}
void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
- Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
+ Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
// Update the hovered alternative tile.
@@ -2043,6 +2043,13 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
}
void TileSetAtlasSourceEditor::_tile_set_changed() {
+ if (tile_set->get_source_count() == 0) {
+ // No sources, so nothing to do here anymore.
+ tile_set->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
+ tile_set = Ref<TileSet>();
+ return;
+ }
+
tile_set_changed_needs_update = true;
}
@@ -2060,14 +2067,14 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what)
}
void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo.is_valid());
+ Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo_man.is_valid());
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
if (tile_data_proxy) {
- UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo;
+ UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(tile_data_proxy).undo_redo;
internal_undo_redo->start_force_keep_in_merge_ends();
Vector<String> components = String(p_property).split("/", true, 2);
@@ -2100,7 +2107,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
ERR_FAIL_COND(!atlas_source);
- UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo;
+ UndoRedo *internal_undo_redo = undo_redo_man->get_history_for_object(atlas_source).undo_redo;
internal_undo_redo->start_force_keep_in_merge_ends();
PackedVector2Array arr;
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 7394288fcd..5e25d343b0 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -407,11 +407,11 @@ void TileSetEditor::_tab_changed(int p_tab_changed) {
}
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo.is_null());
+ Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo_man.is_null());
- TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
- if (!tile_set) {
+ TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited);
+ if (!ed_tile_set) {
return;
}
@@ -421,18 +421,18 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
int begin = 0;
int end;
if (p_array_prefix == "occlusion_layer_") {
- end = tile_set->get_occlusion_layers_count();
+ end = ed_tile_set->get_occlusion_layers_count();
} else if (p_array_prefix == "physics_layer_") {
- end = tile_set->get_physics_layers_count();
+ end = ed_tile_set->get_physics_layers_count();
} else if (p_array_prefix == "terrain_set_") {
- end = tile_set->get_terrain_sets_count();
+ end = ed_tile_set->get_terrain_sets_count();
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
int terrain_set = components[0].trim_prefix("terrain_set_").to_int();
- end = tile_set->get_terrains_count(terrain_set);
+ end = ed_tile_set->get_terrains_count(terrain_set);
} else if (p_array_prefix == "navigation_layer_") {
- end = tile_set->get_navigation_layers_count();
+ end = ed_tile_set->get_navigation_layers_count();
} else if (p_array_prefix == "custom_data_layer_") {
- end = tile_set->get_custom_data_layers_count();
+ end = ed_tile_set->get_custom_data_layers_count();
} else {
ERR_FAIL_MSG("Invalid array prefix for TileSet.");
}
@@ -452,10 +452,10 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
end = MIN(MAX(p_from_index, p_to_pos) + 1, end);
}
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
+#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
// Save layers' properties.
List<PropertyInfo> properties;
- tile_set->get_property_list(&properties);
+ ed_tile_set->get_property_list(&properties);
for (PropertyInfo pi : properties) {
if (pi.name.begins_with(p_array_prefix)) {
String str = pi.name.trim_prefix(p_array_prefix);
@@ -469,17 +469,17 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
if (to_char_index > 0) {
int array_index = str.left(to_char_index).to_int();
if (array_index >= begin && array_index < end) {
- ADD_UNDO(tile_set, pi.name);
+ ADD_UNDO(ed_tile_set, pi.name);
}
}
}
}
// Save properties for TileSetAtlasSources tile data
- for (int i = 0; i < tile_set->get_source_count(); i++) {
- int source_id = tile_set->get_source_id(i);
+ for (int i = 0; i < ed_tile_set->get_source_count(); i++) {
+ int source_id = ed_tile_set->get_source_id(i);
- Ref<TileSetAtlasSource> tas = tile_set->get_source(source_id);
+ Ref<TileSetAtlasSource> tas = ed_tile_set->get_source(source_id);
if (tas.is_valid()) {
for (int j = 0; j < tas->get_tiles_count(); j++) {
Vector2i tile_id = tas->get_tile_id(j);
@@ -537,68 +537,68 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
// Add do method.
if (p_array_prefix == "occlusion_layer_") {
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_occlusion_layer", p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_occlusion_layer", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_occlusion_layer", p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_occlusion_layer", p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_occlusion_layer", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_occlusion_layer", p_from_index, p_to_pos);
}
} else if (p_array_prefix == "physics_layer_") {
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_physics_layer", p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_physics_layer", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_physics_layer", p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_physics_layer", p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_physics_layer", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_physics_layer", p_from_index, p_to_pos);
}
} else if (p_array_prefix == "terrain_set_") {
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_terrain_set", p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_terrain_set", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_terrain_set", p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_terrain_set", p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_terrain_set", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_terrain_set", p_from_index, p_to_pos);
}
} else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
int terrain_set = components[0].trim_prefix("terrain_set_").to_int();
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_terrain", terrain_set, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_terrain", terrain_set, p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_terrain", terrain_set, p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_terrain", terrain_set, p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_terrain", terrain_set, p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_terrain", terrain_set, p_from_index, p_to_pos);
}
} else if (p_array_prefix == "navigation_layer_") {
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_navigation_layer", p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_navigation_layer", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_navigation_layer", p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_navigation_layer", p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_navigation_layer", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_navigation_layer", p_from_index, p_to_pos);
}
} else if (p_array_prefix == "custom_data_layer_") {
if (p_from_index < 0) {
- undo_redo->add_do_method(tile_set, "add_custom_data_layer", p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "add_custom_data_layer", p_to_pos);
} else if (p_to_pos < 0) {
- undo_redo->add_do_method(tile_set, "remove_custom_data_layer", p_from_index);
+ undo_redo_man->add_do_method(ed_tile_set, "remove_custom_data_layer", p_from_index);
} else {
- undo_redo->add_do_method(tile_set, "move_custom_data_layer", p_from_index, p_to_pos);
+ undo_redo_man->add_do_method(ed_tile_set, "move_custom_data_layer", p_from_index, p_to_pos);
}
}
}
void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo.is_null());
+ Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo_man.is_null());
-#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
- TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
- if (tile_set) {
+#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
+ TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited);
+ if (ed_tile_set) {
Vector<String> components = p_property.split("/", true, 3);
- for (int i = 0; i < tile_set->get_source_count(); i++) {
- int source_id = tile_set->get_source_id(i);
+ for (int i = 0; i < ed_tile_set->get_source_count(); i++) {
+ int source_id = ed_tile_set->get_source_id(i);
- Ref<TileSetAtlasSource> tas = tile_set->get_source(source_id);
+ Ref<TileSetAtlasSource> tas = ed_tile_set->get_source(source_id);
if (tas.is_valid()) {
for (int j = 0; j < tas->get_tiles_count(); j++) {
Vector2i tile_id = tas->get_tile_id(j);
@@ -808,9 +808,3 @@ TileSetEditor::TileSetEditor() {
EditorNode::get_singleton()->get_editor_data().add_move_array_element_function(SNAME("TileSet"), callable_mp(this, &TileSetEditor::_move_tile_set_array_element));
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetEditor::_undo_redo_inspector_callback));
}
-
-TileSetEditor::~TileSetEditor() {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed));
- }
-}
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 290c53b109..76a471db74 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -109,7 +109,6 @@ public:
void edit(Ref<TileSet> p_tile_set);
TileSetEditor();
- ~TileSetEditor();
};
#endif // TILE_SET_EDITOR_H
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index f7622e68ab..ef69326686 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -323,7 +323,7 @@ void TileSetScenesCollectionSourceEditor::_update_scenes_list() {
}
// Icon size update.
- int int_size = int(EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
+ int int_size = int(EDITOR_GET("filesystem/file_dialog/thumbnail_size")) * EDSCALE;
scene_tiles_list->set_fixed_icon_size(Vector2(int_size, int_size));
}
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 17115519e2..5b54062632 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -66,12 +66,14 @@ void TilesEditorPlugin::_thread() {
pattern_preview_sem.wait();
pattern_preview_mutex.lock();
- if (pattern_preview_queue.size()) {
+ if (pattern_preview_queue.size() == 0) {
+ pattern_preview_mutex.unlock();
+ } else {
QueueItem item = pattern_preview_queue.front()->get();
pattern_preview_queue.pop_front();
pattern_preview_mutex.unlock();
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
Vector2 thumbnail_size2 = Vector2(thumbnail_size, thumbnail_size);
@@ -129,9 +131,7 @@ void TilesEditorPlugin::_thread() {
Callable::CallError error;
item.callback.callp(args_ptr, 2, r, error);
- viewport->queue_delete();
- } else {
- pattern_preview_mutex.unlock();
+ viewport->queue_free();
}
}
}
@@ -264,12 +264,12 @@ void TilesEditorPlugin::set_sorting_option(int p_option) {
source_sort = p_option;
}
-List<int> TilesEditorPlugin::get_sorted_sources(const Ref<TileSet> tile_set) const {
- SourceNameComparator::tile_set = tile_set;
+List<int> TilesEditorPlugin::get_sorted_sources(const Ref<TileSet> p_tile_set) const {
+ SourceNameComparator::tile_set = p_tile_set;
List<int> source_ids;
- for (int i = 0; i < tile_set->get_source_count(); i++) {
- source_ids.push_back(tile_set->get_source_id(i));
+ for (int i = 0; i < p_tile_set->get_source_count(); i++) {
+ source_ids.push_back(p_tile_set->get_source_id(i));
}
switch (source_sort) {
diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h
index b1fe6f8df6..bdada9ec90 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.h
+++ b/editor/plugins/tiles/tiles_editor_plugin.h
@@ -122,7 +122,7 @@ public:
// Sorting.
void set_sorting_option(int p_option);
- List<int> get_sorted_sources(const Ref<TileSet> tile_set) const;
+ List<int> get_sorted_sources(const Ref<TileSet> p_tile_set) const;
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 40993ea168..9b6ff894b9 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -86,11 +86,9 @@ void VisualShaderNodePlugin::set_editor(VisualShaderEditor *p_editor) {
}
Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
- Object *ret;
- if (GDVIRTUAL_CALL(_create_editor, p_parent_resource, p_node, ret)) {
- return Object::cast_to<Control>(ret);
- }
- return nullptr;
+ Object *ret = nullptr;
+ GDVIRTUAL_CALL(_create_editor, p_parent_resource, p_node, ret);
+ return Object::cast_to<Control>(ret);
}
void VisualShaderNodePlugin::_bind_methods() {
@@ -1235,11 +1233,11 @@ void VisualShaderEditor::_update_nodes() {
Ref<Resource> res = ResourceLoader::load(script_path);
ERR_FAIL_COND(res.is_null());
ERR_FAIL_COND(!res->is_class("Script"));
- Ref<Script> script = Ref<Script>(res);
+ Ref<Script> scr = Ref<Script>(res);
Ref<VisualShaderNodeCustom> ref;
ref.instantiate();
- ref->set_script(script);
+ ref->set_script(scr);
if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) {
continue;
}
@@ -1278,7 +1276,7 @@ void VisualShaderEditor::_update_nodes() {
Dictionary dict;
dict["name"] = name;
- dict["script"] = script;
+ dict["script"] = scr;
dict["description"] = description;
dict["return_icon_type"] = return_icon_type;
@@ -1358,7 +1356,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/renderer/rendering_method") == "gl_compatibility";
+ static bool low_driver = GLOBAL_GET("rendering/renderer/rendering_method") == "gl_compatibility";
HashMap<String, TreeItem *> folders;
@@ -1705,9 +1703,9 @@ void VisualShaderEditor::_update_graph() {
}
}
- List<VisualShader::Connection> connections;
- visual_shader->get_node_connections(type, &connections);
- graph_plugin->set_connections(connections);
+ List<VisualShader::Connection> node_connections;
+ visual_shader->get_node_connections(type, &node_connections);
+ graph_plugin->set_connections(node_connections);
Vector<int> nodes = visual_shader->get_node_list(type);
@@ -1724,7 +1722,7 @@ void VisualShaderEditor::_update_graph() {
graph_plugin->make_dirty(false);
- for (const VisualShader::Connection &E : connections) {
+ for (const VisualShader::Connection &E : node_connections) {
int from = E.from_node;
int from_idx = E.from_port;
int to = E.to_node;
@@ -1733,9 +1731,9 @@ void VisualShaderEditor::_update_graph() {
graph->connect_node(itos(from), from_idx, itos(to), to_idx);
}
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
graph->set_connection_lines_curvature(graph_lines_curvature);
}
@@ -1899,45 +1897,45 @@ void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expa
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
- int from_node = E.from_node;
- int from_port = E.from_port;
- int to_node = E.to_node;
- int to_port = E.to_port;
+ int cn_from_node = E.from_node;
+ int cn_from_port = E.from_port;
+ int cn_to_node = E.to_node;
+ int cn_to_port = E.to_port;
- if (from_node == p_node) {
+ if (cn_from_node == p_node) {
if (p_expand) {
- if (from_port > p_port) { // reconnect ports after expanded ports
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+ if (cn_from_port > p_port) { // reconnect ports after expanded ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port + type_size, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port);
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port + type_size, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port + type_size, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port + type_size, cn_to_node, cn_to_port);
}
} else {
- if (from_port > p_port + type_size) { // reconnect ports after expanded ports
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+ if (cn_from_port > p_port + type_size) { // reconnect ports after expanded ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port);
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - type_size, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - type_size, to_node, to_port);
- } else if (from_port > p_port) { // disconnect component ports
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - type_size, cn_to_node, cn_to_port);
+ } else if (cn_from_port > p_port) { // disconnect component ports
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
}
}
}
@@ -1973,30 +1971,30 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
- int from_node = E.from_node;
- int from_port = E.from_port;
- int to_node = E.to_node;
- int to_port = E.to_port;
-
- if (to_node == p_node) {
- if (to_port == p_port) {
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
- } else if (to_port > p_port) {
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port - 1);
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port - 1);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port - 1);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port - 1);
+ int cn_from_node = E.from_node;
+ int cn_from_port = E.from_port;
+ int cn_to_node = E.to_node;
+ int cn_to_port = E.to_port;
+
+ if (cn_to_node == p_node) {
+ if (cn_to_port == p_port) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ } else if (cn_to_port > p_port) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port - 1);
}
}
}
@@ -2022,30 +2020,30 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
- int from_node = E.from_node;
- int from_port = E.from_port;
- int to_node = E.to_node;
- int to_port = E.to_port;
-
- if (from_node == p_node) {
- if (from_port == p_port) {
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
- } else if (from_port > p_port) {
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
-
- undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, from_node, from_port - 1, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port - 1, to_node, to_port);
-
- undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port - 1, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port - 1, to_node, to_port);
+ int cn_from_node = E.from_node;
+ int cn_from_port = E.from_port;
+ int cn_to_node = E.to_node;
+ int cn_to_port = E.to_port;
+
+ if (cn_from_node == p_node) {
+ if (cn_from_port == p_port) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ } else if (cn_from_port > p_port) {
+ undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes_forced", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
+
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port - 1, cn_to_node, cn_to_port);
}
}
}
@@ -2932,16 +2930,16 @@ void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::Varyin
void VisualShaderEditor::_remove_varying(const String &p_name) {
undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));
- VisualShader::VaryingMode mode = visual_shader->get_varying_mode(p_name);
+ VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);
undo_redo->add_do_method(visual_shader.ptr(), "remove_varying", p_name);
- undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, mode, visual_shader->get_varying_type(p_name));
+ undo_redo->add_undo_method(visual_shader.ptr(), "add_varying", p_name, var_mode, visual_shader->get_varying_type(p_name));
undo_redo->add_do_method(this, "_update_varyings");
undo_redo->add_undo_method(this, "_update_varyings");
for (int i = 0; i <= VisualShader::TYPE_LIGHT; i++) {
- if (mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
+ if (var_mode == VisualShader::VARYING_MODE_FRAG_TO_LIGHT && i == 0) {
continue;
}
@@ -2967,10 +2965,10 @@ void VisualShaderEditor::_remove_varying(const String &p_name) {
}
}
- List<VisualShader::Connection> connections;
- visual_shader->get_node_connections(type, &connections);
+ List<VisualShader::Connection> node_connections;
+ visual_shader->get_node_connections(type, &node_connections);
- for (VisualShader::Connection &E : connections) {
+ for (VisualShader::Connection &E : node_connections) {
Ref<VisualShaderNodeVaryingGetter> var_getter = Object::cast_to<VisualShaderNodeVaryingGetter>(visual_shader->get_node(type, E.from_node).ptr());
if (var_getter.is_valid() && E.from_port > 0) {
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
@@ -3679,10 +3677,10 @@ void VisualShaderEditor::_sbox_input(const Ref<InputEvent> &p_ie) {
void VisualShaderEditor::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
- graph->set_minimap_opacity(EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"));
- graph->set_connection_lines_curvature(EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"));
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
+ graph->set_minimap_opacity(EDITOR_GET("editors/visual_editors/minimap_opacity"));
+ graph->set_connection_lines_curvature(EDITOR_GET("editors/visual_editors/lines_curvature"));
_update_graph();
} break;
@@ -3702,12 +3700,12 @@ void VisualShaderEditor::_notification(int p_what) {
category = category->get_next();
}
- graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
+ graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
+ graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
- highend_label->set_modulate(get_theme_color(SNAME("vulkan_color"), SNAME("Editor")));
+ highend_label->set_modulate(get_theme_color(SNAME("highend_color"), SNAME("Editor")));
node_filter->set_right_icon(Control::get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
@@ -3847,10 +3845,10 @@ void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, Li
}
}
- List<VisualShader::Connection> connections;
- visual_shader->get_node_connections(type, &connections);
+ List<VisualShader::Connection> node_connections;
+ visual_shader->get_node_connections(type, &node_connections);
- for (const VisualShader::Connection &E : connections) {
+ for (const VisualShader::Connection &E : node_connections) {
if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
r_connections.push_back(E);
}
@@ -3961,15 +3959,15 @@ void VisualShaderEditor::_duplicate_nodes() {
int type = get_current_shader_type();
List<CopyItem> items;
- List<VisualShader::Connection> connections;
+ List<VisualShader::Connection> node_connections;
- _dup_copy_nodes(type, items, connections);
+ _dup_copy_nodes(type, items, node_connections);
if (items.is_empty()) {
return;
}
- _dup_paste_nodes(type, items, connections, Vector2(10, 10) * EDSCALE, true);
+ _dup_paste_nodes(type, items, node_connections, Vector2(10, 10) * EDSCALE, true);
}
void VisualShaderEditor::_copy_nodes(bool p_cut) {
@@ -4064,11 +4062,11 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
bool type_changed = next_input_type != prev_input_type;
- Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("Visual Shader Input Type Changed"));
+ Ref<EditorUndoRedoManager> undo_redo_man = EditorNode::get_undo_redo();
+ undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));
- undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name);
- undo_redo->add_undo_method(p_input.ptr(), "set_input_name", prev_name);
+ undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);
+ undo_redo_man->add_undo_method(p_input.ptr(), "set_input_name", prev_name);
if (type_changed) {
for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
@@ -4098,30 +4096,30 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (const VisualShader::Connection &E : conns) {
- int from_node = E.from_node;
- int from_port = E.from_port;
- int to_node = E.to_node;
- int to_port = E.to_port;
-
- if (from_node == id) {
- bool is_incompatible_types = !visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, to_node)->get_input_port_type(to_port));
-
- if (is_incompatible_types || from_port > type_size) {
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, from_node, from_port, to_node, to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, from_node, from_port, to_node, to_port);
+ int cn_from_node = E.from_node;
+ int cn_from_port = E.from_port;
+ int cn_to_node = E.to_node;
+ int cn_to_port = E.to_port;
+
+ if (cn_from_node == id) {
+ bool is_incompatible_types = !visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, cn_to_node)->get_input_port_type(cn_to_port));
+
+ if (is_incompatible_types || cn_from_port > type_size) {
+ undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, cn_from_node, cn_from_port, cn_to_node, cn_to_port);
}
}
}
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
}
}
}
- undo_redo->commit_action();
+ undo_redo_man->commit_action();
}
void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParameterRef> p_parameter_ref, String p_name) {
@@ -4133,11 +4131,11 @@ void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParamete
bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);
- Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("ParameterRef Name Changed"));
+ Ref<EditorUndoRedoManager> undo_redo_man = EditorNode::get_undo_redo();
+ undo_redo_man->create_action(TTR("ParameterRef Name Changed"));
- undo_redo->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
- undo_redo->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);
+ undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
+ undo_redo_man->add_undo_method(p_parameter_ref.ptr(), "set_parameter_name", prev_name);
// update output port
for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
@@ -4152,20 +4150,20 @@ void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParamete
if (visual_shader->is_port_types_compatible(p_parameter_ref->get_parameter_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
continue;
}
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
}
}
}
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
break;
}
}
- undo_redo->commit_action();
+ undo_redo_man->commit_action();
}
void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_varying, String p_name) {
@@ -4177,11 +4175,11 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
- Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
- undo_redo->create_action(TTR("Varying Name Changed"));
+ Ref<EditorUndoRedoManager> undo_redo_man = EditorNode::get_undo_redo();
+ undo_redo_man->create_action(TTR("Varying Name Changed"));
- undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
- undo_redo->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);
+ undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
+ undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_name", prev_name);
VisualShader::VaryingType vtype = p_varying->get_varying_type_by_name(p_name);
VisualShader::VaryingType prev_vtype = p_varying->get_varying_type_by_name(prev_name);
@@ -4189,8 +4187,8 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool type_changed = vtype != prev_vtype;
if (type_changed) {
- undo_redo->add_do_method(p_varying.ptr(), "set_varying_type", vtype);
- undo_redo->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);
+ undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_type", vtype);
+ undo_redo_man->add_undo_method(p_varying.ptr(), "set_varying_type", prev_vtype);
}
// update ports
@@ -4209,32 +4207,32 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.to_node)->get_input_port_type(E.to_port))) {
continue;
}
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
}
} else {
if (E.to_node == id) {
if (visual_shader->is_port_types_compatible(p_varying->get_varying_type_by_name(p_name), visual_shader->get_node(type, E.from_node)->get_output_port_type(E.from_port))) {
continue;
}
- undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
}
}
}
}
- undo_redo->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
- undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_do_method(graph_plugin.ptr(), "update_node", type_id, id);
+ undo_redo_man->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
break;
}
}
- undo_redo->commit_action();
+ undo_redo_man->commit_action();
}
void VisualShaderEditor::_float_constant_selected(int p_which) {
@@ -4515,8 +4513,8 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
for (int i = 0; i < arr.size(); i++) {
String type = ResourceLoader::get_resource_type(arr[i]);
if (type == "GDScript") {
- Ref<Script> script = ResourceLoader::load(arr[i]);
- if (script->get_instance_base_type() == "VisualShaderNodeCustom") {
+ Ref<Script> scr = ResourceLoader::load(arr[i]);
+ if (scr->get_instance_base_type() == "VisualShaderNodeCustom") {
saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE);
saved_node_pos_dirty = true;
@@ -4686,9 +4684,9 @@ VisualShaderEditor::VisualShaderEditor() {
graph->set_show_zoom_label(true);
add_child(graph);
graph->set_drag_forwarding(this);
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
+ float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
+ float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
graph->set_connection_lines_curvature(graph_lines_curvature);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR_INT);
@@ -5087,23 +5085,23 @@ VisualShaderEditor::VisualShaderEditor() {
const String &compare_func_desc = TTR("Returns the boolean result of the %s comparison between two parameters.");
- add_options.push_back(AddOption("Equal", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("GreaterThan", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("GreaterThanEqual", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than or Equal (>=)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("Equal (==)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Equal (==)")), { VisualShaderNodeCompare::FUNC_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("GreaterThan (>)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than (>)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("GreaterThanEqual (>=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Greater Than or Equal (>=)")), { VisualShaderNodeCompare::FUNC_GREATER_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("If", "Conditional/Functions", "VisualShaderNodeIf", TTR("Returns an associated vector if the provided scalars are equal, greater or less."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("IsInf", "Conditional/Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_INF }, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("IsNaN", "Conditional/Functions", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between NaN and a scalar parameter."), { VisualShaderNodeIs::FUNC_IS_NAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("LessThan", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("LessThanEqual", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), { VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("NotEqual", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("Switch", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Switch2D", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("SwitchBool", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_BOOLEAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
- add_options.push_back(AddOption("SwitchFloat", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("SwitchInt", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("SwitchTransform", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_TRANSFORM }, VisualShaderNode::PORT_TYPE_TRANSFORM));
-
- add_options.push_back(AddOption("Compare", "Conditional/Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("LessThan (<)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than (<)")), { VisualShaderNodeCompare::FUNC_LESS_THAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("LessThanEqual (<=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Less Than or Equal (<=)")), { VisualShaderNodeCompare::FUNC_LESS_THAN_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("NotEqual (!=)", "Conditional/Functions", "VisualShaderNodeCompare", vformat(compare_func_desc, TTR("Not Equal (!=)")), { VisualShaderNodeCompare::FUNC_NOT_EQUAL }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("Switch (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 3D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Switch2D (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated 2D vector if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("SwitchBool (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated boolean if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_BOOLEAN }, VisualShaderNode::PORT_TYPE_BOOLEAN));
+ add_options.push_back(AddOption("SwitchFloat (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated floating-point scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_FLOAT }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("SwitchInt (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated integer scalar if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_INT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("SwitchTransform (==)", "Conditional/Functions", "VisualShaderNodeSwitch", TTR("Returns an associated transform if the provided boolean value is true or false."), { VisualShaderNodeSwitch::OP_TYPE_TRANSFORM }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+
+ add_options.push_back(AddOption("Compare (==)", "Conditional/Common", "VisualShaderNodeCompare", TTR("Returns the boolean result of the comparison between two parameters."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("Is", "Conditional/Common", "VisualShaderNodeIs", TTR("Returns the boolean result of the comparison between INF (or NaN) and a scalar parameter."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
add_options.push_back(AddOption("BooleanConstant", "Conditional/Variables", "VisualShaderNodeBooleanConstant", TTR("Boolean constant."), {}, VisualShaderNode::PORT_TYPE_BOOLEAN));
@@ -5308,7 +5306,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("EmitParticle", "Particles", "VisualShaderNodeParticleEmit", "", {}, -1, TYPE_FLAGS_PROCESS | TYPE_FLAGS_PROCESS_CUSTOM | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("ParticleAccelerator", "Particles", "VisualShaderNodeParticleAccelerator", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("ParticleRandomness", "Particles", "VisualShaderNodeParticleRandomness", "", {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles/Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", TTR("A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("MultiplyByAxisAngle (*)", "Particles/Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", TTR("A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("BoxEmitter", "Particles/Emitters", "VisualShaderNodeParticleBoxEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("MeshEmitter", "Particles/Emitters", "VisualShaderNodeParticleMeshEmitter", "", {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
@@ -5359,10 +5357,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Max", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the greater of two values."), { VisualShaderNodeFloatOp::OP_MAX }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Min", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the lesser of two values."), { VisualShaderNodeFloatOp::OP_MIN }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Mix", "Scalar/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two scalars."), { VisualShaderNodeMix::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("MultiplyAdd", "Scalar/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), { VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Negate", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Negate", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeIntFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("OneMinus", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Scalar/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on scalars."), { VisualShaderNodeMultiplyAdd::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Negate (*-1)", "Scalar/Functions", "VisualShaderNodeIntFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeIntFunc::FUNC_NEGATE }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("OneMinus (1-)", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 - scalar"), { VisualShaderNodeFloatFunc::FUNC_ONEMINUS }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Pow", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeFloatOp::OP_POW }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Radians", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Reciprocal", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR));
@@ -5381,21 +5379,21 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("TanH", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Returns the hyperbolic tangent of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TANH }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Trunc", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeFloatFunc::FUNC_TRUNC }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Add", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Add", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("BitwiseAND", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise AND (a & b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_AND }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("BitwiseLeftShift", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise left shift (a << b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_LEFT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("BitwiseOR", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise OR (a | b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_OR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("BitwiseRightShift", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise right shift (a >> b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_RIGHT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("BitwiseXOR", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise XOR (a ^ b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_XOR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Divide", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Divide", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Multiply", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Multiply", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Sums two floating-point scalars."), { VisualShaderNodeFloatOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Add (+)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Sums two integer scalars."), { VisualShaderNodeIntOp::OP_ADD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseAND (&)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise AND (a & b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_AND }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseLeftShift (<<)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise left shift (a << b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_LEFT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseOR (|)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise OR (a | b) operation for two integers."), { VisualShaderNodeIntOp::OP_BITWISE_OR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseRightShift (>>)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise right shift (a >> b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_RIGHT_SHIFT }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("BitwiseXOR (^)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the result of bitwise XOR (a ^ b) operation on the integer."), { VisualShaderNodeIntOp::OP_BITWISE_XOR }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Divides two floating-point scalars."), { VisualShaderNodeFloatOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Divide (/)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Divides two integer scalars."), { VisualShaderNodeIntOp::OP_DIV }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Multiplies two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Multiply (*)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Multiplies two integer scalars."), { VisualShaderNodeIntOp::OP_MUL }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
add_options.push_back(AddOption("Remainder", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Returns the remainder of the two floating-point scalars."), { VisualShaderNodeFloatOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("Remainder", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Returns the remainder of the two integer scalars."), { VisualShaderNodeIntOp::OP_MOD }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
- add_options.push_back(AddOption("Subtract", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));
- add_options.push_back(AddOption("Subtract", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
+ add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeFloatOp", TTR("Subtracts two floating-point scalars."), { VisualShaderNodeFloatOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Subtract (-)", "Scalar/Operators", "VisualShaderNodeIntOp", TTR("Subtracts two integer scalars."), { VisualShaderNodeIntOp::OP_SUB }, VisualShaderNode::PORT_TYPE_SCALAR_INT));
add_options.push_back(AddOption("FloatConstant", "Scalar/Variables", "VisualShaderNodeFloatConstant", TTR("Scalar floating-point constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("IntConstant", "Scalar/Variables", "VisualShaderNodeIntConstant", TTR("Scalar integer constant."), {}, VisualShaderNode::PORT_TYPE_SCALAR_INT));
@@ -5452,12 +5450,12 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Inverse", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), { VisualShaderNodeTransformFunc::FUNC_INVERSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("Transpose", "Transform/Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), { VisualShaderNodeTransformFunc::FUNC_TRANSPOSE }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Add", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Divide", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Multiply", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("MultiplyComp", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("Subtract", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
- add_options.push_back(AddOption("TransformVectorMult", "Transform/Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Add (+)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Sums two transforms."), { VisualShaderNodeTransformOp::OP_ADD }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Divide (/)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Divides two transforms."), { VisualShaderNodeTransformOp::OP_A_DIV_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Multiply (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Multiplies two transforms."), { VisualShaderNodeTransformOp::OP_AxB }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("MultiplyComp (*)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Performs per-component multiplication of two transforms."), { VisualShaderNodeTransformOp::OP_AxB_COMP }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("Subtract (-)", "Transform/Operators", "VisualShaderNodeTransformOp", TTR("Subtracts two transforms."), { VisualShaderNodeTransformOp::OP_A_MINUS_B }, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ add_options.push_back(AddOption("TransformVectorMult (*)", "Transform/Operators", "VisualShaderNodeTransformVecMult", TTR("Multiplies vector by transform."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("TransformConstant", "Transform/Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("TransformParameter", "Transform/Variables", "VisualShaderNodeTransformParameter", TTR("Transform parameter."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
@@ -5573,21 +5571,21 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("MixS", "Vector/Functions", "VisualShaderNodeMix", TTR("Linear interpolation between two vectors using scalar."), { VisualShaderNodeMix::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("MultiplyAdd", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("MultiplyAdd", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("MultiplyAdd", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Negate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Negate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Negate", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("MultiplyAdd (a * b + c)", "Vector/Functions", "VisualShaderNodeMultiplyAdd", TTR("Performs a fused multiply-add operation (a * b + c) on vectors."), { VisualShaderNodeMultiplyAdd::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Negate (*-1)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the opposite value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_NEGATE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Normalize", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Calculates the normalize product of vector."), { VisualShaderNodeVectorFunc::FUNC_NORMALIZE, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("OneMinus", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("OneMinus", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("OneMinus", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Pow", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Pow", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Pow", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("OneMinus (1-)", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("1.0 - vector"), { VisualShaderNodeVectorFunc::FUNC_ONEMINUS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Pow (^)", "Vector/Functions", "VisualShaderNodeVectorOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeVectorOp::OP_POW, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Radians", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeVectorFunc::FUNC_RADIANS, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
@@ -5632,9 +5630,9 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("StepS", "Vector/Functions", "VisualShaderNodeStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), { VisualShaderNodeStep::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Sum", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
- add_options.push_back(AddOption("Sum", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
- add_options.push_back(AddOption("Sum", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
+ add_options.push_back(AddOption("Sum (+)", "Vector/Functions", "VisualShaderNodeDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), { VisualShaderNodeDerivativeFunc::FUNC_SUM, VisualShaderNodeDerivativeFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, true));
add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Tan", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
@@ -5645,21 +5643,21 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Trunc", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Trunc", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), { VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Add", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 2D vector to 2D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Add", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 3D vector to 3D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Add", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 4D vector to 4D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Divide", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Divide", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Divide", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Multiply", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Multiply", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Multiply", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 2D vector to 2D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 3D vector to 3D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Add (+)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Adds 4D vector to 4D vector."), { VisualShaderNodeVectorOp::OP_ADD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Divide (/)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Divides 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_DIV, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 2D vector by 2D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 3D vector by 3D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Multiply (*)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Multiplies 4D vector by 4D vector."), { VisualShaderNodeVectorOp::OP_MUL, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Remainder", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 2D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Remainder", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 3D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Remainder", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Returns the remainder of the two 4D vectors."), { VisualShaderNodeVectorOp::OP_MOD, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
- add_options.push_back(AddOption("Subtract", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 2D vector from 2D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
- add_options.push_back(AddOption("Subtract", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 3D vector from 3D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("Subtract", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 4D vector from 4D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 2D vector from 2D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 3D vector from 3D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Subtract (-)", "Vector/Operators", "VisualShaderNodeVectorOp", TTR("Subtracts 4D vector from 4D vector."), { VisualShaderNodeVectorOp::OP_SUB, VisualShaderNodeVectorOp::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Vector2Constant", "Vector/Variables", "VisualShaderNodeVec2Constant", TTR("2D vector constant."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Vector2Parameter", "Vector/Variables", "VisualShaderNodeVec2Parameter", TTR("2D vector parameter."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
@@ -6229,9 +6227,9 @@ void VisualShaderNodePortPreview::_shader_changed() {
}
}
- Ref<ShaderMaterial> material;
- material.instantiate();
- material->set_shader(preview_shader);
+ Ref<ShaderMaterial> mat;
+ mat.instantiate();
+ mat->set_shader(preview_shader);
//find if a material is also being edited and copy parameters to this one
@@ -6252,12 +6250,12 @@ void VisualShaderNodePortPreview::_shader_changed() {
List<PropertyInfo> params;
src_mat->get_shader()->get_shader_uniform_list(&params);
for (const PropertyInfo &E : params) {
- material->set(E.name, src_mat->get(E.name));
+ mat->set(E.name, src_mat->get(E.name));
}
}
}
- set_material(material);
+ set_material(mat);
}
void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, VisualShader::Type p_type, int p_node, int p_port) {
@@ -6271,7 +6269,7 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua
}
Size2 VisualShaderNodePortPreview::get_minimum_size() const {
- int port_preview_size = EditorSettings::get_singleton()->get("editors/visual_editors/visual_shader/port_preview_size");
+ int port_preview_size = EDITOR_GET("editors/visual_editors/visual_shader/port_preview_size");
return Size2(port_preview_size, port_preview_size) * EDSCALE;
}
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index a00df0ef40..d6b69e10db 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -63,7 +63,7 @@ void POTGenerator::generate_pot(const String &p_file) {
// Clear all_translation_strings of the previous round.
all_translation_strings.clear();
- Vector<String> files = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
+ Vector<String> files = GLOBAL_GET("internationalization/locale/translations_pot_files");
// Collect all translatable strings according to files order in "POT Generation" setting.
for (int i = 0; i < files.size(); i++) {
@@ -99,8 +99,8 @@ void POTGenerator::_write_to_pot(const String &p_file) {
return;
}
- String project_name = ProjectSettings::get_singleton()->get("application/config/name");
- Vector<String> files = ProjectSettings::get_singleton()->get("internationalization/locale/translations_pot_files");
+ String project_name = GLOBAL_GET("application/config/name");
+ Vector<String> files = GLOBAL_GET("internationalization/locale/translations_pot_files");
String extracted_files = "";
for (int i = 0; i < files.size(); i++) {
extracted_files += "# " + files[i] + "\n";
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 0c0151d1a5..78f3b4de0e 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -230,6 +230,7 @@ static const char *gdscript_function_renames[][2] = {
{ "add_force", "apply_force" }, //RigidBody2D
{ "add_icon_override", "add_theme_icon_override" }, // Control
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
+ { "add_spatial_gizmo_plugin", "add_node_3d_gizmo_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
@@ -301,6 +302,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_cull_mask_bit", "get_cull_mask_value" }, // Camera3D
{ "get_cursor_position", "get_caret_column" }, // LineEdit
{ "get_d", "get_distance" }, // LineShape2D
+ { "get_depth_bias_enable", "get_depth_bias_enabled" }, // RDPipelineRasterizationState
{ "get_drag_data", "_get_drag_data" }, // Control
{ "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor
{ "get_editor_viewport", "get_editor_main_screen" }, // EditorPlugin
@@ -309,6 +311,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_error_string", "get_error_message" }, // JSON
{ "get_filename", "get_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places
{ "get_focus_neighbour", "get_focus_neighbor" }, // Control
+ { "get_follow_smoothing", "get_position_smoothing_speed" }, // Camera2D
{ "get_font_types", "get_font_type_list" }, // Theme
{ "get_frame_color", "get_color" }, // ColorRect
{ "get_global_rate_scale", "get_playback_speed_scale" }, // AudioServer
@@ -357,6 +360,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_render_targetsize", "get_render_target_size" }, // XRInterface
{ "get_resource_type", "_get_resource_type" }, // ResourceFormatLoader
{ "get_result", "get_data" }, //JSON
+ { "get_reverb_bus", "set_reverb_bus_name" }, // Area3D
{ "get_rpc_sender_id", "get_remote_sender_id" }, // Multiplayer API
{ "get_save_extension", "_get_save_extension" }, // EditorImportPlugin
{ "get_scancode", "get_keycode" }, // InputEventKey
@@ -367,6 +371,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_slide_count", "get_slide_collision_count" }, // CharacterBody2D, CharacterBody3D
{ "get_slips_on_slope", "get_slide_on_slope" }, // SeparationRayShape2D, SeparationRayShape3D
{ "get_space_override_mode", "get_gravity_space_override_mode" }, // Area2D
+ { "get_spatial_node", "get_node_3d" }, // EditorNode3DGizmo
{ "get_speed", "get_velocity" }, // InputEventMouseMotion
{ "get_stylebox_types", "get_stylebox_type_list" }, // Theme
{ "get_surface_material", "get_surface_override_material" }, // MeshInstance3D broke ImporterMesh
@@ -377,6 +382,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_theme_item_types", "get_theme_item_type_list" }, // Theme
{ "get_timer_process_mode", "get_timer_process_callback" }, // Timer
{ "get_translation", "get_position" }, // Node3D broke GLTFNode which is used rarely
+ { "get_unit_db", "get_volume_db" }, // AudioStreamPlayer3D
{ "get_unit_offset", "get_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "get_use_in_baked_light", "is_baking_navigation" }, // GridMap
{ "get_used_cells_by_id", "get_used_cells" }, // TileMap
@@ -414,6 +420,7 @@ static const char *gdscript_function_renames[][2] = {
{ "is_commiting_action", "is_committing_action" }, // UndoRedo
{ "is_doubleclick", "is_double_click" }, // InputEventMouseButton
{ "is_draw_red", "is_draw_warning" }, // EditorProperty
+ { "is_follow_smoothing_enabled", "is_position_smoothing_enabled" }, // Camera2D
{ "is_h_drag_enabled", "is_drag_horizontal_enabled" }, // Camera2D
{ "is_handle_highlighted", "_is_handle_highlighted" }, // EditorNode3DGizmo, EditorNode3DGizmoPlugin
{ "is_inverting_faces", "get_flip_faces" }, // CSGPrimitive3D
@@ -466,6 +473,7 @@ static const char *gdscript_function_renames[][2] = {
{ "remove_font_override", "remove_theme_font_override" }, // Control
{ "remove_icon_override", "remove_theme_icon_override" }, // Control
{ "remove_scene_import_plugin", "remove_scene_format_importer_plugin" }, //EditorPlugin
+ { "remove_spatial_gizmo_plugin", "remove_node_3d_gizmo_plugin" }, // EditorPlugin
{ "remove_stylebox_override", "remove_theme_stylebox_override" }, // Control
{ "rename_animation", "rename_animation_library" }, // AnimationPlayer
{ "rename_dependencies", "_rename_dependencies" }, // ResourceFormatLoader
@@ -491,13 +499,16 @@ static const char *gdscript_function_renames[][2] = {
{ "set_cull_mask_bit", "set_cull_mask_value" }, // Camera3D
{ "set_cursor_position", "set_caret_column" }, // LineEdit
{ "set_d", "set_distance" }, // WorldMarginShape2D
+ { "set_depth_bias_enable", "set_depth_bias_enabled" }, // RDPipelineRasterizationState
{ "set_doubleclick", "set_double_click" }, // InputEventMouseButton
{ "set_draw_red", "set_draw_warning" }, // EditorProperty
+ { "set_enable_follow_smoothing", "set_position_smoothing_enabled" }, // Camera2D
{ "set_enabled_focus_mode", "set_focus_mode" }, // BaseButton
{ "set_endian_swap", "set_big_endian" }, // File
{ "set_expand_to_text_length", "set_expand_to_text_length_enabled" }, // LineEdit
{ "set_filename", "set_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places
{ "set_focus_neighbour", "set_focus_neighbor" }, // Control
+ { "set_follow_smoothing", "set_position_smoothing_speed" }, // Camera2D
{ "set_frame_color", "set_color" }, // ColorRect
{ "set_global_rate_scale", "set_playback_speed_scale" }, // AudioServer
{ "set_gravity_distance_scale", "set_gravity_point_distance_scale" }, // Area2D
@@ -521,9 +532,11 @@ static const char *gdscript_function_renames[][2] = {
{ "set_oneshot", "set_one_shot" }, // AnimatedTexture
{ "set_pause_mode", "set_process_mode" }, // Node
{ "set_physical_scancode", "set_physical_keycode" }, // InputEventKey
+ { "set_proximity_fade", "set_proximity_fade_enabled" }, // Material
{ "set_refuse_new_network_connections", "set_refuse_new_connections" }, // Multiplayer API
{ "set_region", "set_region_enabled" }, // Sprite2D, Sprite broke AtlasTexture
{ "set_region_filter_clip", "set_region_filter_clip_enabled" }, // Sprite2D
+ { "set_reverb_bus", "set_reverb_bus_name" }, // Area3D
{ "set_rotate", "set_rotates" }, // PathFollow2D
{ "set_scancode", "set_keycode" }, // InputEventKey
{ "set_shift", "set_shift_pressed" }, // InputEventWithModifiers
@@ -532,6 +545,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_slips_on_slope", "set_slide_on_slope" }, // SeparationRayShape2D, SeparationRayShape3D
{ "set_sort_enabled", "set_y_sort_enabled" }, // Node2D
{ "set_space_override_mode", "set_gravity_space_override_mode" }, // Area2D
+ { "set_spatial_node", "set_node_3d" }, // EditorNode3DGizmo
{ "set_speed", "set_velocity" }, // InputEventMouseMotion
{ "set_ssao_edge_sharpness", "set_ssao_sharpness" }, // Environment
{ "set_surface_material", "set_surface_override_material" }, // MeshInstance3D broke ImporterMesh
@@ -540,6 +554,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_text_align", "set_text_alignment" }, // Button
{ "set_timer_process_mode", "set_timer_process_callback" }, // Timer
{ "set_translation", "set_position" }, // Node3D - this broke GLTFNode which is used rarely
+ { "set_unit_db", "set_volume_db" }, // AudioStreamPlayer3D
{ "set_unit_offset", "set_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "set_uv2", "surface_set_uv2" }, // ImmediateMesh broke Surffacetool
{ "set_v_drag_enabled", "set_drag_vertical_enabled" }, // Camera2D
@@ -651,6 +666,7 @@ static const char *csharp_function_renames[][2] = {
// { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape
// {"GetVScroll","GetVScrollBar"},//ItemList, broke TextView
+ { "AddSpatialGizmoPlugin", "AddNode3dGizmoPlugin" }, // EditorPlugin
{ "RenderingServer", "GetTabAlignment" }, // Tab
{ "_AboutToShow", "_AboutToPopup" }, // ColorPickerButton
{ "_GetConfigurationWarning", "_GetConfigurationWarnings" }, // Node
@@ -734,12 +750,14 @@ static const char *csharp_function_renames[][2] = {
{ "GetCullMaskBit", "GetCullMaskValue" }, // Camera3D
{ "GetCursorPosition", "GetCaretColumn" }, // LineEdit
{ "GetD", "GetDistance" }, // LineShape2D
+ { "GetDepthBiasEnable", "GetDepthBiasEnabled" }, // RDPipelineRasterizationState
{ "GetDragDataFw", "_GetDragDataFw" }, // ScriptEditor
{ "GetEditorViewport", "GetViewport" }, // EditorPlugin
{ "GetEnabledFocusMode", "GetFocusMode" }, // BaseButton
{ "GetEndianSwap", "IsBigEndian" }, // File
{ "GetErrorString", "GetErrorMessage" }, // JSON
{ "GetFocusNeighbour", "GetFocusNeighbor" }, // Control
+ { "GetFollowSmoothing", "GetFollowSmoothingSpeed" }, // Camera2D
{ "GetFontTypes", "GetFontTypeList" }, // Theme
{ "GetFrameColor", "GetColor" }, // ColorRect
{ "GetGlobalRateScale", "GetPlaybackSpeedScale" }, // AudioServer
@@ -787,6 +805,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetRenderTargetsize", "GetRenderTargetSize" }, // XRInterface
{ "GetResourceType", "_GetResourceType" }, // ResourceFormatLoader
{ "GetResult", "GetData" }, //JSON
+ { "GetReverbBus", "GetReverbBusName" }, // Area3D
{ "GetRpcSenderId", "GetRemoteSenderId" }, // Multiplayer API
{ "GetSaveExtension", "_GetSaveExtension" }, // EditorImportPlugin
{ "GetScancode", "GetKeycode" }, // InputEventKey
@@ -796,6 +815,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetSizeOverride", "GetSize2dOverride" }, // SubViewport
{ "GetSlipsOnSlope", "GetSlideOnSlope" }, // SeparationRayShape2D, SeparationRayShape3D
{ "GetSpaceOverrideMode", "GetGravitySpaceOverrideMode" }, // Area2D
+ { "GetSpatialNode", "GetNode3d" }, // EditorNode3DGizmo
{ "GetSpeed", "GetVelocity" }, // InputEventMouseMotion
{ "GetStyleboxTypes", "GetStyleboxTypeList" }, // Theme
{ "GetSurfaceMaterial", "GetSurfaceOverrideMaterial" }, // MeshInstance3D broke ImporterMesh
@@ -806,6 +826,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetThemeItemTypes", "GetThemeItemTypeList" }, // Theme
{ "GetTimerProcessMode", "GetTimerProcessCallback" }, // Timer
{ "GetTranslation", "GetPosition" }, // Node3D broke GLTFNode which is used rarely
+ { "GetUnitDb", "GetVolumeDb" }, // AudioStreamPlayer3D
{ "GetUnitOffset", "GetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "GetUseInBakedLight", "IsBakingNavigation" }, // GridMap
{ "GetUsedCellsById", "GetUsedCells" }, // TileMap
@@ -842,6 +863,7 @@ static const char *csharp_function_renames[][2] = {
{ "IsAParentOf", "IsAncestorOf" }, // Node
{ "IsCommitingAction", "IsCommittingAction" }, // UndoRedo
{ "IsDoubleclick", "IsDoubleClick" }, // InputEventMouseButton
+ { "IsFollowSmoothingEnabled", "IsPositionSmoothingEnabled" }, // Camera2D
{ "IsHDragEnabled", "IsDragHorizontalEnabled" }, // Camera2D
{ "IsHandleHighlighted", "_IsHandleHighlighted" }, // EditorNode3DGizmo, EditorNode3DGizmoPlugin
{ "IsNetworkMaster", "IsMultiplayerAuthority" }, // Node
@@ -890,6 +912,7 @@ static const char *csharp_function_renames[][2] = {
{ "RemoveConstantOverride", "RemoveThemeConstantOverride" }, // Control
{ "RemoveFontOverride", "RemoveThemeFontOverride" }, // Control
{ "RemoveSceneImportPlugin", "RemoveSceneFormatImporterPlugin" }, //EditorPlugin
+ { "RemoveSpatialGizmoPlugin", "RemoveNode3dGizmoPlugin" }, // EditorPlugin
{ "RemoveStyleboxOverride", "RemoveThemeStyleboxOverride" }, // Control
{ "RenameAnimation", "RenameAnimationLibrary" }, // AnimationPlayer
{ "RenameDependencies", "_RenameDependencies" }, // ResourceFormatLoader
@@ -915,11 +938,14 @@ static const char *csharp_function_renames[][2] = {
{ "SetCullMaskBit", "SetCullMaskValue" }, // Camera3D
{ "SetCursorPosition", "SetCaretColumn" }, // LineEdit
{ "SetD", "SetDistance" }, // WorldMarginShape2D
+ { "SetDepthBiasEnable", "SetDepthBiasEnabled" }, // RDPipelineRasterizationState
{ "SetDoubleclick", "SetDoubleClick" }, // InputEventMouseButton
+ { "SetEnableFollowSmoothing", "SetFollowSmoothingEnabled" }, // Camera2D
{ "SetEnabledFocusMode", "SetFocusMode" }, // BaseButton
{ "SetEndianSwap", "SetBigEndian" }, // File
{ "SetExpandToTextLength", "SetExpandToTextLengthEnabled" }, // LineEdit
{ "SetFocusNeighbour", "SetFocusNeighbor" }, // Control
+ { "SetFollowSmoothing", "SetFollowSmoothingSpeed" }, // Camera2D
{ "SetFrameColor", "SetColor" }, // ColorRect
{ "SetGlobalRateScale", "SetPlaybackSpeedScale" }, // AudioServer
{ "SetGravityDistanceScale", "SetGravityPointDistanceScale" }, // Area2D
@@ -941,9 +967,11 @@ static const char *csharp_function_renames[][2] = {
{ "SetNetworkPeer", "SetMultiplayerPeer" }, // Multiplayer API
{ "SetOneshot", "SetOneShot" }, // AnimatedTexture
{ "SetPhysicalScancode", "SetPhysicalKeycode" }, // InputEventKey
+ { "SetProximityFade", "SetProximityFadeEnabled" }, // Material
{ "SetRefuseNewNetworkConnections", "SetRefuseNewConnections" }, // Multiplayer API
{ "SetRegion", "SetRegionEnabled" }, // Sprite2D, Sprite broke AtlasTexture
{ "SetRegionFilterClip", "SetRegionFilterClipEnabled" }, // Sprite2D
+ { "SetReverbBus", "SetReverbBusName" }, // Area3D
{ "SetRotate", "SetRotates" }, // PathFollow2D
{ "SetScancode", "SetKeycode" }, // InputEventKey
{ "SetShift", "SetShiftPressed" }, // InputEventWithModifiers
@@ -952,6 +980,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetSlipsOnSlope", "SetSlideOnSlope" }, // SeparationRayShape2D, SeparationRayShape3D
{ "SetSortEnabled", "SetYSortEnabled" }, // Node2D
{ "SetSpaceOverrideMode", "SetGravitySpaceOverrideMode" }, // Area2D
+ { "SetSpatialNode", "SetNode3d" }, // EditorNode3DGizmo
{ "SetSpeed", "SetVelocity" }, // InputEventMouseMotion
{ "SetSsaoEdgeSharpness", "SetSsaoSharpness" }, // Environment
{ "SetSurfaceMaterial", "SetSurfaceOverrideMaterial" }, // MeshInstance3D broke ImporterMesh
@@ -961,6 +990,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetTimerProcessMode", "SetTimerProcessCallback" }, // Timer
{ "SetTonemapAutoExposure", "SetTonemapAutoExposureEnabled" }, // Environment
{ "SetTranslation", "SetPosition" }, // Node3D - this broke GLTFNode which is used rarely
+ { "SetUnitDb", "SetVolumeDb" }, // AudioStreamPlayer3D
{ "SetUnitOffset", "SetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "SetUv2", "SurfaceSetUv2" }, // ImmediateMesh broke Surffacetool
{ "SetVDragEnabled", "SetDragVerticalEnabled" }, // Camera2D
@@ -1059,6 +1089,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "close_v_ofs", "close_v_offset" }, // Theme
{ "commentfocus", "comment_focus" }, // Theme
{ "contacts_reported", "max_contacts_reported" }, // RigidBody
+ { "depth_bias_enable", "depth_bias_enabled" }, // RDPipelineRasterizationState
{ "drag_margin_bottom", "drag_bottom_margin" }, // Camera2D
{ "drag_margin_h_enabled", "drag_horizontal_enabled" }, // Camera2D
{ "drag_margin_left", "drag_left_margin" }, // Camera2D
@@ -1101,6 +1132,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "pause_mode", "process_mode" }, // Node
{ "physical_scancode", "physical_keycode" }, // InputEventKey
{ "popup_exclusive", "exclusive" }, // Window
+ { "proximity_fade_enable", "proximity_fade_enabled" }, // Material
{ "rect_position", "position" }, // Control
{ "rect_global_position", "global_position" }, // Control
{ "rect_size", "size" }, // Control
@@ -1111,9 +1143,12 @@ static const char *gdscript_properties_renames[][2] = {
{ "rect_clip_content", "clip_contents" }, // Control
{ "refuse_new_network_connections", "refuse_new_connections" }, // MultiplayerAPI
{ "region_filter_clip", "region_filter_clip_enabled" }, // Sprite2D
+ { "reverb_bus_enable", "reverb_bus_enabled" }, // Area3D
{ "selectedframe", "selected_frame" }, // Theme
{ "size_override_stretch", "size_2d_override_stretch" }, // SubViewport
{ "slips_on_slope", "slide_on_slope" }, // SeparationRayShape2D
+ { "smoothing_enabled", "follow_smoothing_enabled" }, // Camera2D
+ { "smoothing_speed", "position_smoothing_speed" }, // Camera2D
{ "ss_reflections_depth_tolerance", "ssr_depth_tolerance" }, // Environment
{ "ss_reflections_enabled", "ssr_enabled" }, // Environment
{ "ss_reflections_fade_in", "ssr_fade_in" }, // Environment
@@ -1125,6 +1160,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "table_hseparation", "table_h_separation" }, // Theme
{ "table_vseparation", "table_v_separation" }, // Theme
{ "translation", "position" }, // Node3D - broke GLTFNode
+ { "unit_db", "volume_db" }, // AudioStreamPlayer3D
{ "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D
{ "vseparation", "v_separation" }, // Theme
@@ -1164,6 +1200,7 @@ static const char *csharp_properties_renames[][2] = {
{ "CloseHOfs", "CloseHOffset" }, // Theme
{ "CloseVOfs", "CloseVOffset" }, // Theme
{ "Commentfocus", "CommentFocus" }, // Theme
+ { "DepthBiasEnable", "DepthBiasEnabled" }, // RDPipelineRasterizationState
{ "DragMarginBottom", "DragBottomMargin" }, // Camera2D
{ "DragMarginHEnabled", "DragHorizontalEnabled" }, // Camera2D
{ "DragMarginLeft", "DragLeftMargin" }, // Camera2D
@@ -1199,11 +1236,15 @@ static const char *csharp_properties_renames[][2] = {
{ "PauseMode", "ProcessMode" }, // Node
{ "PhysicalScancode", "PhysicalKeycode" }, // InputEventKey
{ "PopupExclusive", "Exclusive" }, // Window
+ { "ProximityFadeEnable", "ProximityFadeEnabled" }, // Material
{ "RefuseNewNetworkConnections", "RefuseNewConnections" }, // MultiplayerAPI
{ "RegionFilterClip", "RegionFilterClipEnabled" }, // Sprite2D
+ { "ReverbBusEnable", "ReverbBusEnabled" }, // Area3D
{ "Selectedframe", "SelectedFrame" }, // Theme
{ "SizeOverrideStretch", "Size2dOverrideStretch" }, // SubViewport
{ "SlipsOnSlope", "SlideOnSlope" }, // SeparationRayShape2D
+ { "SmoothingEnabled", "FollowSmoothingEnabled" }, // Camera2D
+ { "SmoothingSpeed", "FollowSmoothingSpeed" }, // Camera2D
{ "SsReflectionsDepthTolerance", "SsrDepthTolerance" }, // Environment
{ "SsReflectionsEnabled", "SsrEnabled" }, // Environment
{ "SsReflectionsFadeIn", "SsrFadeIn" }, // Environment
@@ -1215,6 +1256,7 @@ static const char *csharp_properties_renames[][2] = {
{ "TableHseparation", "TableHSeparation" }, // Theme
{ "TableVseparation", "TableVSeparation" }, // Theme
{ "Translation", "Position" }, // Node3D - broke GLTFNode
+ { "UnitDb", "VolumeDb" }, // AudioStreamPlayer3D
{ "UnitOffset", "ProgressRatio" }, // PathFollow2D, PathFollow3D
{ "Vseparation", "VSeparation" }, // Theme
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 673da8872d..588746bf64 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -143,7 +143,11 @@ private:
install_status_rect->set_texture(new_icon);
}
- set_size(Size2(500, 0) * EDSCALE);
+ Size2i window_size = get_size();
+ Size2 contents_min_size = get_contents_minimum_size();
+ if (window_size.x < contents_min_size.x || window_size.y < contents_min_size.y) {
+ set_size(window_size.max(contents_min_size));
+ }
}
String _test_path() {
@@ -563,19 +567,19 @@ private:
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->make_dir(dir.path_join(rel_path));
} else {
- Vector<uint8_t> data;
- data.resize(info.uncompressed_size);
+ Vector<uint8_t> uncomp_data;
+ uncomp_data.resize(info.uncompressed_size);
String rel_path = path.substr(zip_root.length());
//read
unzOpenCurrentFile(pkg);
- ret = unzReadCurrentFile(pkg, data.ptrw(), data.size());
+ ret = unzReadCurrentFile(pkg, uncomp_data.ptrw(), uncomp_data.size());
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", rel_path));
unzCloseCurrentFile(pkg);
Ref<FileAccess> f = FileAccess::open(dir.path_join(rel_path), FileAccess::WRITE);
if (f.is_valid()) {
- f->store_buffer(data.ptr(), data.size());
+ f->store_buffer(uncomp_data.ptr(), uncomp_data.size());
} else {
failed_files.push_back(rel_path);
}
@@ -710,7 +714,7 @@ public:
create_dir->hide();
} else {
- fav_dir = EditorSettings::get_singleton()->get("filesystem/directories/default_project_path");
+ fav_dir = EDITOR_GET("filesystem/directories/default_project_path");
if (!fav_dir.is_empty()) {
project_path->set_text(fav_dir);
fdialog->set_current_dir(fav_dir);
@@ -1261,7 +1265,7 @@ void ProjectList::migrate_config() {
continue;
}
- String path = EditorSettings::get_singleton()->get(property_key);
+ String path = EDITOR_GET(property_key);
String favoriteKey = "favorite_projects/" + property_key.get_slice("/", 1);
bool favorite = EditorSettings::get_singleton()->has_setting(favoriteKey);
add_project(path, favorite);
@@ -1490,7 +1494,7 @@ void ProjectList::sort_projects() {
for (int i = 0; i < _projects.size(); ++i) {
Item &item = _projects.write[i];
- bool visible = true;
+ bool item_visible = true;
if (!_search_term.is_empty()) {
String search_path;
if (_search_term.contains("/")) {
@@ -1502,10 +1506,10 @@ void ProjectList::sort_projects() {
}
// When searching, display projects whose name or path contain the search term
- visible = item.project_name.findn(_search_term) != -1 || search_path.findn(_search_term) != -1;
+ item_visible = item.project_name.findn(_search_term) != -1 || search_path.findn(_search_term) != -1;
}
- item.control->set_visible(visible);
+ item.control->set_visible(item_visible);
}
for (int i = 0; i < _projects.size(); ++i) {
@@ -1912,7 +1916,7 @@ void ProjectManager::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- int default_sorting = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order");
+ int default_sorting = (int)EDITOR_GET("project_manager/sorting_order");
filter_option->select(default_sorting);
_project_list->set_order_option(default_sorting);
@@ -2557,7 +2561,7 @@ ProjectManager::ProjectManager() {
EditorSettings::get_singleton()->set_optimize_save(false); //just write settings as they came
{
- int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ int display_scale = EDITOR_GET("interface/editor/display_scale");
switch (display_scale) {
case 0:
@@ -2583,7 +2587,7 @@ ProjectManager::ProjectManager() {
editor_set_scale(2.0);
break;
default:
- editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
+ editor_set_scale(EDITOR_GET("interface/editor/custom_display_scale"));
break;
}
EditorFileDialog::get_icon_func = &ProjectManager::_file_dialog_get_icon;
@@ -2592,7 +2596,13 @@ ProjectManager::ProjectManager() {
// TRANSLATORS: This refers to the application where users manage their Godot projects.
DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager", "Application"));
- EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
+
+ int swap_cancel_ok = EDITOR_GET("interface/editor/accept_dialog_cancel_ok_buttons");
+ if (swap_cancel_ok != 0) { // 0 is auto, set in register_scene based on DisplayServer.
+ // Swap on means OK first.
+ AcceptDialog::set_swap_cancel_ok(swap_cancel_ok == 2);
+ }
set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
set_theme(create_custom_theme());
@@ -2805,7 +2815,7 @@ ProjectManager::ProjectManager() {
}
}
- String current_lang = EditorSettings::get_singleton()->get("interface/editor/editor_language");
+ String current_lang = EDITOR_GET("interface/editor/editor_language");
language_btn->set_text(current_lang);
for (int i = 0; i < editor_languages.size(); i++) {
@@ -2844,7 +2854,7 @@ ProjectManager::ProjectManager() {
scan_dir->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
scan_dir->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
- scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
+ scan_dir->set_current_dir(EDITOR_GET("filesystem/directories/default_project_path"));
add_child(scan_dir);
scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
@@ -2926,7 +2936,7 @@ ProjectManager::ProjectManager() {
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM);
- String default_project_path = EditorSettings::get_singleton()->get("filesystem/directories/default_project_path");
+ String default_project_path = EDITOR_GET("filesystem/directories/default_project_path");
if (!dir_access->dir_exists(default_project_path)) {
Error error = dir_access->make_dir_recursive(default_project_path);
if (error != OK) {
@@ -2934,7 +2944,7 @@ ProjectManager::ProjectManager() {
}
}
- String autoscan_path = EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path");
+ String autoscan_path = EDITOR_GET("filesystem/directories/autoscan_project_path");
if (!autoscan_path.is_empty()) {
if (dir_access->dir_exists(autoscan_path)) {
_scan_begin(autoscan_path);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 2da49f11cc..f23b08409e 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/check_button.h"
#include "servers/movie_writer/movie_writer.h"
ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr;
@@ -72,6 +73,11 @@ void ProjectSettingsEditor::set_plugins_page() {
tab_container->set_current_tab(tab_container->get_tab_idx_from_control(plugin_settings));
}
+void ProjectSettingsEditor::set_general_page(const String &p_category) {
+ tab_container->set_current_tab(tab_container->get_tab_idx_from_control(general_editor));
+ general_settings_inspector->set_current_section(p_category);
+}
+
void ProjectSettingsEditor::update_plugins() {
plugin_settings->update_plugins();
}
@@ -346,7 +352,7 @@ void ProjectSettingsEditor::_action_added(const String &p_name) {
void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionary &p_action) {
const String property_name = "input/" + p_name;
- Dictionary old_val = ProjectSettings::get_singleton()->get(property_name);
+ Dictionary old_val = GLOBAL_GET(property_name);
if (old_val["deadzone"] != p_action["deadzone"]) {
// Deadzone Changed
@@ -356,12 +362,12 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar
} else {
// Events changed
- int event_count = ((Array)p_action["events"]).size();
+ int act_event_count = ((Array)p_action["events"]).size();
int old_event_count = ((Array)old_val["events"]).size();
- if (event_count == old_event_count) {
+ if (act_event_count == old_event_count) {
undo_redo->create_action(TTR("Edit Input Action Event"));
- } else if (event_count > old_event_count) {
+ } else if (act_event_count > old_event_count) {
undo_redo->create_action(TTR("Add Input Action Event"));
} else {
undo_redo->create_action(TTR("Remove Input Action Event"));
@@ -381,7 +387,7 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar
void ProjectSettingsEditor::_action_removed(const String &p_name) {
const String property_name = "input/" + p_name;
- Dictionary old_val = ProjectSettings::get_singleton()->get(property_name);
+ Dictionary old_val = GLOBAL_GET(property_name);
int order = ProjectSettings::get_singleton()->get_order(property_name);
undo_redo->create_action(TTR("Erase Input Action"));
@@ -404,7 +410,7 @@ void ProjectSettingsEditor::_action_renamed(const String &p_old_name, const Stri
"An action with this name already exists.");
int order = ProjectSettings::get_singleton()->get_order(old_property_name);
- Dictionary action = ProjectSettings::get_singleton()->get(old_property_name);
+ Dictionary action = GLOBAL_GET(old_property_name);
undo_redo->create_action(TTR("Rename Input Action Event"));
// Do: clear old, set new
@@ -499,7 +505,7 @@ void ProjectSettingsEditor::_update_action_map_editor() {
// Strip the "input/" from the left.
String display_name = property_name.substr(String("input/").size() - 1);
- Dictionary action = ProjectSettings::get_singleton()->get(property_name);
+ Dictionary action = GLOBAL_GET(property_name);
ActionMapEditor::ActionInfo action_info;
action_info.action = action;
@@ -575,7 +581,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
tab_container->set_theme_type_variation("TabContainerOdd");
add_child(tab_container);
- VBoxContainer *general_editor = memnew(VBoxContainer);
+ general_editor = memnew(VBoxContainer);
general_editor->set_name(TTR("General"));
general_editor->set_alignment(BoxContainer::ALIGNMENT_BEGIN);
general_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 040d992e40..ec10c76cb7 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -53,6 +53,7 @@ class ProjectSettingsEditor : public AcceptDialog {
Timer *timer = nullptr;
TabContainer *tab_container = nullptr;
+ VBoxContainer *general_editor = nullptr;
SectionedInspector *general_settings_inspector = nullptr;
ActionMapEditor *action_map_editor = nullptr;
LocalizationEditor *localization_editor = nullptr;
@@ -116,6 +117,7 @@ public:
static ProjectSettingsEditor *get_singleton() { return singleton; }
void popup_project_settings();
void set_plugins_page();
+ void set_general_page(const String &p_category);
void update_plugins();
EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; }
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 300a3d0f05..f918570c66 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -652,9 +652,9 @@ void RenameDialog::_features_toggled(bool pressed) {
}
// Adjust to minimum size in y
- Size2i size = get_size();
- size.y = 0;
- set_size(size);
+ Size2i new_size = get_size();
+ new_size.y = 0;
+ set_size(new_size);
}
#endif // MODULE_REGEX_ENABLED
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 4563dbb0f7..5b54a5a229 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -170,9 +170,9 @@ Node *SceneCreateDialog::create_scene_root() {
root = memnew(Node3D);
break;
case ROOT_USER_INTERFACE: {
- Control *gui = memnew(Control);
- gui->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- root = gui;
+ Control *gui_ctl = memnew(Control);
+ gui_ctl->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ root = gui_ctl;
} break;
case ROOT_OTHER:
root = Object::cast_to<Node>(select_node_dialog->instance_selected());
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index d1dc188be9..6a935b4f7b 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -330,9 +330,9 @@ bool SceneTreeDock::_track_inherit(const String &p_target_scene_path, Node *p_de
Ref<SceneState> ss = p->get_scene_inherited_state();
if (ss.is_valid()) {
String path = ss->get_path();
- Ref<PackedScene> data = ResourceLoader::load(path);
- if (data.is_valid()) {
- p = data->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ Ref<PackedScene> pack_data = ResourceLoader::load(path);
+ if (pack_data.is_valid()) {
+ p = pack_data->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!p) {
continue;
}
@@ -946,7 +946,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
} break;
case TOOL_AUTO_EXPAND: {
- scene_tree->set_auto_expand_selected(!EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"), true);
+ scene_tree->set_auto_expand_selected(!EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), true);
} break;
case TOOL_SCENE_EDITABLE_CHILDREN: {
if (!profile_allow_editing) {
@@ -1147,9 +1147,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
String name = selected_favorite_root.get_slicec(' ', 0);
if (ScriptServer::is_global_class(name)) {
new_node = Object::cast_to<Node>(ClassDB::instantiate(ScriptServer::get_global_class_native_base(name)));
- Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script");
- if (new_node && script.is_valid()) {
- new_node->set_script(script);
+ Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script");
+ if (new_node && scr.is_valid()) {
+ new_node->set_script(scr);
new_node->set_name(name);
}
} else {
@@ -1187,6 +1187,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
} break;
default: {
+ _filter_option_selected(p_tool);
+
if (p_tool >= EDIT_SUBRESOURCE_BASE) {
int idx = p_tool - EDIT_SUBRESOURCE_BASE;
@@ -1235,14 +1237,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_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));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
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_mp(scene_tree, &SceneTreeEditor::_update_tree));
- spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_lock_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
+ spatial_editor_plugin->get_spatial_editor()->connect("item_group_status_changed", callable_mp(scene_tree, &SceneTreeEditor::_update_tree).bind(false));
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
@@ -1323,7 +1325,7 @@ void SceneTreeDock::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
clear_inherit_confirm->connect("confirmed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM, false));
- scene_tree->set_auto_expand_selected(EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"), false);
+ scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -1331,7 +1333,7 @@ void SceneTreeDock::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- scene_tree->set_auto_expand_selected(EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"), false);
+ scene_tree->set_auto_expand_selected(EDITOR_GET("docks/scene_tree/auto_expand_to_selected"), false);
button_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_instance->set_icon(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")));
button_create_script->set_icon(get_theme_icon(SNAME("ScriptCreate"), SNAME("EditorIcons")));
@@ -1399,6 +1401,7 @@ void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root
void SceneTreeDock::_load_request(const String &p_path) {
EditorNode::get_singleton()->open_request(p_path);
+ _local_tree_selected();
}
void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) {
@@ -2174,11 +2177,15 @@ void SceneTreeDock::_selection_changed() {
void SceneTreeDock::_do_create(Node *p_parent) {
Variant c = create_dialog->instance_selected();
-
- ERR_FAIL_COND(!c);
Node *child = Object::cast_to<Node>(c);
ERR_FAIL_COND(!child);
+ String new_name = p_parent->validate_child_name(child);
+ if (GLOBAL_GET("editor/node_naming/name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
+ new_name = adjust_name_casing(new_name);
+ }
+ child->set_name(new_name);
+
editor_data->get_undo_redo()->create_action_for_history(TTR("Create Node"), editor_data->get_current_edited_scene_history_id());
if (edited_scene) {
@@ -2189,7 +2196,6 @@ void SceneTreeDock::_do_create(Node *p_parent) {
editor_data->get_undo_redo()->add_do_reference(child);
editor_data->get_undo_redo()->add_undo_method(p_parent, "remove_child", child);
- String new_name = p_parent->validate_child_name(child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
@@ -2442,7 +2448,7 @@ void SceneTreeDock::_new_scene_from(String p_file) {
}
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
@@ -2883,11 +2889,83 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
void SceneTreeDock::_update_tree_menu() {
PopupMenu *tree_menu = button_tree_menu->get_popup();
- tree_menu->set_item_checked(tree_menu->get_item_idx_from_text(TTR("Auto Expand to Selected")), EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"));
+ tree_menu->clear();
+
+ _append_filter_options_to(tree_menu);
+
+ tree_menu->add_separator();
+ tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
+ tree_menu->set_item_checked(tree_menu->get_item_index(TOOL_AUTO_EXPAND), EDITOR_GET("docks/scene_tree/auto_expand_to_selected"));
+}
+
+void SceneTreeDock::_update_filter_menu() {
+ _append_filter_options_to(filter->get_menu());
}
void SceneTreeDock::_filter_changed(const String &p_filter) {
scene_tree->set_filter(p_filter);
+
+ String warning = scene_tree->get_filter_term_warning();
+ if (!warning.is_empty()) {
+ filter->add_theme_icon_override(SNAME("clear"), get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ filter->set_tooltip_text(warning);
+ } else {
+ filter->remove_theme_icon_override(SNAME("clear"));
+ filter->set_tooltip_text("");
+ }
+}
+
+void SceneTreeDock::_filter_gui_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_null()) {
+ return;
+ }
+
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::MIDDLE) {
+ filter_quick_menu->clear();
+
+ _append_filter_options_to(filter_quick_menu, false);
+ filter_quick_menu->set_position(get_screen_position() + get_local_mouse_position());
+ filter_quick_menu->reset_size();
+ filter_quick_menu->popup();
+ filter_quick_menu->grab_focus();
+ accept_event();
+ }
+}
+
+void SceneTreeDock::_filter_option_selected(int p_option) {
+ String filter_parameter;
+ switch (p_option) {
+ case FILTER_BY_TYPE: {
+ filter_parameter = "type";
+ } break;
+ case FILTER_BY_GROUP: {
+ filter_parameter = "group";
+ } break;
+ }
+
+ if (!filter_parameter.is_empty()) {
+ set_filter((get_filter() + " " + filter_parameter + ":").strip_edges());
+ filter->set_caret_column(filter->get_text().length());
+ filter->grab_focus();
+ }
+}
+
+void SceneTreeDock::_append_filter_options_to(PopupMenu *p_menu, bool p_include_separator) {
+ if (p_include_separator) {
+ p_menu->add_separator();
+
+ p_menu->set_item_text(-1, TTR("Filters"));
+ p_menu->set_item_icon(-1, get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ p_menu->set_item_indent(-1, -2);
+ }
+
+ p_menu->add_item(TTR("Filter by Type"), FILTER_BY_TYPE);
+ p_menu->add_item(TTR("Filter by Group"), FILTER_BY_GROUP);
+ p_menu->set_item_icon(p_menu->get_item_index(FILTER_BY_TYPE), get_theme_icon(SNAME("Node"), SNAME("EditorIcons")));
+ p_menu->set_item_icon(p_menu->get_item_index(FILTER_BY_GROUP), get_theme_icon(SNAME("Groups"), SNAME("EditorIcons")));
+ p_menu->set_item_tooltip(p_menu->get_item_index(FILTER_BY_TYPE), TTR("Selects all Nodes of the given type."));
+ p_menu->set_item_tooltip(p_menu->get_item_index(FILTER_BY_GROUP), TTR("Selects all Nodes belonging to the given group.\nIf empty, selects any Node belonging to any group."));
}
String SceneTreeDock::get_filter() {
@@ -3141,6 +3219,7 @@ void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
add_child(p_remote);
remote_tree = p_remote;
remote_tree->hide();
+ remote_tree->connect("open", callable_mp(this, &SceneTreeDock::_load_request));
}
void SceneTreeDock::show_remote_tree() {
@@ -3187,7 +3266,7 @@ void SceneTreeDock::_update_create_root_dialog() {
EditorSettings::get_singleton()->save();
if (node_shortcuts_toggle->is_pressed()) {
for (int i = 0; i < favorite_node_shortcuts->get_child_count(); i++) {
- favorite_node_shortcuts->get_child(i)->queue_delete();
+ favorite_node_shortcuts->get_child(i)->queue_free();
}
Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
@@ -3399,14 +3478,22 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene"));
filter_hbc->add_child(button_instance);
-
vbc->add_child(filter_hbc);
+
+ // The "Filter Nodes" text input above the Scene Tree Editor.
filter = memnew(LineEdit);
filter->set_h_size_flags(SIZE_EXPAND_FILL);
filter->set_placeholder(TTR("Filter Nodes"));
filter_hbc->add_child(filter);
filter->add_theme_constant_override("minimum_character_width", 0);
filter->connect("text_changed", callable_mp(this, &SceneTreeDock::_filter_changed));
+ filter->connect("gui_input", callable_mp(this, &SceneTreeDock::_filter_gui_input));
+ filter->get_menu()->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_update_filter_menu));
+ filter->get_menu()->connect("id_pressed", callable_mp(this, &SceneTreeDock::_filter_option_selected));
+
+ filter_quick_menu = memnew(PopupMenu);
+ filter_quick_menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_filter_option_selected));
+ filter->add_child(filter_quick_menu);
button_create_script = memnew(Button);
button_create_script->set_flat(true);
@@ -3430,7 +3517,6 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
filter_hbc->add_child(button_tree_menu);
PopupMenu *tree_menu = button_tree_menu->get_popup();
- tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
tree_menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
button_hb = memnew(HBoxContainer);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index e48b518252..04bb4d93e7 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -160,7 +160,13 @@ class SceneTreeDock : public VBoxContainer {
EditorQuickOpen *quick_open = nullptr;
EditorFileDialog *new_scene_from_dialog = nullptr;
+ enum FilterMenuItems {
+ FILTER_BY_TYPE = 64, // Used in the same menus as the Tool enum.
+ FILTER_BY_GROUP,
+ };
+
LineEdit *filter = nullptr;
+ PopupMenu *filter_quick_menu = nullptr;
TextureRect *filter_icon = nullptr;
PopupMenu *menu = nullptr;
@@ -243,8 +249,12 @@ class SceneTreeDock : public VBoxContainer {
void _tree_rmb(const Vector2 &p_menu_pos);
void _update_tree_menu();
+ void _update_filter_menu();
void _filter_changed(const String &p_filter);
+ void _filter_gui_input(const Ref<InputEvent> &p_event);
+ void _filter_option_selected(int option);
+ void _append_filter_options_to(PopupMenu *p_menu, bool p_include_separator = true);
void _perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos);
void _replace_with_branch_scene(const String &p_file, Node *base);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 7bcc8aa078..c8bc189106 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -215,8 +215,8 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (connect_to_script_mode) {
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- Ref<Script> script = p_node->get_script();
- if (!script.is_null() && EditorNode::get_singleton()->get_object_custom_type_base(p_node) != script) {
+ Ref<Script> scr = p_node->get_script();
+ if (!scr.is_null() && EditorNode::get_singleton()->get_object_custom_type_base(p_node) != scr) {
//has script
item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT);
} else {
@@ -224,7 +224,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->set_custom_color(0, get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")));
item->set_selectable(0, false);
- if (!script.is_null()) { // make sure to mark the script if a custom type
+ if (!scr.is_null()) { // make sure to mark the script if a custom type
item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT);
item->set_button_disabled(0, item->get_button_count(0) - 1, true);
}
@@ -268,8 +268,8 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (can_rename) { //should be can edit..
- String warning = p_node->get_configuration_warnings_as_string();
- if (!warning.is_empty()) {
+ String conf_warning = p_node->get_configuration_warnings_as_string();
+ if (!conf_warning.is_empty()) {
const int num_warnings = p_node->get_configuration_warnings().size();
String warning_icon;
if (num_warnings == 1) {
@@ -284,15 +284,15 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
const String bullet_point = String::utf8("• ");
int next_newline = 0;
while (next_newline != -1) {
- next_newline = warning.find("\n", next_newline + 2);
- if (warning.substr(next_newline + 1, bullet_point.length()) != bullet_point) {
- warning = warning.insert(next_newline + 1, " ");
+ next_newline = conf_warning.find("\n", next_newline + 2);
+ if (conf_warning.substr(next_newline + 1, bullet_point.length()) != bullet_point) {
+ conf_warning = conf_warning.insert(next_newline + 1, " ");
}
}
String newline = (num_warnings == 1 ? "\n" : "\n\n");
- item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + newline + warning);
+ item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + newline + conf_warning);
}
if (p_node->is_unique_name_in_owner()) {
@@ -385,20 +385,20 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
p_node->connect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed).bind(p_node));
}
- Ref<Script> script = p_node->get_script();
- if (!script.is_null()) {
+ Ref<Script> scr = p_node->get_script();
+ if (!scr.is_null()) {
String additional_notes;
Color button_color = Color(1, 1, 1);
// Can't set tooltip after adding button, need to do it before.
- if (script->is_tool()) {
+ if (scr->is_tool()) {
additional_notes += "\n" + TTR("This script is currently running in the editor.");
button_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
}
- if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == script) {
+ if (EditorNode::get_singleton()->get_object_custom_type_base(p_node) == scr) {
additional_notes += "\n" + TTR("This script is a custom type.");
button_color.a = 0.5;
}
- item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + script->get_path() + additional_notes);
+ item->add_button(0, get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), BUTTON_SCRIPT, false, TTR("Open Script:") + " " + scr->get_path() + additional_notes);
item->set_button_color(0, item->get_button_count(0) - 1, button_color);
}
@@ -483,8 +483,9 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
if (valid_types.size()) {
bool valid = false;
- for (int i = 0; i < valid_types.size(); i++) {
- if (p_node->is_class(valid_types[i])) {
+ for (const StringName &E : valid_types) {
+ if (p_node->is_class(E) ||
+ EditorNode::get_singleton()->is_object_of_custom_type(p_node, E)) {
valid = true;
break;
}
@@ -511,16 +512,16 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
int idx = item->get_button_by_id(0, BUTTON_VISIBILITY);
ERR_FAIL_COND(idx == -1);
- bool visible = false;
+ bool node_visible = false;
if (p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer") || p_node->is_class("Window")) {
- visible = p_node->call("is_visible");
+ node_visible = p_node->call("is_visible");
CanvasItemEditor::get_singleton()->get_viewport_control()->queue_redraw();
} else if (p_node->is_class("Node3D")) {
- visible = p_node->call("is_visible");
+ node_visible = p_node->call("is_visible");
}
- if (visible) {
+ if (node_visible) {
item->set_button(0, idx, get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")));
} else {
item->set_button(0, idx, get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons")));
@@ -612,6 +613,7 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_selected) {
if (!p_parent) {
p_parent = tree->get_root();
+ filter_term_warning.clear();
}
if (!p_parent) {
@@ -673,27 +675,37 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra
if (parameter == "type" || parameter == "t") {
// Filter by Type.
- String node_type = get_node(p_item->get_metadata(0))->get_class().to_lower();
+ String type = get_node(p_item->get_metadata(0))->get_class();
+ bool term_in_inherited_class = false;
+ // Every Node is is a Node, duh!
+ while (type != "Node") {
+ if (type.to_lower().contains(argument)) {
+ term_in_inherited_class = true;
+ break;
+ }
- if (!node_type.contains(argument)) {
+ type = ClassDB::get_parent_class(type);
+ }
+ if (!term_in_inherited_class) {
return false;
}
} else if (parameter == "group" || parameter == "g") {
// Filter by Group.
Node *node = get_node(p_item->get_metadata(0));
- List<Node::GroupInfo> group_info_list;
- node->get_groups(&group_info_list);
- if (group_info_list.is_empty()) {
- return false;
- }
- // When argument is empty, match all Nodes belonging to any group.
- if (!argument.is_empty()) {
+ if (argument.is_empty()) {
+ // When argument is empty, match all Nodes belonging to any exposed group.
+ if (node->get_persistent_group_count() == 0) {
+ return false;
+ }
+ } else {
+ List<Node::GroupInfo> group_info_list;
+ node->get_groups(&group_info_list);
+
bool term_in_groups = false;
for (int j = 0; j < group_info_list.size(); j++) {
- // Ignore private groups.
- if (String(group_info_list[j].name).begins_with("__")) {
- continue;
+ if (!group_info_list[j].persistent) {
+ continue; // Ignore internal groups.
}
if (String(group_info_list[j].name).to_lower().contains(argument)) {
term_in_groups = true;
@@ -704,8 +716,8 @@ bool SceneTreeEditor::_item_matches_all_terms(TreeItem *p_item, PackedStringArra
return false;
}
}
- } else {
- WARN_PRINT(vformat(TTR("Special Node filter \"%s\" is not recognised. Available filters include \"type\" and \"group\"."), parameter));
+ } else if (filter_term_warning.is_empty()) {
+ filter_term_warning = vformat(TTR("\"%s\" is not a known filter."), parameter);
continue;
}
} else {
@@ -804,6 +816,10 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_
TreeItem *item = Object::cast_to<TreeItem>(p_object);
ERR_FAIL_COND(!item);
+ if (!item->is_visible()) {
+ return;
+ }
+
NodePath np = item->get_metadata(0);
Node *n = get_node(np);
@@ -1025,6 +1041,10 @@ String SceneTreeEditor::get_filter() const {
return filter;
}
+String SceneTreeEditor::get_filter_term_warning() {
+ return filter_term_warning;
+}
+
void SceneTreeEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -1119,7 +1139,7 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
return Variant(); //dragging from button
}
- Vector<Node *> selected;
+ Vector<Node *> selected_nodes;
Vector<Ref<Texture2D>> icons;
TreeItem *next = tree->get_next_selected(nullptr);
while (next) {
@@ -1129,14 +1149,14 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
if (n) {
// Only allow selection if not part of an instantiated scene.
if (!n->get_owner() || n->get_owner() == get_scene_node() || n->get_owner()->get_scene_file_path().is_empty()) {
- selected.push_back(n);
+ selected_nodes.push_back(n);
icons.push_back(next->get_icon(0));
}
}
next = tree->get_next_selected(next);
}
- if (selected.is_empty()) {
+ if (selected_nodes.is_empty()) {
return Variant();
}
@@ -1145,20 +1165,20 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
int list_max = 10;
float opacity_step = 1.0f / list_max;
float opacity_item = 1.0f;
- for (int i = 0; i < selected.size(); i++) {
+ for (int i = 0; i < selected_nodes.size(); i++) {
if (i < list_max) {
HBoxContainer *hb = memnew(HBoxContainer);
TextureRect *tf = memnew(TextureRect);
tf->set_texture(icons[i]);
tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
hb->add_child(tf);
- Label *label = memnew(Label(selected[i]->get_name()));
+ Label *label = memnew(Label(selected_nodes[i]->get_name()));
hb->add_child(label);
vb->add_child(hb);
hb->set_modulate(Color(1, 1, 1, opacity_item));
opacity_item -= opacity_step;
}
- NodePath p = selected[i]->get_path();
+ NodePath p = selected_nodes[i]->get_path();
objs.push_back(p);
}
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 8fbc3ab6d6..dcdfead885 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -62,6 +62,7 @@ class SceneTreeEditor : public Control {
ObjectID instance_node;
String filter;
+ String filter_term_warning;
AcceptDialog *error = nullptr;
AcceptDialog *warning = nullptr;
@@ -142,6 +143,7 @@ public:
void set_filter(const String &p_filter);
String get_filter() const;
+ String get_filter_term_warning();
void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_display_foreign_nodes(bool p_display);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index f57dfe4827..cc09c3a432 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -828,9 +828,9 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_get_current_template() const
return ScriptLanguage::ScriptTemplate();
}
-Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(const ScriptLanguage *language, const StringName &p_object, const String &p_dir, const ScriptLanguage::TemplateLocation &p_origin) const {
+Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(const ScriptLanguage *p_language, const StringName &p_object, const String &p_dir, const ScriptLanguage::TemplateLocation &p_origin) const {
Vector<ScriptLanguage::ScriptTemplate> user_templates;
- String extension = language->get_extension();
+ String extension = p_language->get_extension();
String dir_path = p_dir.path_join(p_object);
@@ -840,7 +840,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c
String file = d->get_next();
while (file != String()) {
if (file.get_extension() == extension) {
- user_templates.append(_parse_template(language, dir_path, file, p_origin, p_object));
+ user_templates.append(_parse_template(p_language, dir_path, file, p_origin, p_object));
}
file = d->get_next();
}
@@ -849,7 +849,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c
return user_templates;
}
-ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptLanguage *language, const String &p_path, const String &p_filename, const ScriptLanguage::TemplateLocation &p_origin, const String &p_inherits) const {
+ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptLanguage *p_language, const String &p_path, const String &p_filename, const ScriptLanguage::TemplateLocation &p_origin, const String &p_inherits) const {
ScriptLanguage::ScriptTemplate script_template = ScriptLanguage::ScriptTemplate();
script_template.origin = p_origin;
script_template.inherit = p_inherits;
@@ -857,7 +857,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
// Get meta delimiter
String meta_delimiter = String();
List<String> comment_delimiters;
- language->get_comment_delimiters(&comment_delimiters);
+ p_language->get_comment_delimiters(&comment_delimiters);
for (const String &script_delimiter : comment_delimiters) {
if (!script_delimiter.contains(" ")) {
meta_delimiter = script_delimiter;
diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h
index c7d8cfc38a..fb1a49a1ca 100644
--- a/editor/script_create_dialog.h
+++ b/editor/script_create_dialog.h
@@ -119,8 +119,8 @@ class ScriptCreateDialog : public ConfirmationDialog {
void _update_template_menu();
void _update_dialog();
ScriptLanguage::ScriptTemplate _get_current_template() const;
- Vector<ScriptLanguage::ScriptTemplate> _get_user_templates(const ScriptLanguage *language, const StringName &p_object, const String &p_dir, const ScriptLanguage::TemplateLocation &p_origin) const;
- ScriptLanguage::ScriptTemplate _parse_template(const ScriptLanguage *language, const String &p_path, const String &p_filename, const ScriptLanguage::TemplateLocation &p_origin, const String &p_inherits) const;
+ Vector<ScriptLanguage::ScriptTemplate> _get_user_templates(const ScriptLanguage *p_language, const StringName &p_object, const String &p_dir, const ScriptLanguage::TemplateLocation &p_origin) const;
+ ScriptLanguage::ScriptTemplate _parse_template(const ScriptLanguage *p_language, const String &p_path, const String &p_filename, const ScriptLanguage::TemplateLocation &p_origin, const String &p_inherits) const;
String _get_script_origin_label(const ScriptLanguage::TemplateLocation &p_origin) const;
protected:
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index ae533b5b75..cdbe88b99e 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -96,20 +96,20 @@ void ShaderCreateDialog::_update_language_info() {
type_data.clear();
for (int i = 0; i < SHADER_TYPE_MAX; i++) {
- ShaderTypeData data;
+ ShaderTypeData shader_type_data;
if (i == int(SHADER_TYPE_TEXT)) {
- data.use_templates = true;
- data.extensions.push_back("gdshader");
- data.default_extension = "gdshader";
+ shader_type_data.use_templates = true;
+ shader_type_data.extensions.push_back("gdshader");
+ shader_type_data.default_extension = "gdshader";
} else if (i == int(SHADER_TYPE_INC)) {
- data.extensions.push_back("gdshaderinc");
- data.default_extension = "gdshaderinc";
+ shader_type_data.extensions.push_back("gdshaderinc");
+ shader_type_data.default_extension = "gdshaderinc";
} else {
- data.default_extension = "tres";
+ shader_type_data.default_extension = "tres";
}
- data.extensions.push_back("res");
- data.extensions.push_back("tres");
- type_data.push_back(data);
+ shader_type_data.extensions.push_back("res");
+ shader_type_data.extensions.push_back("tres");
+ type_data.push_back(shader_type_data);
}
}
@@ -261,9 +261,9 @@ void ShaderCreateDialog::_load_exist() {
void ShaderCreateDialog::_type_changed(int p_language) {
current_type = p_language;
- ShaderTypeData data = type_data[p_language];
+ ShaderTypeData shader_type_data = type_data[p_language];
- String selected_ext = "." + data.default_extension;
+ String selected_ext = "." + shader_type_data.default_extension;
String path = file_path->get_text();
String extension = "";
@@ -284,10 +284,10 @@ void ShaderCreateDialog::_type_changed(int p_language) {
type_menu->set_item_disabled(int(SHADER_TYPE_INC), load_enabled);
mode_menu->set_disabled(p_language == SHADER_TYPE_INC);
- template_menu->set_disabled(!data.use_templates);
+ template_menu->set_disabled(!shader_type_data.use_templates);
template_menu->clear();
- if (data.use_templates) {
+ if (shader_type_data.use_templates) {
int last_template = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_template", 0);
template_menu->add_item(TTR("Default"));
@@ -437,8 +437,6 @@ String ShaderCreateDialog::_validate_path(const String &p_path) {
}
}
- ShaderTypeData data = type_data[type_menu->get_selected()];
-
bool found = false;
bool match = false;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 473bbd69d9..6967536692 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -107,7 +107,7 @@ protected:
String path = "shader_globals/" + String(p_name);
undo_redo->add_do_property(ProjectSettings::get_singleton(), path, gv);
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), path, ProjectSettings::get_singleton()->get(path));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), path, GLOBAL_GET(path));
undo_redo->add_do_method(this, "_var_changed");
undo_redo->add_undo_method(this, "_var_changed");
block_update = true;
@@ -420,7 +420,7 @@ void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_add", p_variable, RS::get_singleton()->global_shader_parameter_get_type(p_variable), RS::get_singleton()->global_shader_parameter_get(p_variable));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, Variant());
- undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, ProjectSettings::get_singleton()->get("shader_globals/" + p_variable));
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "shader_globals/" + p_variable, GLOBAL_GET("shader_globals/" + p_variable));
undo_redo->add_do_method(this, "_changed");
undo_redo->add_undo_method(this, "_changed");
undo_redo->commit_action();
diff --git a/gles3_builders.py b/gles3_builders.py
index 84f11532e0..46ab1bbc03 100644
--- a/gles3_builders.py
+++ b/gles3_builders.py
@@ -436,7 +436,7 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
)
fd.write(
- """_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, const Projection& p_matrix,RID p_version,ShaderVariant p_variant"""
+ """_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, const Projection& p_matrix, RID p_version, ShaderVariant p_variant"""
+ defvariant
+ """,uint64_t p_specialization="""
+ str(defspec)
@@ -444,13 +444,13 @@ def build_gles3_header(filename: str, include: str, class_suffix: str, header_da
GLfloat matrix[16];
- for (int i=0;i<4;i++) {
- for (int j=0;j<4;j++) {
- matrix[i*4+j]=p_matrix.matrix[i][j];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ matrix[i * 4 + j] = p_matrix.columns[i][j];
}
}
- glUniformMatrix4fv(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),1,false,matrix);
+ glUniformMatrix4fv(version_get_uniform(p_uniform, p_version, p_variant, p_specialization), 1, false, matrix);
}"""
)
diff --git a/main/main.cpp b/main/main.cpp
index 5c2259bf7c..2a08b03b96 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -36,6 +36,7 @@
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
#include "core/extension/extension_api_dump.h"
+#include "core/extension/gdnative_interface_dump.gen.h"
#include "core/extension/native_extension_manager.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
@@ -199,6 +200,7 @@ static MovieWriter *movie_writer = nullptr;
static bool disable_vsync = false;
static bool print_fps = false;
#ifdef TOOLS_ENABLED
+static bool dump_gdnative_interface = false;
static bool dump_extension_api = false;
#endif
bool profile_gpu = false;
@@ -231,7 +233,7 @@ static String get_full_version_string() {
void initialize_physics() {
/// 3D Physics Server
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server(
- ProjectSettings::get_singleton()->get(PhysicsServer3DManager::setting_property_name));
+ GLOBAL_GET(PhysicsServer3DManager::setting_property_name));
if (!physics_server_3d) {
// Physics server not found, Use the default physics
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
@@ -241,7 +243,7 @@ void initialize_physics() {
// 2D Physics server
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server(
- ProjectSettings::get_singleton()->get(PhysicsServer2DManager::get_singleton()->setting_property_name));
+ GLOBAL_GET(PhysicsServer2DManager::get_singleton()->setting_property_name));
if (!physics_server_2d) {
// Physics server not found, Use the default physics
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
@@ -414,6 +416,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
+ OS::get_singleton()->print(" --dump-gdextension-interface Generate GDExtension header file 'gdnative_interface.h' in the current folder. This file is the base file required to implement a GDExtension.\n");
OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n");
OS::get_singleton()->print(" --startup-benchmark Benchmark the startup time and print it to console.\n");
OS::get_singleton()->print(" --startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.\n");
@@ -1054,6 +1057,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
auto_build_solutions = true;
editor = true;
cmdline_tool = true;
+ } else if (I->get() == "--dump-gdextension-interface") {
+ // Register as an editor instance to use low-end fallback if relevant.
+ editor = true;
+ cmdline_tool = true;
+ dump_gdnative_interface = true;
+ print_line("Dumping gdnative interface header file");
+ // Hack. Not needed but otherwise we end up detecting that this should
+ // run the project instead of a cmdline tool.
+ // Needs full refactoring to fix properly.
+ main_args.push_back(I->get());
} else if (I->get() == "--dump-extension-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
@@ -1446,10 +1459,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
input_map->load_from_project_settings(); //keys for game
}
- if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stdout"))) {
+ if (bool(GLOBAL_GET("application/run/disable_stdout"))) {
quiet_stdout = true;
}
- if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stderr"))) {
+ if (bool(GLOBAL_GET("application/run/disable_stderr"))) {
CoreGlobals::print_error_enabled = false;
};
@@ -1457,7 +1470,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
CoreGlobals::print_line_enabled = false;
}
- Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
+ Logger::set_flush_stdout_on_print(GLOBAL_GET("application/run/flush_stdout_on_print"));
OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
@@ -1530,6 +1543,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (default_renderer_mobile.is_empty()) {
default_renderer_mobile = "gl_compatibility";
}
+ // Default to Compatibility when using the project manager.
+ if (rendering_driver.is_empty() && rendering_method.is_empty() && project_manager) {
+ rendering_driver = "opengl3";
+ rendering_method = "gl_compatibility";
+ }
#endif
if (renderer_hints.is_empty()) {
ERR_PRINT("No renderers available.");
@@ -1590,11 +1608,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Now validate whether the selected driver matches with the renderer.
bool valid_combination = false;
Vector<String> available_drivers;
+#ifdef VULKAN_ENABLED
if (rendering_method == "forward_plus" || rendering_method == "mobile") {
available_drivers.push_back("vulkan");
- } else if (rendering_method == "gl_compatibility") {
+ }
+#endif
+#ifdef GLES3_ENABLED
+ if (rendering_method == "gl_compatibility") {
available_drivers.push_back("opengl3");
- } else {
+ }
+#endif
+ if (available_drivers.is_empty()) {
OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data());
goto error;
}
@@ -1775,10 +1799,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
PropertyInfo(Variant::INT, "physics/common/physics_ticks_per_second",
PROPERTY_HINT_RANGE, "1,1000,1"));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
- Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
- ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps",
+ Engine::get_singleton()->set_max_fps(GLOBAL_DEF("application/run/max_fps", 0));
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/max_fps",
PropertyInfo(Variant::INT,
- "debug/settings/fps/force_fps",
+ "application/run/max_fps",
PROPERTY_HINT_RANGE, "0,1000,1"));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
@@ -1807,7 +1831,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
PROPERTY_HINT_RANGE,
"0,33200,1,or_greater")); // No negative numbers
+ GLOBAL_DEF("display/window/ios/allow_high_refresh_rate", true);
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
+ GLOBAL_DEF("display/window/ios/hide_status_bar", true);
+ GLOBAL_DEF("display/window/ios/suppress_ui_gesture", true);
GLOBAL_DEF("input_devices/pointing/ios/touch_delay", 0.15);
ProjectSettings::get_singleton()->set_custom_property_info("input_devices/pointing/ios/touch_delay",
PropertyInfo(Variant::FLOAT,
@@ -1954,9 +1981,15 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
{
String display_driver = DisplayServer::get_create_function_name(display_driver_idx);
+ Vector2i *window_position = nullptr;
+ Vector2i position = init_custom_pos;
+ if (init_use_custom_pos) {
+ window_position = &position;
+ }
+
// rendering_driver now held in static global String in main and initialized in setup()
Error err;
- display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
+ display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err);
if (err != OK || display_server == nullptr) {
// We can't use this display server, try other ones as fallback.
// Skip headless (always last registered) because that's not what users
@@ -1965,7 +1998,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
if (i == display_driver_idx) {
continue; // Don't try the same twice.
}
- display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
+ display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, err);
if (err == OK && display_server != nullptr) {
break;
}
@@ -2127,7 +2160,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
} else {
// Create a 1×1 transparent image. This will effectively hide the splash image.
boot_logo.instantiate();
- boot_logo->create(1, 1, false, Image::FORMAT_RGBA8);
+ boot_logo->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
}
@@ -2313,11 +2346,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
"display/mouse_cursor/custom_image",
PROPERTY_HINT_FILE, "*.png,*.webp"));
- if (String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) {
+ if (String(GLOBAL_GET("display/mouse_cursor/custom_image")) != String()) {
Ref<Texture2D> cursor = ResourceLoader::load(
- ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image"));
+ GLOBAL_GET("display/mouse_cursor/custom_image"));
if (cursor.is_valid()) {
- Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot");
+ Vector2 hotspot = GLOBAL_GET("display/mouse_cursor/custom_image_hotspot");
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot);
}
}
@@ -2549,8 +2582,15 @@ bool Main::start() {
return false;
}
+ if (dump_gdnative_interface) {
+ GDNativeInterfaceDump::generate_gdnative_interface_file("gdnative_interface.h");
+ }
+
if (dump_extension_api) {
NativeExtensionAPIDump::generate_extension_json_file("extension_api.json");
+ }
+
+ if (dump_gdnative_interface || dump_extension_api) {
return false;
}
@@ -2799,7 +2839,7 @@ bool Main::start() {
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ String appname = GLOBAL_GET("application/config/name");
appname = TranslationServer::get_singleton()->translate(appname);
#ifdef DEBUG_ENABLED
// Append a suffix to the window title to denote that the project is running
diff --git a/methods.py b/methods.py
index 7feffb2848..f4afead9f4 100644
--- a/methods.py
+++ b/methods.py
@@ -7,15 +7,6 @@ from collections import OrderedDict
from collections.abc import Mapping
from typing import Iterator
-# We need to define our own `Action` method to control the verbosity of output
-# and whenever we need to run those commands in a subprocess on some platforms.
-from SCons import Node
-from SCons.Script import Action
-from SCons.Script import ARGUMENTS
-from SCons.Script import Glob
-from SCons.Variables.BoolVariable import _text2bool
-from platform_methods import run_in_subprocess
-
def add_source_files(self, sources, files):
# Convert string to list of absolute paths (including expanding wildcard)
@@ -220,6 +211,9 @@ def get_cmdline_bool(option, default):
"""We use `ARGUMENTS.get()` to check if options were manually overridden on the command line,
and SCons' _text2bool helper to convert them to booleans, otherwise they're handled as strings.
"""
+ from SCons.Script import ARGUMENTS
+ from SCons.Variables.BoolVariable import _text2bool
+
cmdline_val = ARGUMENTS.get(option)
if cmdline_val is not None:
return _text2bool(cmdline_val)
@@ -703,6 +697,9 @@ def generate_cpp_hint_file(filename):
def glob_recursive(pattern, node="."):
+ from SCons import Node
+ from SCons.Script import Glob
+
results = []
for f in Glob(str(node) + "/*", source=True):
if type(f) is Node.FS.Dir:
@@ -742,7 +739,7 @@ def generate_vs_project(env, num_jobs):
PLATFORMS = ["Win32", "x64"]
PLATFORM_IDS = ["x86_32", "x86_64"]
CONFIGURATIONS = ["editor", "template_release", "template_debug"]
- DEV_SUFFIX = ["", ".dev"]
+ DEV_SUFFIX = ".dev" if env["dev_build"] else ""
@staticmethod
def for_every_variant(value):
@@ -777,10 +774,9 @@ def generate_vs_project(env, num_jobs):
for platform in ModuleConfigs.PLATFORMS
]
self.arg_dict["runfile"] += [
- f'bin\\godot.windows.{config}{dev}.{plat_id}{f".{name}" if name else ""}.exe'
+ f'bin\\godot.windows.{config}{ModuleConfigs.DEV_SUFFIX}{".double" if env["float"] == "64" else ""}.{plat_id}{f".{name}" if name else ""}.exe'
for config in ModuleConfigs.CONFIGURATIONS
for plat_id in ModuleConfigs.PLATFORM_IDS
- for dev in ModuleConfigs.DEV_SUFFIX
]
self.arg_dict["cpppaths"] += ModuleConfigs.for_every_variant(env["CPPPATH"] + [includes])
self.arg_dict["cppdefines"] += ModuleConfigs.for_every_variant(env["CPPDEFINES"] + defines)
@@ -815,12 +811,18 @@ def generate_vs_project(env, num_jobs):
if env["dev_build"]:
common_build_postfix.append("dev_build=yes")
- if env["tests"]:
+ if env["dev_mode"]:
+ common_build_postfix.append("dev_mode=yes")
+
+ elif env["tests"]:
common_build_postfix.append("tests=yes")
if env["custom_modules"]:
common_build_postfix.append("custom_modules=%s" % env["custom_modules"])
+ if env["float"] == "64":
+ common_build_postfix.append("float=64")
+
result = " ^& ".join(common_build_prefix + [" ".join([commands] + common_build_postfix)])
return result
@@ -908,6 +910,9 @@ def CommandNoCache(env, target, sources, command, **args):
def Run(env, function, short_message, subprocess=True):
+ from SCons.Script import Action
+ from platform_methods import run_in_subprocess
+
output_print = short_message if not env["verbose"] else ""
if not subprocess:
return Action(function, output_print)
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html
index c9f3c2cc0d..93afbf085d 100644
--- a/misc/dist/html/editor.html
+++ b/misc/dist/html/editor.html
@@ -1,752 +1,757 @@
<!DOCTYPE html>
-<html xmlns="https://www.w3.org/1999/xhtml" lang="en">
-<head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" />
- <meta name="author" content="Godot Engine" />
- <meta name="description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
- <meta name="mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="application-name" content="Godot" />
- <meta name="apple-mobile-web-app-title" content="Godot" />
- <meta name="theme-color" content="#202531" />
- <meta name="msapplication-navbutton-color" content="#202531" />
- <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
- <meta name="msapplication-starturl" content="/latest" />
- <meta property="og:site_name" content="Godot Engine Web Editor" />
- <meta property="og:url" name="twitter:url" content="https://editor.godotengine.org/releases/latest/" />
- <meta property="og:title" name="twitter:title" content="Free and open source 2D and 3D game engine" />
- <meta property="og:description" name="twitter:description" content="Use the Godot Engine editor directly in your web browser, without having to install anything." />
- <meta property="og:image" name="twitter:image" content="https://godotengine.org/themes/godotengine/assets/og_image.png" />
- <meta property="og:type" content="website" />
- <meta name="twitter:card" content="summary" />
- <link id="-gd-engine-icon" rel="icon" type="image/png" href="favicon.png" />
- <link rel="apple-touch-icon" type="image/png" href="favicon.png" />
- <link rel="manifest" href="manifest.json" />
- <title>Godot Engine Web Editor (@GODOT_VERSION@)</title>
- <style>
- *:focus {
- /* More visible outline for better keyboard navigation. */
- outline: 0.125rem solid hsl(220, 100%, 62.5%);
- /* Make the outline always appear above other elements. */
- /* Otherwise, one of its sides can be hidden by tabs in the Download and More layouts. */
- position: relative;
- }
-
- body {
- touch-action: none;
- font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- margin: 0;
- border: 0 none;
- padding: 0;
- text-align: center;
- background-color: #333b4f;
- overflow: hidden;
- }
-
- a {
- color: hsl(205, 100%, 75%);
- text-decoration-color: hsla(205, 100%, 75%, 0.3);
- text-decoration-thickness: 0.125rem;
- }
-
- a:hover {
- filter: brightness(117.5%);
- }
-
- a:active {
- filter: brightness(82.5%);
- }
-
- .welcome-modal {
- display: none;
- position: fixed;
- z-index: 1;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- background-color: hsla(0, 0%, 0%, 0.5);
- text-align: left;
- }
-
- .welcome-modal-title {
- text-align: center;
- }
-
- .welcome-modal-content {
- background-color: #333b4f;
- box-shadow: 0 0.25rem 0.25rem hsla(0, 0%, 0%, 0.5);
- line-height: 1.5;
- max-width: 38rem;
- margin: 4rem auto 0 auto;
- color: white;
- border-radius: 0.5rem;
- padding: 1rem 1rem 2rem 1rem;
- }
-
- #tabs-buttons {
- /* Match the default background color of the editor window for a seamless appearance. */
- background-color: #202531;
- }
-
- #tab-game {
- /* Use a pure black background to better distinguish the running project */
- /* from the editor window, and to use a more neutral background color (no tint). */
- background-color: black;
- /* Make the background span the entire page height. */
- min-height: 100vh;
- }
-
- #canvas, #gameCanvas {
- display: block;
- margin: 0;
- color: white;
- }
-
- /* Don't show distracting focus outlines for the main tabs' contents. */
- #tab-editor canvas:focus,
- #tab-game canvas:focus,
- #canvas:focus,
- #gameCanvas:focus {
- outline: none;
- }
-
- .godot {
- color: #e0e0e0;
- background-color: #3b3943;
- background-image: linear-gradient(to bottom, #403e48, #35333c);
- border: 1px solid #45434e;
- box-shadow: 0 0 1px 1px #2f2d35;
- }
-
- .btn {
- appearance: none;
- color: #e0e0e0;
- background-color: #262c3b;
- border: 1px solid #202531;
- padding: 0.5rem 1rem;
- margin: 0 0.5rem;
- }
-
- .btn:not(:disabled):hover {
- color: #e0e1e5;
- border-color: #666c7b;
- }
-
- .btn:active {
- border-color: #699ce8;
- color: #699ce8;
- }
-
- .btn:disabled {
- color: #aaa;
- border-color: #242937;
- }
-
- .btn.tab-btn {
- padding: 0.3rem 1rem;
- }
-
- .btn.close-btn {
- padding: 0.3rem 1rem;
- margin-left: -0.75rem;
- font-weight: 700;
- }
-
-
- /* Status display
- * ============== */
-
- #status {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- /* don't consume click events - make children visible explicitly */
- visibility: hidden;
- }
-
- #status-progress {
- width: 366px;
- height: 7px;
- background-color: #38363A;
- border: 1px solid #444246;
- padding: 1px;
- box-shadow: 0 0 2px 1px #1B1C22;
- border-radius: 2px;
- visibility: visible;
- }
-
- @media only screen and (orientation:portrait) {
- #status-progress {
- width: 61.8%;
- }
- }
-
- #status-progress-inner {
- height: 100%;
- width: 0;
- box-sizing: border-box;
- transition: width 0.5s linear;
- background-color: #202020;
- border: 1px solid #222223;
- box-shadow: 0 0 1px 1px #27282E;
- border-radius: 3px;
- }
-
- #status-indeterminate {
- visibility: visible;
- position: relative;
- }
-
- #status-indeterminate > div {
- width: 4.5px;
- height: 0;
- border-style: solid;
- border-width: 9px 3px 0 3px;
- border-color: #2b2b2b transparent transparent transparent;
- transform-origin: center 21px;
- position: absolute;
- }
-
- #status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
- #status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
- #status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
- #status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
- #status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
- #status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
- #status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
- #status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
-
- #status-notice {
- margin: 0 100px;
- line-height: 1.3;
- visibility: visible;
- padding: 4px 6px;
- visibility: visible;
- }
- </style>
-</head>
-<body>
- <div
- id="welcome-modal"
- class="welcome-modal"
- role="dialog"
- aria-labelledby="welcome-modal-title"
- aria-describedby="welcome-modal-description"
- onclick="if (event.target === this) closeWelcomeModal(false)"
- >
- <div class="welcome-modal-content">
- <h2 id="welcome-modal-title" class="welcome-modal-title">Important - Please read before continuing</h2>
- <div id="welcome-modal-description">
- <p>
- The Godot Web Editor has some limitations compared to the native version.
- Its main focus is education and experimentation;
- <strong>it is not recommended for production</strong>.
- </p>
- <p>
- Refer to the
- <a
- href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html"
- target="_blank"
- rel="noopener"
- >Web editor documentation</a> for usage instructions and limitations.
- </p>
- </div>
- <div id="welcome-modal-missing-description" style="display: none">
- <p>
- <strong>The following features required by the Godot Web Editor are missing:</strong>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
+ <meta name="author" content="Godot Engine">
+ <meta name="description" content="Use the Godot Engine editor directly in your web browser, without having to install anything.">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+ <meta name="application-name" content="Godot">
+ <meta name="apple-mobile-web-app-title" content="Godot">
+ <meta name="theme-color" content="#202531">
+ <meta name="msapplication-navbutton-color" content="#202531">
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
+ <meta name="msapplication-starturl" content="/latest">
+ <meta property="og:site_name" content="Godot Engine Web Editor">
+ <meta property="og:url" name="twitter:url" content="https://editor.godotengine.org/releases/latest/">
+ <meta property="og:title" name="twitter:title" content="Free and open source 2D and 3D game engine">
+ <meta property="og:description" name="twitter:description" content="Use the Godot Engine editor directly in your web browser, without having to install anything.">
+ <meta property="og:image" name="twitter:image" content="https://godotengine.org/themes/godotengine/assets/og_image.png">
+ <meta property="og:type" content="website">
+ <meta name="twitter:card" content="summary">
+ <link id="-gd-engine-icon" rel="icon" type="image/png" href="favicon.png">
+ <link rel="apple-touch-icon" type="image/png" href="favicon.png">
+ <link rel="manifest" href="manifest.json">
+ <title>Godot Engine Web Editor (@GODOT_VERSION@)</title>
+ <style>
+*:focus {
+ /* More visible outline for better keyboard navigation. */
+ outline: 0.125rem solid hsl(220, 100%, 62.5%);
+ /* Make the outline always appear above other elements. */
+ /* Otherwise, one of its sides can be hidden by tabs in the Download and More layouts. */
+ position: relative;
+}
+
+body {
+ touch-action: none;
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 0;
+ border: 0 none;
+ padding: 0;
+ text-align: center;
+ background-color: #333b4f;
+ overflow: hidden;
+}
+
+a {
+ color: hsl(205, 100%, 75%);
+ text-decoration-color: hsla(205, 100%, 75%, 0.3);
+ text-decoration-thickness: 0.125rem;
+}
+
+a:hover {
+ filter: brightness(117.5%);
+}
+
+a:active {
+ filter: brightness(82.5%);
+}
+
+.welcome-modal {
+ display: none;
+ position: fixed;
+ z-index: 1;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ background-color: hsla(0, 0%, 0%, 0.5);
+ text-align: left;
+}
+
+.welcome-modal-title {
+ text-align: center;
+}
+
+.welcome-modal-content {
+ background-color: #333b4f;
+ box-shadow: 0 0.25rem 0.25rem hsla(0, 0%, 0%, 0.5);
+ line-height: 1.5;
+ max-width: 38rem;
+ margin: 4rem auto 0 auto;
+ color: white;
+ border-radius: 0.5rem;
+ padding: 1rem 1rem 2rem 1rem;
+}
+
+#tabs-buttons {
+ /* Match the default background color of the editor window for a seamless appearance. */
+ background-color: #202531;
+}
+
+#tab-game {
+ /* Use a pure black background to better distinguish the running project */
+ /* from the editor window, and to use a more neutral background color (no tint). */
+ background-color: black;
+ /* Make the background span the entire page height. */
+ min-height: 100vh;
+}
+
+#canvas, #gameCanvas {
+ display: block;
+ margin: 0;
+ color: white;
+}
+
+/* Don't show distracting focus outlines for the main tabs' contents. */
+#tab-editor canvas:focus,
+#tab-game canvas:focus,
+#canvas:focus,
+#gameCanvas:focus {
+ outline: none;
+}
+
+.godot {
+ color: #e0e0e0;
+ background-color: #3b3943;
+ background-image: linear-gradient(to bottom, #403e48, #35333c);
+ border: 1px solid #45434e;
+ box-shadow: 0 0 1px 1px #2f2d35;
+}
+
+.btn {
+ appearance: none;
+ color: #e0e0e0;
+ background-color: #262c3b;
+ border: 1px solid #202531;
+ padding: 0.5rem 1rem;
+ margin: 0 0.5rem;
+}
+
+.btn:not(:disabled):hover {
+ color: #e0e1e5;
+ border-color: #666c7b;
+}
+
+.btn:active {
+ border-color: #699ce8;
+ color: #699ce8;
+}
+
+.btn:disabled {
+ color: #aaa;
+ border-color: #242937;
+}
+
+.btn.tab-btn {
+ padding: 0.3rem 1rem;
+}
+
+.btn.close-btn {
+ padding: 0.3rem 1rem;
+ margin-left: -0.75rem;
+ font-weight: 700;
+}
+
+/* Status display */
+
+#status {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ /* don't consume click events - make children visible explicitly */
+ visibility: hidden;
+}
+
+#status-progress {
+ width: 366px;
+ height: 7px;
+ background-color: #38363A;
+ border: 1px solid #444246;
+ padding: 1px;
+ box-shadow: 0 0 2px 1px #1B1C22;
+ border-radius: 2px;
+ visibility: visible;
+}
+
+@media only screen and (orientation:portrait) {
+ #status-progress {
+ width: 61.8%;
+ }
+}
+
+#status-progress-inner {
+ height: 100%;
+ width: 0;
+ box-sizing: border-box;
+ transition: width 0.5s linear;
+ background-color: #202020;
+ border: 1px solid #222223;
+ box-shadow: 0 0 1px 1px #27282E;
+ border-radius: 3px;
+}
+
+#status-indeterminate {
+ visibility: visible;
+ position: relative;
+}
+
+#status-indeterminate > div {
+ width: 4.5px;
+ height: 0;
+ border-style: solid;
+ border-width: 9px 3px 0 3px;
+ border-color: #2b2b2b transparent transparent transparent;
+ transform-origin: center 21px;
+ position: absolute;
+}
+
+#status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
+#status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
+#status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
+#status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
+#status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
+#status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
+#status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
+#status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
+
+#status-notice {
+ margin: 0 100px;
+ line-height: 1.3;
+ visibility: visible;
+ padding: 4px 6px;
+ visibility: visible;
+}
+ </style>
+ </head>
+ <body>
+ <div
+ id="welcome-modal"
+ class="welcome-modal"
+ role="dialog"
+ aria-labelledby="welcome-modal-title"
+ aria-describedby="welcome-modal-description"
+ onclick="if (event.target === this) closeWelcomeModal(false)"
+ >
+ <div class="welcome-modal-content">
+ <h2 id="welcome-modal-title" class="welcome-modal-title">Important - Please read before continuing</h2>
+ <div id="welcome-modal-description">
+ <p>
+ The Godot Web Editor has some limitations compared to the native version.
+ Its main focus is education and experimentation;
+ <strong>it is not recommended for production</strong>.
+ </p>
+ <p>
+ Refer to the
+ <a
+ href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html"
+ target="_blank"
+ rel="noopener"
+ >Web editor documentation</a> for usage instructions and limitations.
+ </p>
+ </div>
+ <div id="welcome-modal-missing-description" style="display: none">
+ <p>
+ <strong>The following features required by the Godot Web Editor are missing:</strong>
+ </p>
<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"
- target="_blank"
- rel="noopener"
- >Exporting for the Web</a> for more information.
- </p>
- </div>
- <div style="text-align: center">
- <button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
- OK, don't show again
- </button>
+ <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"
+ target="_blank"
+ rel="noopener"
+ >Exporting for the Web</a> for more information.
+ </p>
+ </div>
+ <div style="text-align: center">
+ <button id="welcome-modal-dismiss" class="btn" type="button" onclick="closeWelcomeModal(true)" style="margin-top: 1rem">
+ OK, don't show again
+ </button>
+ </div>
</div>
</div>
- </div>
- <div id="tabs-buttons">
- <button id="btn-tab-loader" class="btn tab-btn" onclick="showTab('loader')">Loader</button>
- <button id="btn-tab-editor" class="btn tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button>
- <button id="btn-close-editor" class="btn close-btn" disabled="disabled" onclick="closeEditor()">×</button>
- <button id="btn-tab-game" class="btn tab-btn" disabled="disabled" onclick="showTab('game')">Game</button>
- <button id="btn-close-game" class="btn close-btn" disabled="disabled" onclick="closeGame()">×</button>
- <button id="btn-tab-update" class="btn tab-btn" style="display: none;">Update</button>
- </div>
- <div id="tabs">
- <div id="tab-loader">
- <div style="color: #e0e0e0;" id="persistence">
- <br />
- <img src="logo.svg" alt="Godot Engine logo" width="1024" height="414" style="width: auto; height: auto; max-width: min(85%, 50vh); max-height: 250px" />
- <br />
- @GODOT_VERSION@
- <br />
- <a href="releases/">Need an old version?</a>
- <br />
- <br />
- <br />
- <label for="videoMode" style="margin-right: 1rem">Video driver:</label>
- <select id="videoMode">
- <option value="" selected="selected">Auto</option>
- <option value="opengl3">WebGL 2</option>
- </select>
- <br />
- <br />
- <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label> <input id="zip-file" type="file" name="files" style="margin-bottom: 1rem"/>
- <br />
-<a href="demo.zip">(Try this for example)</a>
- <br />
- <br />
- <button id="startButton" class="btn" style="margin-bottom: 4rem; font-weight: 700">Start Godot editor</button>
- <br />
- <button class="btn" onclick="clearPersistence()" style="margin-bottom: 1.5rem">Clear persistent data</button>
- <br />
- <a href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html">Web editor documentation</a>
- </div>
- </div>
- <div id="tab-editor" style="display: none;">
- <canvas id="editor-canvas" tabindex="1">
- HTML5 canvas appears to be unsupported in the current browser.<br />
- Please try updating or use a different browser.
- </canvas>
- </div>
- <div id="tab-game" style="display: none;">
- <canvas id="game-canvas" tabindex="2">
- HTML5 canvas appears to be unsupported in the current browser.<br />
- Please try updating or use a different browser.
- </canvas>
+ <div id="tabs-buttons">
+ <button id="btn-tab-loader" class="btn tab-btn" onclick="showTab('loader')">Loader</button>
+ <button id="btn-tab-editor" class="btn tab-btn" disabled="disabled" onclick="showTab('editor')">Editor</button>
+ <button id="btn-close-editor" class="btn close-btn" disabled="disabled" onclick="closeEditor()">×</button>
+ <button id="btn-tab-game" class="btn tab-btn" disabled="disabled" onclick="showTab('game')">Game</button>
+ <button id="btn-close-game" class="btn close-btn" disabled="disabled" onclick="closeGame()">×</button>
+ <button id="btn-tab-update" class="btn tab-btn" style="display: none;">Update</button>
</div>
- <div id="tab-status" style="display: none;">
- <div id="status-progress" style="display: none;" oncontextmenu="event.preventDefault();"><div id="status-progress-inner"></div></div>
- <div id="status-indeterminate" style="display: none;" oncontextmenu="event.preventDefault();">
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
+ <div id="tabs">
+ <div id="tab-loader">
+ <div style="color: #e0e0e0;" id="persistence">
+ <br >
+ <img src="logo.svg" alt="Godot Engine logo" width="1024" height="414" style="width: auto; height: auto; max-width: min(85%, 50vh); max-height: 250px">
+ <br >
+ @GODOT_VERSION@
+ <br >
+ <a href="releases/">Need an old version?</a>
+ <br >
+ <br >
+ <br >
+ <label for="videoMode" style="margin-right: 1rem">Video driver:</label>
+ <select id="videoMode">
+ <option value="" selected="selected">Auto</option>
+ <option value="opengl3">WebGL 2</option>
+ </select>
+ <br >
+ <br >
+ <label for="zip-file" style="margin-right: 1rem">Preload project ZIP:</label>
+ <input id="zip-file" type="file" name="files" style="margin-bottom: 1rem">
+ <br >
+ <a href="demo.zip">(Try this for example)</a>
+ <br >
+ <br >
+ <button id="startButton" class="btn" style="margin-bottom: 4rem; font-weight: 700">Start Godot editor</button>
+ <br >
+ <button class="btn" onclick="clearPersistence()" style="margin-bottom: 1.5rem">Clear persistent data</button>
+ <br >
+ <a href="https://docs.godotengine.org/en/latest/tutorials/editor/using_the_web_editor.html">Web editor documentation</a>
+ </div>
+ </div>
+ <div id="tab-editor" style="display: none;">
+ <canvas id="editor-canvas" tabindex="1">
+ HTML5 canvas appears to be unsupported in the current browser.<br >
+ Please try updating or use a different browser.
+ </canvas>
+ </div>
+ <div id="tab-game" style="display: none;">
+ <canvas id="game-canvas" tabindex="2">
+ HTML5 canvas appears to be unsupported in the current browser.<br >
+ Please try updating or use a different browser.
+ </canvas>
+ </div>
+ <div id="tab-status" style="display: none;">
+ <div id="status-progress" style="display: none;" oncontextmenu="event.preventDefault();">
+ <div id="status-progress-inner"></div>
+ </div>
+ <div id="status-indeterminate" style="display: none;" oncontextmenu="event.preventDefault();">
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ </div>
+ <div id="status-notice" class="godot" style="display: none;"></div>
</div>
- <div id="status-notice" class="godot" style="display: none;"></div>
</div>
- </div>
- <script>//<![CDATA[
- window.addEventListener("load", () => {
- function notifyUpdate(sw) {
- const btn = document.getElementById("btn-tab-update");
- btn.onclick = function () {
- if (!window.confirm("Are you sure you want to update?\nClicking \"OK\" will reload all active instances!")) {
- return;
- }
- sw.postMessage("update");
- btn.innerHTML = "Updating...";
- btn.disabled = true;
- };
- btn.style.display = "";
- }
- if ("serviceWorker" in navigator) {
- navigator.serviceWorker.register("service.worker.js").then(function (reg) {
- if (reg.waiting) {
- notifyUpdate(reg.waiting);
- }
- reg.addEventListener("updatefound", function () {
- const update = reg.installing;
- update.addEventListener("statechange", function () {
- if (update.state === "installed") {
- // It's a new install, claim and perform aggressive caching.
- if (!reg.active) {
- update.postMessage("claim");
- } else {
- notifyUpdate(update);
- }
- }
- });
- });
- });
- }
-
- 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-missing-description").style.display = "block";
- document.getElementById("welcome-modal-dismiss").style.display = "none";
- 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 (missing.length || localStorage.getItem("welcomeModalDismissed") !== 'true') {
- document.getElementById("welcome-modal").style.display = "block";
- document.getElementById("welcome-modal-dismiss").focus();
+ <script>
+window.addEventListener('load', () => {
+ function notifyUpdate(sw) {
+ const btn = document.getElementById('btn-tab-update');
+ btn.onclick = function () {
+ if (!window.confirm('Are you sure you want to update?\nClicking "OK" will reload all active instances!')) {
+ return;
}
- });
-
- function closeWelcomeModal(dontShowAgain) {
- document.getElementById("welcome-modal").style.display = "none";
- if (dontShowAgain) {
- localStorage.setItem("welcomeModalDismissed", 'true');
+ sw.postMessage('update');
+ btn.innerHTML = 'Updating...';
+ btn.disabled = true;
+ };
+ btn.style.display = '';
+ }
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('service.worker.js').then(function (reg) {
+ if (reg.waiting) {
+ notifyUpdate(reg.waiting);
}
- }
- //]]></script>
- <script src="godot.editor.js"></script>
- <script>//<![CDATA[
-
- var editor = null;
- var game = null;
- var setStatusMode;
- var setStatusNotice;
- var video_driver = "";
-
- function clearPersistence() {
- function deleteDB(path) {
- return new Promise(function(resolve, reject) {
- var req = indexedDB.deleteDatabase(path);
- req.onsuccess = function() {
- resolve();
- };
- req.onerror = function(err) {
- reject(err);
- };
- req.onblocked = function(err) {
- reject(err);
+ reg.addEventListener('updatefound', function () {
+ const update = reg.installing;
+ update.addEventListener('statechange', function () {
+ if (update.state === 'installed') {
+ // It's a new install, claim and perform aggressive caching.
+ if (!reg.active) {
+ update.postMessage('claim');
+ } else {
+ notifyUpdate(update);
+ }
}
-
});
- }
- if (!window.confirm("Are you sure you want to delete all the locally stored files?\nClicking \"OK\" will permanently remove your projects and editor settings!")) {
- return;
- }
- Promise.all([
- deleteDB("/home/web_user"),
- ]).then(function(results) {
- alert("Done.");
- }).catch(function (err) {
- alert("Error deleting local files. Please retry after reloading the page.");
});
- }
-
- function selectVideoMode() {
- var select = document.getElementById('videoMode');
- video_driver = select.selectedOptions[0].value;
- }
-
- var tabs = [
- document.getElementById('tab-loader'),
- document.getElementById('tab-editor'),
- document.getElementById('tab-game')
- ]
- function showTab(name) {
- tabs.forEach(function (elem) {
- if (elem.id == 'tab-' + name) {
- elem.style.display = 'block';
- if (name == 'editor' || name == 'game') {
- const canvas = document.getElementById(name + '-canvas');
- canvas.focus();
- }
- } else {
- elem.style.display = 'none';
- }
- });
- }
-
- function setButtonEnabled(id, enabled) {
- if (enabled) {
- document.getElementById(id).disabled = "";
- } else {
- document.getElementById(id).disabled = "disabled";
+ });
+ }
+
+ const missing = Engine.getMissingFeatures();
+ if (missing.length) {
+ // Display error dialog as threading support is required for the editor.
+ document.getElementById('startButton').disabled = 'disabled';
+ document.getElementById('welcome-modal-description').style.display = 'none';
+ document.getElementById('welcome-modal-missing-description').style.display = 'block';
+ document.getElementById('welcome-modal-dismiss').style.display = 'none';
+ 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 (missing.length || localStorage.getItem('welcomeModalDismissed') !== 'true') {
+ document.getElementById('welcome-modal').style.display = 'block';
+ document.getElementById('welcome-modal-dismiss').focus();
+ }
+});
+
+function closeWelcomeModal(dontShowAgain) { // eslint-disable-line no-unused-vars
+ document.getElementById('welcome-modal').style.display = 'none';
+ if (dontShowAgain) {
+ localStorage.setItem('welcomeModalDismissed', 'true');
+ }
+}
+ </script>
+ <script src="godot.editor.js"></script>
+ <script>
+let editor = null;
+let game = null;
+let setStatusMode;
+let setStatusNotice;
+let video_driver = '';
+
+function clearPersistence() { // eslint-disable-line no-unused-vars
+ function deleteDB(path) {
+ return new Promise(function (resolve, reject) {
+ const req = indexedDB.deleteDatabase(path);
+ req.onsuccess = function () {
+ resolve();
+ };
+ req.onerror = function (err) {
+ reject(err);
+ };
+ req.onblocked = function (err) {
+ reject(err);
+ };
+ });
+ }
+ if (!window.confirm('Are you sure you want to delete all the locally stored files?\nClicking "OK" will permanently remove your projects and editor settings!')) {
+ return;
+ }
+ Promise.all([
+ deleteDB('/home/web_user'),
+ ]).then(function (results) {
+ alert('Done.');
+ }).catch(function (err) {
+ alert('Error deleting local files. Please retry after reloading the page.');
+ });
+}
+
+function selectVideoMode() {
+ const select = document.getElementById('videoMode');
+ video_driver = select.selectedOptions[0].value;
+}
+
+const tabs = [
+ document.getElementById('tab-loader'),
+ document.getElementById('tab-editor'),
+ document.getElementById('tab-game'),
+];
+function showTab(name) {
+ tabs.forEach(function (elem) {
+ if (elem.id === `tab-${name}`) {
+ elem.style.display = 'block';
+ if (name === 'editor' || name === 'game') {
+ const canvas = document.getElementById(`${name}-canvas`);
+ canvas.focus();
}
+ } else {
+ elem.style.display = 'none';
+ }
+ });
+}
+
+function setButtonEnabled(id, enabled) {
+ if (enabled) {
+ document.getElementById(id).disabled = '';
+ } else {
+ document.getElementById(id).disabled = 'disabled';
+ }
+}
+
+function setLoaderEnabled(enabled) {
+ setButtonEnabled('btn-tab-loader', enabled);
+ setButtonEnabled('btn-tab-editor', !enabled);
+ setButtonEnabled('btn-close-editor', !enabled);
+}
+
+function setGameTabEnabled(enabled) {
+ setButtonEnabled('btn-tab-game', enabled);
+ setButtonEnabled('btn-close-game', enabled);
+}
+
+function closeGame() {
+ if (game) {
+ game.requestQuit();
+ }
+}
+
+function closeEditor() { // eslint-disable-line no-unused-vars
+ closeGame();
+ if (editor) {
+ editor.requestQuit();
+ }
+}
+
+function startEditor(zip) {
+ const INDETERMINATE_STATUS_STEP_MS = 100;
+ const persistentPaths = ['/home/web_user'];
+
+ let editorCanvas = document.getElementById('editor-canvas');
+ let gameCanvas = document.getElementById('game-canvas');
+ const statusProgress = document.getElementById('status-progress');
+ const statusProgressInner = document.getElementById('status-progress-inner');
+ const statusIndeterminate = document.getElementById('status-indeterminate');
+ const statusNotice = document.getElementById('status-notice');
+ const headerDiv = document.getElementById('tabs-buttons');
+
+ let initializing = true;
+ let statusMode = 'hidden';
+
+ showTab('status');
+
+ let animationCallbacks = [];
+ function animate(time) {
+ animationCallbacks.forEach((callback) => callback(time));
+ requestAnimationFrame(animate);
+ }
+ requestAnimationFrame(animate);
+
+ let lastScale = 0;
+ let lastWidth = 0;
+ let lastHeight = 0;
+ function adjustCanvasDimensions() {
+ const scale = window.devicePixelRatio || 1;
+ const headerHeight = headerDiv.offsetHeight + 1;
+ const width = window.innerWidth;
+ const height = window.innerHeight - headerHeight;
+ if (lastScale !== scale || lastWidth !== width || lastHeight !== height) {
+ editorCanvas.width = width * scale;
+ editorCanvas.height = height * scale;
+ editorCanvas.style.width = `${width}px`;
+ editorCanvas.style.height = `${height}px`;
+ lastScale = scale;
+ lastWidth = width;
+ lastHeight = height;
+ }
+ }
+ animationCallbacks.push(adjustCanvasDimensions);
+ adjustCanvasDimensions();
+
+ function replaceCanvas(from) {
+ const out = document.createElement('canvas');
+ out.id = from.id;
+ out.tabIndex = from.tabIndex;
+ from.parentNode.replaceChild(out, from);
+ lastScale = 0;
+ return out;
+ }
+
+ function animateStatusIndeterminate(ms) {
+ const i = Math.floor((ms / INDETERMINATE_STATUS_STEP_MS) % 8);
+ if (statusIndeterminate.children[i].style.borderTopColor === '') {
+ Array.prototype.slice.call(statusIndeterminate.children).forEach((child) => {
+ child.style.borderTopColor = '';
+ });
+ statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
}
+ }
- function setLoaderEnabled(enabled) {
- setButtonEnabled('btn-tab-loader', enabled);
- setButtonEnabled('btn-tab-editor', !enabled);
- setButtonEnabled('btn-close-editor', !enabled);
- }
-
- function setGameTabEnabled(enabled) {
- setButtonEnabled('btn-tab-game', enabled);
- setButtonEnabled('btn-close-game', enabled);
+ setStatusMode = function (mode) {
+ if (statusMode === mode || !initializing) {
+ return;
}
-
- function closeGame() {
+ [statusProgress, statusIndeterminate, statusNotice].forEach((elem) => {
+ elem.style.display = 'none';
+ });
+ animationCallbacks = animationCallbacks.filter(function (value) {
+ return (value !== animateStatusIndeterminate);
+ });
+ switch (mode) {
+ case 'progress':
+ statusProgress.style.display = 'block';
+ break;
+ case 'indeterminate':
+ statusIndeterminate.style.display = 'block';
+ animationCallbacks.push(animateStatusIndeterminate);
+ break;
+ case 'notice':
+ statusNotice.style.display = 'block';
+ break;
+ case 'hidden':
+ break;
+ default:
+ throw new Error('Invalid status mode');
+ }
+ statusMode = mode;
+ };
+
+ setStatusNotice = function (text) {
+ while (statusNotice.lastChild) {
+ statusNotice.removeChild(statusNotice.lastChild);
+ }
+ const lines = text.split('\n');
+ lines.forEach((line) => {
+ statusNotice.appendChild(document.createTextNode(line));
+ statusNotice.appendChild(document.createElement('br'));
+ });
+ };
+
+ const gameConfig = {
+ 'persistentPaths': persistentPaths,
+ 'unloadAfterInit': false,
+ 'canvas': gameCanvas,
+ 'canvasResizePolicy': 1,
+ 'onExit': function () {
+ gameCanvas = replaceCanvas(gameCanvas);
+ setGameTabEnabled(false);
+ showTab('editor');
+ game = null;
+ },
+ };
+
+ let OnEditorExit = function () {
+ showTab('loader');
+ setLoaderEnabled(true);
+ };
+ function Execute(args) {
+ const is_editor = args.filter(function (v) {
+ return v === '--editor' || v === '-e';
+ }).length !== 0;
+ const is_project_manager = args.filter(function (v) {
+ return v === '--project-manager';
+ }).length !== 0;
+ const is_game = !is_editor && !is_project_manager;
+ if (video_driver) {
+ args.push('--rendering-driver', video_driver);
+ }
+
+ if (is_game) {
if (game) {
- game.requestQuit();
- }
- }
-
- function closeEditor() {
- closeGame();
- if (editor) {
- editor.requestQuit();
- }
- }
-
- function startEditor(zip) {
- const INDETERMINATE_STATUS_STEP_MS = 100;
- const persistentPaths = ['/home/web_user'];
-
- var editorCanvas = document.getElementById('editor-canvas');
- var gameCanvas = document.getElementById('game-canvas');
- var statusProgress = document.getElementById('status-progress');
- var statusProgressInner = document.getElementById('status-progress-inner');
- var statusIndeterminate = document.getElementById('status-indeterminate');
- var statusNotice = document.getElementById('status-notice');
- var headerDiv = document.getElementById('tabs-buttons');
-
- var initializing = true;
- var statusMode = 'hidden';
-
- showTab('status');
-
- var animationCallbacks = [];
- function animate(time) {
- animationCallbacks.forEach(callback => callback(time));
- requestAnimationFrame(animate);
- }
- requestAnimationFrame(animate);
-
- var lastScale = 0;
- var lastWidth = 0;
- var lastHeight = 0;
- function adjustCanvasDimensions() {
- var scale = window.devicePixelRatio || 1;
- var headerHeight = headerDiv.offsetHeight + 1;
- var width = window.innerWidth;
- var height = window.innerHeight - headerHeight;
- if (lastScale !== scale || lastWidth !== width || lastHeight !== height) {
- editorCanvas.width = width * scale;
- editorCanvas.height = height * scale;
- editorCanvas.style.width = width + "px";
- editorCanvas.style.height = height + "px";
- lastScale = scale;
- lastWidth = width;
- lastHeight = height;
- }
- }
- animationCallbacks.push(adjustCanvasDimensions);
- adjustCanvasDimensions();
-
- function replaceCanvas(from) {
- const out = document.createElement("canvas");
- out.id = from.id;
- out.tabIndex = from.tabIndex;
- from.parentNode.replaceChild(out, from);
- lastScale = 0;
- return out;
+ console.error('A game is already running. Close it first');
+ return;
}
-
- setStatusMode = function setStatusMode(mode) {
- if (statusMode === mode || !initializing)
- return;
- [statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
- elem.style.display = 'none';
- });
- animationCallbacks = animationCallbacks.filter(function(value) {
- return (value != animateStatusIndeterminate);
- });
- switch (mode) {
- case 'progress':
- statusProgress.style.display = 'block';
- break;
- case 'indeterminate':
- statusIndeterminate.style.display = 'block';
- animationCallbacks.push(animateStatusIndeterminate);
- break;
- case 'notice':
- statusNotice.style.display = 'block';
- break;
- case 'hidden':
- break;
- default:
- throw new Error('Invalid status mode');
- }
- statusMode = mode;
- };
-
- function animateStatusIndeterminate(ms) {
- var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
- if (statusIndeterminate.children[i].style.borderTopColor == '') {
- Array.prototype.slice.call(statusIndeterminate.children).forEach(child => {
- child.style.borderTopColor = '';
+ setGameTabEnabled(true);
+ game = new Engine(gameConfig);
+ showTab('game');
+ game.init().then(function () {
+ requestAnimationFrame(function () {
+ game.start({ 'args': args, 'canvas': gameCanvas }).then(function () {
+ gameCanvas.focus();
});
- statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
- }
- }
-
- setStatusNotice = function setStatusNotice(text) {
- while (statusNotice.lastChild) {
- statusNotice.removeChild(statusNotice.lastChild);
- }
- var lines = text.split('\n');
- lines.forEach((line) => {
- statusNotice.appendChild(document.createTextNode(line));
- statusNotice.appendChild(document.createElement('br'));
});
- };
-
- const gameConfig = {
- 'persistentPaths': persistentPaths,
- 'unloadAfterInit': false,
- 'canvas': gameCanvas,
- 'canvasResizePolicy': 1,
- 'onExit': function () {
- gameCanvas = replaceCanvas(gameCanvas);
- setGameTabEnabled(false);
- showTab('editor');
- game = null;
- },
- };
-
- var OnEditorExit = function () {
- showTab('loader');
+ });
+ } else { // New editor instances will be run in the same canvas. We want to wait for it to exit.
+ OnEditorExit = function (code) {
setLoaderEnabled(true);
- };
- function Execute(args) {
- const is_editor = args.filter(function(v) { return v == '--editor' || v == '-e' }).length != 0;
- const is_project_manager = args.filter(function(v) { return v == '--project-manager' }).length != 0;
- const is_game = !is_editor && !is_project_manager;
- if (video_driver) {
- args.push('--rendering-driver', video_driver);
- }
-
- if (is_game) {
- if (game) {
- console.error("A game is already running. Close it first");
- return;
- }
- setGameTabEnabled(true);
- game = new Engine(gameConfig);
- showTab('game');
- game.init().then(function() {
- requestAnimationFrame(function() {
- game.start({'args': args, 'canvas': gameCanvas}).then(function() {
- gameCanvas.focus();
- });
- });
+ setTimeout(function () {
+ editor.init().then(function () {
+ setLoaderEnabled(false);
+ OnEditorExit = function () {
+ showTab('loader');
+ setLoaderEnabled(true);
+ };
+ editor.start({ 'args': args, 'persistentDrops': is_project_manager, 'canvas': editorCanvas });
});
- } else { // New editor instances will be run in the same canvas. We want to wait for it to exit.
- OnEditorExit = function(code) {
- setLoaderEnabled(true);
- setTimeout(function() {
- editor.init().then(function() {
- setLoaderEnabled(false);
- OnEditorExit = function() {
- showTab('loader');
- setLoaderEnabled(true);
- };
- editor.start({'args': args, 'persistentDrops': is_project_manager, 'canvas': editorCanvas});
- });
- }, 0);
- OnEditorExit = null;
- };
- }
- }
-
- const editorConfig = {
- 'unloadAfterInit': false,
- 'onProgress': function progressFunction (current, total) {
- if (total > 0) {
- statusProgressInner.style.width = current/total * 100 + '%';
- setStatusMode('progress');
- if (current === total) {
- // wait for progress bar animation
- setTimeout(() => {
- setStatusMode('indeterminate');
- }, 100);
- }
- } else {
- setStatusMode('indeterminate');
- }
- },
- 'canvas': editorCanvas,
- 'canvasResizePolicy': 0,
- 'onExit': function() {
- editorCanvas = replaceCanvas(editorCanvas);
- if (OnEditorExit) {
- OnEditorExit();
- }
- },
- 'onExecute': Execute,
- 'persistentPaths': persistentPaths,
+ }, 0);
+ OnEditorExit = null;
};
- editor = new Engine(editorConfig);
-
- function displayFailureNotice(err) {
- var msg = err.message || err;
- console.error(msg);
- setStatusNotice(msg);
- setStatusMode('notice');
- initializing = false;
- };
-
- if (!Engine.isWebGLAvailable()) {
- displayFailureNotice('WebGL not available');
+ }
+ }
+
+ const editorConfig = {
+ 'unloadAfterInit': false,
+ 'onProgress': function progressFunction(current, total) {
+ if (total > 0) {
+ statusProgressInner.style.width = `${(current / total) * 100}%`;
+ setStatusMode('progress');
+ if (current === total) {
+ // wait for progress bar animation
+ setTimeout(() => {
+ setStatusMode('indeterminate');
+ }, 100);
+ }
} else {
setStatusMode('indeterminate');
- editor.init('godot.editor').then(function() {
- if (zip) {
- editor.copyToFS("/tmp/preload.zip", zip);
- }
- try {
- // Avoid user creating project in the persistent root folder.
- editor.copyToFS("/home/web_user/keep", new Uint8Array());
- } catch(e) {
- // File exists
- }
- selectVideoMode();
- showTab('editor');
- setLoaderEnabled(false);
- const args = ['--project-manager', '--single-window'];
- if (video_driver) {
- args.push('--rendering-driver', video_driver);
- }
- editor.start({'args': args, 'persistentDrops': true}).then(function() {
- setStatusMode('hidden');
- initializing = false;
- });
- }).catch(displayFailureNotice);
}
- };
- document.getElementById("startButton").onclick = function() {
- preloadZip(document.getElementById('zip-file')).then(function(zip) {
- startEditor(zip);
+ },
+ 'canvas': editorCanvas,
+ 'canvasResizePolicy': 0,
+ 'onExit': function () {
+ editorCanvas = replaceCanvas(editorCanvas);
+ if (OnEditorExit) {
+ OnEditorExit();
+ }
+ },
+ 'onExecute': Execute,
+ 'persistentPaths': persistentPaths,
+ };
+ editor = new Engine(editorConfig);
+
+ function displayFailureNotice(err) {
+ const msg = err.message || err;
+ console.error(msg);
+ setStatusNotice(msg);
+ setStatusMode('notice');
+ initializing = false;
+ }
+
+ if (!Engine.isWebGLAvailable()) {
+ displayFailureNotice('WebGL not available');
+ } else {
+ setStatusMode('indeterminate');
+ editor.init('godot.editor').then(function () {
+ if (zip) {
+ editor.copyToFS('/tmp/preload.zip', zip);
+ }
+ try {
+ // Avoid user creating project in the persistent root folder.
+ editor.copyToFS('/home/web_user/keep', new Uint8Array());
+ } catch (e) {
+ // File exists
+ }
+ selectVideoMode();
+ showTab('editor');
+ setLoaderEnabled(false);
+ const args = ['--project-manager', '--single-window'];
+ if (video_driver) {
+ args.push('--rendering-driver', video_driver);
+ }
+ editor.start({ 'args': args, 'persistentDrops': true }).then(function () {
+ setStatusMode('hidden');
+ initializing = false;
});
- }
-
- function preloadZip(target) {
- return new Promise(function(resolve, reject) {
- if (target.files.length > 0) {
- target.files[0].arrayBuffer().then(function(data) {
- resolve(data);
- });
- } else {
- resolve();
- }
+ }).catch(displayFailureNotice);
+ }
+}
+
+function preloadZip(target) {
+ return new Promise(function (resolve, reject) {
+ if (target.files.length > 0) {
+ target.files[0].arrayBuffer().then(function (data) {
+ resolve(data);
});
- }
- //]]></script>
-</body>
+ } else {
+ resolve();
+ }
+ });
+}
+
+document.getElementById('startButton').onclick = function () {
+ preloadZip(document.getElementById('zip-file')).then(function (zip) {
+ startEditor(zip);
+ });
+};
+ </script>
+ </body>
</html>
diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html
index d5b0050cfd..6ae3e5cc73 100644
--- a/misc/dist/html/full-size.html
+++ b/misc/dist/html/full-size.html
@@ -1,247 +1,245 @@
<!DOCTYPE html>
-<html xmlns='https://www.w3.org/1999/xhtml' lang='' xml:lang=''>
-<head>
- <meta charset='utf-8' />
- <meta name='viewport' content='width=device-width, user-scalable=no' />
- <title>$GODOT_PROJECT_NAME</title>
- <style type='text/css'>
-
- body {
- touch-action: none;
- margin: 0;
- border: 0 none;
- padding: 0;
- text-align: center;
- background-color: black;
- }
-
- #canvas {
- display: block;
- margin: 0;
- color: white;
- }
-
- #canvas:focus {
- outline: none;
- }
-
- .godot {
- font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
- color: #e0e0e0;
- background-color: #3b3943;
- background-image: linear-gradient(to bottom, #403e48, #35333c);
- border: 1px solid #45434e;
- box-shadow: 0 0 1px 1px #2f2d35;
- }
-
-
- /* Status display
- * ============== */
-
- #status {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- /* don't consume click events - make children visible explicitly */
- visibility: hidden;
- }
-
- #status-progress {
- width: 366px;
- height: 7px;
- background-color: #38363A;
- border: 1px solid #444246;
- padding: 1px;
- box-shadow: 0 0 2px 1px #1B1C22;
- border-radius: 2px;
- visibility: visible;
- }
-
- @media only screen and (orientation:portrait) {
- #status-progress {
- width: 61.8%;
- }
- }
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, user-scalable=no">
+ <title>$GODOT_PROJECT_NAME</title>
+ <style>
+body {
+ touch-action: none;
+ margin: 0;
+ border: 0 none;
+ padding: 0;
+ text-align: center;
+ background-color: black;
+}
+
+#canvas {
+ display: block;
+ margin: 0;
+ color: white;
+}
+
+#canvas:focus {
+ outline: none;
+}
+
+.godot {
+ font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
+ color: #e0e0e0;
+ background-color: #3b3943;
+ background-image: linear-gradient(to bottom, #403e48, #35333c);
+ border: 1px solid #45434e;
+ box-shadow: 0 0 1px 1px #2f2d35;
+}
+
+/* Status display */
+
+#status {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ /* don't consume click events - make children visible explicitly */
+ visibility: hidden;
+}
+
+#status-progress {
+ width: 366px;
+ height: 7px;
+ background-color: #38363A;
+ border: 1px solid #444246;
+ padding: 1px;
+ box-shadow: 0 0 2px 1px #1B1C22;
+ border-radius: 2px;
+ visibility: visible;
+}
+
+@media only screen and (orientation:portrait) {
+ #status-progress {
+ width: 61.8%;
+ }
+}
+
+#status-progress-inner {
+ height: 100%;
+ width: 0;
+ box-sizing: border-box;
+ transition: width 0.5s linear;
+ background-color: #202020;
+ border: 1px solid #222223;
+ box-shadow: 0 0 1px 1px #27282E;
+ border-radius: 3px;
+}
+
+#status-indeterminate {
+ height: 42px;
+ visibility: visible;
+ position: relative;
+}
+
+#status-indeterminate > div {
+ width: 4.5px;
+ height: 0;
+ border-style: solid;
+ border-width: 9px 3px 0 3px;
+ border-color: #2b2b2b transparent transparent transparent;
+ transform-origin: center 21px;
+ position: absolute;
+}
+
+#status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
+#status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
+#status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
+#status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
+#status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
+#status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
+#status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
+#status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
+
+#status-notice {
+ margin: 0 100px;
+ line-height: 1.3;
+ visibility: visible;
+ padding: 4px 6px;
+ visibility: visible;
+}
+ </style>
+ $GODOT_HEAD_INCLUDE
+ </head>
+ <body>
+ <canvas id="canvas">
+ HTML5 canvas appears to be unsupported in the current browser.<br >
+ Please try updating or use a different browser.
+ </canvas>
+ <div id="status">
+ <div id="status-progress" style="display: none;" oncontextmenu="event.preventDefault();">
+ <div id ="status-progress-inner"></div>
+ </div>
+ <div id="status-indeterminate" style="display: none;" oncontextmenu="event.preventDefault();">
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ <div></div>
+ </div>
+ <div id="status-notice" class="godot" style="display: none;"></div>
+ </div>
- #status-progress-inner {
- height: 100%;
- width: 0;
- box-sizing: border-box;
- transition: width 0.5s linear;
- background-color: #202020;
- border: 1px solid #222223;
- box-shadow: 0 0 1px 1px #27282E;
- border-radius: 3px;
+ <script src="$GODOT_URL"></script>
+ <script>
+const GODOT_CONFIG = $GODOT_CONFIG;
+const engine = new Engine(GODOT_CONFIG);
+
+(function () {
+ const INDETERMINATE_STATUS_STEP_MS = 100;
+ const statusProgress = document.getElementById('status-progress');
+ const statusProgressInner = document.getElementById('status-progress-inner');
+ const statusIndeterminate = document.getElementById('status-indeterminate');
+ const statusNotice = document.getElementById('status-notice');
+
+ let initializing = true;
+ let statusMode = 'hidden';
+
+ let animationCallbacks = [];
+ function animate(time) {
+ animationCallbacks.forEach((callback) => callback(time));
+ requestAnimationFrame(animate);
+ }
+ requestAnimationFrame(animate);
+
+ function animateStatusIndeterminate(ms) {
+ const i = Math.floor((ms / INDETERMINATE_STATUS_STEP_MS) % 8);
+ if (statusIndeterminate.children[i].style.borderTopColor === '') {
+ Array.prototype.slice.call(statusIndeterminate.children).forEach((child) => {
+ child.style.borderTopColor = '';
+ });
+ statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
}
+ }
- #status-indeterminate {
- height: 42px;
- visibility: visible;
- position: relative;
+ function setStatusMode(mode) {
+ if (statusMode === mode || !initializing) {
+ return;
}
-
- #status-indeterminate > div {
- width: 4.5px;
- height: 0;
- border-style: solid;
- border-width: 9px 3px 0 3px;
- border-color: #2b2b2b transparent transparent transparent;
- transform-origin: center 21px;
- position: absolute;
+ [statusProgress, statusIndeterminate, statusNotice].forEach((elem) => {
+ elem.style.display = 'none';
+ });
+ animationCallbacks = animationCallbacks.filter(function (value) {
+ return (value !== animateStatusIndeterminate);
+ });
+ switch (mode) {
+ case 'progress':
+ statusProgress.style.display = 'block';
+ break;
+ case 'indeterminate':
+ statusIndeterminate.style.display = 'block';
+ animationCallbacks.push(animateStatusIndeterminate);
+ break;
+ case 'notice':
+ statusNotice.style.display = 'block';
+ break;
+ case 'hidden':
+ break;
+ default:
+ throw new Error('Invalid status mode');
}
+ statusMode = mode;
+ }
- #status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
- #status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
- #status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
- #status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
- #status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
- #status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
- #status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
- #status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
-
- #status-notice {
- margin: 0 100px;
- line-height: 1.3;
- visibility: visible;
- padding: 4px 6px;
- visibility: visible;
+ function setStatusNotice(text) {
+ while (statusNotice.lastChild) {
+ statusNotice.removeChild(statusNotice.lastChild);
}
- </style>
-$GODOT_HEAD_INCLUDE
-</head>
-<body>
- <canvas id='canvas'>
- HTML5 canvas appears to be unsupported in the current browser.<br />
- Please try updating or use a different browser.
- </canvas>
- <div id='status'>
- <div id='status-progress' style='display: none;' oncontextmenu='event.preventDefault();'><div id ='status-progress-inner'></div></div>
- <div id='status-indeterminate' style='display: none;' oncontextmenu='event.preventDefault();'>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- <div></div>
- </div>
- <div id='status-notice' class='godot' style='display: none;'></div>
- </div>
-
- <script type='text/javascript' src='$GODOT_URL'></script>
- <script type='text/javascript'>//<![CDATA[
-
- const GODOT_CONFIG = $GODOT_CONFIG;
- var engine = new Engine(GODOT_CONFIG);
-
- (function() {
- const INDETERMINATE_STATUS_STEP_MS = 100;
- var statusProgress = document.getElementById('status-progress');
- var statusProgressInner = document.getElementById('status-progress-inner');
- var statusIndeterminate = document.getElementById('status-indeterminate');
- var statusNotice = document.getElementById('status-notice');
-
- var initializing = true;
- var statusMode = 'hidden';
-
- var animationCallbacks = [];
- function animate(time) {
- animationCallbacks.forEach(callback => callback(time));
- requestAnimationFrame(animate);
- }
- requestAnimationFrame(animate);
-
- function setStatusMode(mode) {
-
- if (statusMode === mode || !initializing)
- return;
- [statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
- elem.style.display = 'none';
- });
- animationCallbacks = animationCallbacks.filter(function(value) {
- return (value != animateStatusIndeterminate);
- });
- switch (mode) {
- case 'progress':
- statusProgress.style.display = 'block';
- break;
- case 'indeterminate':
- statusIndeterminate.style.display = 'block';
- animationCallbacks.push(animateStatusIndeterminate);
- break;
- case 'notice':
- statusNotice.style.display = 'block';
- break;
- case 'hidden':
- break;
- default:
- throw new Error('Invalid status mode');
- }
- statusMode = mode;
- }
-
- function animateStatusIndeterminate(ms) {
- var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
- if (statusIndeterminate.children[i].style.borderTopColor == '') {
- Array.prototype.slice.call(statusIndeterminate.children).forEach(child => {
- child.style.borderTopColor = '';
- });
- statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
- }
- }
-
- function setStatusNotice(text) {
- while (statusNotice.lastChild) {
- statusNotice.removeChild(statusNotice.lastChild);
- }
- var lines = text.split('\n');
- lines.forEach((line) => {
- statusNotice.appendChild(document.createTextNode(line));
- statusNotice.appendChild(document.createElement('br'));
- });
- };
-
- function displayFailureNotice(err) {
- var msg = err.message || err;
- console.error(msg);
- setStatusNotice(msg);
- setStatusMode('notice');
- initializing = false;
- };
-
- 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({
- 'onProgress': function (current, total) {
- if (total > 0) {
- statusProgressInner.style.width = current/total * 100 + '%';
- setStatusMode('progress');
- if (current === total) {
- // wait for progress bar animation
- setTimeout(() => {
- setStatusMode('indeterminate');
- }, 500);
- }
- } else {
+ const lines = text.split('\n');
+ lines.forEach((line) => {
+ statusNotice.appendChild(document.createTextNode(line));
+ statusNotice.appendChild(document.createElement('br'));
+ });
+ }
+
+ function displayFailureNotice(err) {
+ const msg = err.message || err;
+ console.error(msg);
+ setStatusNotice(msg);
+ setStatusMode('notice');
+ initializing = false;
+ }
+
+ 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({
+ 'onProgress': function (current, total) {
+ if (total > 0) {
+ statusProgressInner.style.width = `${(current / total) * 100}%`;
+ setStatusMode('progress');
+ if (current === total) {
+ // wait for progress bar animation
+ setTimeout(() => {
setStatusMode('indeterminate');
- }
- },
- }).then(() => {
- setStatusMode('hidden');
- initializing = false;
- }, displayFailureNotice);
- }
- })();
- //]]></script>
-</body>
+ }, 500);
+ }
+ } else {
+ setStatusMode('indeterminate');
+ }
+ },
+ }).then(() => {
+ setStatusMode('hidden');
+ initializing = false;
+ }, displayFailureNotice);
+ }
+}());
+ </script>
+ </body>
</html>
diff --git a/misc/dist/html/offline-export.html b/misc/dist/html/offline-export.html
index 41ab42b04b..ae5298ae46 100644
--- a/misc/dist/html/offline-export.html
+++ b/misc/dist/html/offline-export.html
@@ -1,42 +1,41 @@
<!DOCTYPE html>
<html lang="en">
-<head>
- <meta charset="utf-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>You are offline</title>
- <style>
- html {
- background-color: #000000;
- color: #ffffff;
- }
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>You are offline</title>
+ <style>
+html {
+ background-color: #000000;
+ color: #ffffff;
+}
- body {
- font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- margin: 2rem;
- }
+body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 2rem;
+}
- p {
- margin-block: 1rem;
- }
+p {
+ margin-block: 1rem;
+}
- button {
- display: block;
- padding: 1rem 2rem;
- margin: 3rem auto 0;
- }
- </style>
-</head>
-<body>
- <h1>You are offline</h1>
- <p>This application requires an Internet connection to run for the first time.</p>
- <p>Press the button below to try reloading:</p>
- <button type="button">Reload</button>
-
- <script>
- document.querySelector("button").addEventListener("click", () => {
- window.location.reload();
- });
- </script>
-</body>
+button {
+ display: block;
+ padding: 1rem 2rem;
+ margin: 3rem auto 0;
+}
+ </style>
+ </head>
+ <body>
+ <h1>You are offline</h1>
+ <p>This application requires an Internet connection to run for the first time.</p>
+ <p>Press the button below to try reloading:</p>
+ <button type="button">Reload</button>
+ <script>
+document.querySelector('button').addEventListener('click', () => {
+ window.location.reload();
+});
+ </script>
+ </body>
</html>
diff --git a/misc/dist/html/offline.html b/misc/dist/html/offline.html
index 5cfc3362d9..123181e3e0 100644
--- a/misc/dist/html/offline.html
+++ b/misc/dist/html/offline.html
@@ -1,44 +1,44 @@
<!DOCTYPE html>
<html lang="en">
-<head>
- <meta charset="utf-8" />
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta name="theme-color" content="#202531" />
- <meta name="msapplication-navbutton-color" content="#202531" />
- <title>You are offline</title>
- <style>
- html {
- background-color: #333b4f;
- color: #e0e0e0;
- }
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="theme-color" content="#202531">
+ <meta name="msapplication-navbutton-color" content="#202531">
+ <title>You are offline</title>
+ <style>
+html {
+ background-color: #333b4f;
+ color: #e0e0e0;
+}
- body {
- font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- margin: 2rem;
- }
+body {
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ margin: 2rem;
+}
- p {
- margin-block: 1rem;
- }
+p {
+ margin-block: 1rem;
+}
- button {
- display: block;
- padding: 1rem 2rem;
- margin: 3rem auto 0;
- }
- </style>
-</head>
-<body>
- <h1>You are offline</h1>
- <p>This application requires an Internet connection to run for the first time.</p>
- <p>Press the button below to try reloading:</p>
- <button type="button">Reload</button>
+button {
+ display: block;
+ padding: 1rem 2rem;
+ margin: 3rem auto 0;
+}
+ </style>
+ </head>
+ <body>
+ <h1>You are offline</h1>
+ <p>This application requires an Internet connection to run for the first time.</p>
+ <p>Press the button below to try reloading:</p>
+ <button type="button">Reload</button>
- <script>
- document.querySelector("button").addEventListener("click", () => {
- window.location.reload();
- });
- </script>
-</body>
+ <script>
+document.querySelector('button').addEventListener('click', () => {
+ window.location.reload();
+});
+ </script>
+ </body>
</html>
diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
index e9d22f6b4d..b88dfae5b2 100644
--- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
+++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist
@@ -58,5 +58,6 @@
</array>
$additional_plist_content
$plist_launch_screen_name
+ <key>CADisableMinimumFrameDurationOnPhone</key><true/>
</dict>
</plist>
diff --git a/misc/dist/linux/godot.6 b/misc/dist/linux/godot.6
index 07e2a389a7..766be6d0a7 100644
--- a/misc/dist/linux/godot.6
+++ b/misc/dist/linux/godot.6
@@ -150,6 +150,12 @@ Disallow dumping the base types (used with \fB\-\-doctool\fR).
\fB\-\-build\-solutions\fR
Build the scripting solutions (e.g. for C# projects). Implies \-\-editor and requires a valid project to edit.
.TP
+\fB\-\-dump\-gdextension\-interface\fR
+Generate GDExtension header file 'gdnative_interface.h' in the current folder. This file is the base file required to implement a GDExtension.
+.TP
+\fB\-\-dump\-extension\-api\fR
+Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.
+.TP
\fB\-\-test\fR <test>
Run a unit test ('string', 'math', 'physics', 'physics_2d', 'render', 'oa_hash_map', 'gui', 'shaderlang', 'gd_tokenizer', 'gd_parser', 'gd_compiler', 'gd_bytecode', 'ordered_hash_map', 'astar').
.SH FILES
diff --git a/misc/dist/shell/_godot.zsh-completion b/misc/dist/shell/_godot.zsh-completion
index 2bc6fe9317..18b74115bf 100644
--- a/misc/dist/shell/_godot.zsh-completion
+++ b/misc/dist/shell/_godot.zsh-completion
@@ -84,5 +84,6 @@ _arguments \
'--doctool[dump the engine API reference to the given path in XML format, merging if existing files are found]:path to base Godot build directory (optional):_dirs' \
'--no-docbase[disallow dumping the base types (used with --doctool)]' \
'--build-solutions[build the scripting solutions (e.g. for C# projects)]' \
+ '--dump-gdextension-interface[generate GDExtension header file 'gdnative_interface.h' in the current folder. This file is the base file required to implement a GDExtension.]' \
'--dump-extension-api[generate JSON dump of the Godot API for GDExtension bindings named "extension_api.json" in the current folder]' \
'--test[run all unit tests; run with "--test --help" for more information]'
diff --git a/misc/dist/shell/godot.bash-completion b/misc/dist/shell/godot.bash-completion
index bc5fa600f5..871c8f8eac 100644
--- a/misc/dist/shell/godot.bash-completion
+++ b/misc/dist/shell/godot.bash-completion
@@ -86,6 +86,7 @@ _complete_godot_options() {
--doctool
--no-docbase
--build-solutions
+--dump-gdextension-interface
--dump-extension-api
--test
" -- "$1"))
diff --git a/misc/dist/shell/godot.fish b/misc/dist/shell/godot.fish
index 9ac692eace..9cbec8a4f6 100644
--- a/misc/dist/shell/godot.fish
+++ b/misc/dist/shell/godot.fish
@@ -106,5 +106,6 @@ complete -c godot -l validate-conversion-3to4 -d "Shows what elements will be re
complete -c godot -l doctool -d "Dump the engine API reference to the given path in XML format, merging if existing files are found" -r
complete -c godot -l no-docbase -d "Disallow dumping the base types (used with --doctool)"
complete -c godot -l build-solutions -d "Build the scripting solutions (e.g. for C# projects)"
+complete -c godot -l dump-gdextension-interface -d "Generate GDExtension header file 'gdnative_interface.h' in the current folder. This file is the base file required to implement a GDExtension"
complete -c godot -l dump-extension-api -d "Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder"
complete -c godot -l test -d "Run all unit tests; run with '--test --help' for more information" -x
diff --git a/misc/scripts/dotnet_format.sh b/misc/scripts/dotnet_format.sh
index 645737f419..cc34137a37 100755
--- a/misc/scripts/dotnet_format.sh
+++ b/misc/scripts/dotnet_format.sh
@@ -5,6 +5,13 @@
set -uo pipefail
+# Create dummy generated files.
+echo "<Project />" > modules/mono/SdkPackageVersions.props
+mkdir -p modules/mono/glue/GodotSharp/GodotSharp/Generated
+echo "<Project />" > modules/mono/glue/GodotSharp/GodotSharp/Generated/GeneratedIncludes.props
+mkdir -p modules/mono/glue/GodotSharp/GodotSharpEditor/Generated
+echo "<Project />" > modules/mono/glue/GodotSharp/GodotSharpEditor/Generated/GeneratedIncludes.props
+
# Loops through all C# projects tracked by Git.
git ls-files -- '*.csproj' \
':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' |
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index e80d453df7..155f7809b0 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -253,7 +253,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size
};
image.instantiate();
- image->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata);
+ image->set_data(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata);
return image;
}
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index cc21ed28e8..681b3e74bc 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -156,7 +156,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
if (p_color_buffer == nullptr || color_table_size == 0) { // regular pixels
- p_image->create(width, height, false, Image::FORMAT_RGBA8, data);
+ p_image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
} else { // data is in indexed format, extend it
@@ -194,7 +194,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
dest += 4;
}
- p_image->create(width, height, false, Image::FORMAT_RGBA8, extended_data);
+ p_image->set_data(width, height, false, Image::FORMAT_RGBA8, extended_data);
}
}
return err;
diff --git a/modules/camera/camera_macos.mm b/modules/camera/camera_macos.mm
index 0b9696a3e9..0e61dde8e9 100644
--- a/modules/camera/camera_macos.mm
+++ b/modules/camera/camera_macos.mm
@@ -158,7 +158,7 @@
memcpy(w, dataY, new_width * new_height);
img[0].instantiate();
- img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
+ img[0]->set_data(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
}
{
@@ -177,7 +177,7 @@
///TODO OpenGL doesn't support FORMAT_RG8, need to do some form of conversion
img[1].instantiate();
- img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
+ img[1]->set_data(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
}
// set our texture...
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 3932c2377f..461960ab26 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -92,13 +92,13 @@ uint32_t CSGShape3D::get_collision_mask() const {
void CSGShape3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t collision_layer = get_collision_layer();
+ uint32_t layer = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << (p_layer_number - 1);
+ layer |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << (p_layer_number - 1));
+ layer &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(collision_layer);
+ set_collision_layer(layer);
}
bool CSGShape3D::get_collision_layer_value(int p_layer_number) const {
@@ -690,7 +690,7 @@ CSGCombiner3D::CSGCombiner3D() {
/////////////////////
CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials) {
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
Vector<bool> invert;
invert.resize(p_vertices.size() / 3);
@@ -701,9 +701,9 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver
w[i] = flip_faces;
}
}
- brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert);
+ new_brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert);
- return brush;
+ return new_brush;
}
void CSGPrimitive3D::_bind_methods() {
@@ -742,7 +742,7 @@ CSGBrush *CSGMesh3D::_build_brush() {
Vector<bool> smooth;
Vector<Ref<Material>> materials;
Vector<Vector2> uvs;
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
for (int i = 0; i < mesh->get_surface_count(); i++) {
if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
@@ -776,8 +776,8 @@ CSGBrush *CSGMesh3D::_build_brush() {
}
Ref<Material> mat;
- if (material.is_valid()) {
- mat = material;
+ if (base_material.is_valid()) {
+ mat = base_material;
} else {
mat = mesh->surface_get_material(i);
}
@@ -933,12 +933,12 @@ Ref<Mesh> CSGMesh3D::get_mesh() {
CSGBrush *CSGSphere3D::_build_brush() {
// set our bounding box
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
int face_count = rings * radial_segments * 2 - radial_segments * 2;
bool invert_val = get_flip_faces();
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
Vector<Vector3> faces;
Vector<Vector2> uvs;
@@ -1019,7 +1019,7 @@ CSGBrush *CSGSphere3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
@@ -1036,7 +1036,7 @@ CSGBrush *CSGSphere3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
@@ -1048,9 +1048,9 @@ CSGBrush *CSGSphere3D::_build_brush() {
}
}
- brush->build_from_faces(faces, uvs, smooth, materials, invert);
+ new_brush->build_from_faces(faces, uvs, smooth, materials, invert);
- return brush;
+ return new_brush;
}
void CSGSphere3D::_bind_methods() {
@@ -1137,12 +1137,12 @@ CSGSphere3D::CSGSphere3D() {
CSGBrush *CSGBox3D::_build_brush() {
// set our bounding box
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
int face_count = 12; //it's a cube..
bool invert_val = get_flip_faces();
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
Vector<Vector3> faces;
Vector<Vector2> uvs;
@@ -1204,7 +1204,7 @@ CSGBrush *CSGBox3D::_build_brush() {
smoothw[face] = false;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
//face 2
@@ -1218,7 +1218,7 @@ CSGBrush *CSGBox3D::_build_brush() {
smoothw[face] = false;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
@@ -1229,9 +1229,9 @@ CSGBrush *CSGBox3D::_build_brush() {
}
}
- brush->build_from_faces(faces, uvs, smooth, materials, invert);
+ new_brush->build_from_faces(faces, uvs, smooth, materials, invert);
- return brush;
+ return new_brush;
}
void CSGBox3D::_bind_methods() {
@@ -1270,12 +1270,12 @@ Ref<Material> CSGBox3D::get_material() const {
CSGBrush *CSGCylinder3D::_build_brush() {
// set our bounding box
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
int face_count = sides * (cone ? 1 : 2) + sides + (cone ? 0 : sides);
bool invert_val = get_flip_faces();
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
Vector<Vector3> faces;
Vector<Vector2> uvs;
@@ -1312,14 +1312,14 @@ CSGBrush *CSGCylinder3D::_build_brush() {
float ang = inc * Math_TAU;
float ang_n = inc_n * Math_TAU;
- Vector3 base(Math::cos(ang), 0, Math::sin(ang));
- Vector3 base_n(Math::cos(ang_n), 0, Math::sin(ang_n));
+ Vector3 face_base(Math::cos(ang), 0, Math::sin(ang));
+ Vector3 face_base_n(Math::cos(ang_n), 0, Math::sin(ang_n));
Vector3 face_points[4] = {
- base + Vector3(0, -1, 0),
- base_n + Vector3(0, -1, 0),
- base_n * (cone ? 0.0 : 1.0) + Vector3(0, 1, 0),
- base * (cone ? 0.0 : 1.0) + Vector3(0, 1, 0),
+ face_base + Vector3(0, -1, 0),
+ face_base_n + Vector3(0, -1, 0),
+ face_base_n * (cone ? 0.0 : 1.0) + Vector3(0, 1, 0),
+ face_base * (cone ? 0.0 : 1.0) + Vector3(0, 1, 0),
};
Vector2 u[4] = {
@@ -1340,7 +1340,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
@@ -1356,7 +1356,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
@@ -1371,7 +1371,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
smoothw[face] = false;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
if (!cone) {
@@ -1386,7 +1386,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
smoothw[face] = false;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
}
@@ -1397,9 +1397,9 @@ CSGBrush *CSGCylinder3D::_build_brush() {
}
}
- brush->build_from_faces(faces, uvs, smooth, materials, invert);
+ new_brush->build_from_faces(faces, uvs, smooth, materials, invert);
- return brush;
+ return new_brush;
}
void CSGCylinder3D::_bind_methods() {
@@ -1515,12 +1515,12 @@ CSGBrush *CSGTorus3D::_build_brush() {
float radius = (max_radius - min_radius) * 0.5;
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
int face_count = ring_sides * sides * 2;
bool invert_val = get_flip_faces();
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
Vector<Vector3> faces;
Vector<Vector2> uvs;
@@ -1596,7 +1596,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
@@ -1611,7 +1611,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = invert_val;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
}
@@ -1622,9 +1622,9 @@ CSGBrush *CSGTorus3D::_build_brush() {
}
}
- brush->build_from_faces(faces, uvs, smooth, materials, invert);
+ new_brush->build_from_faces(faces, uvs, smooth, materials, invert);
- return brush;
+ return new_brush;
}
void CSGTorus3D::_bind_methods() {
@@ -1726,10 +1726,10 @@ CSGTorus3D::CSGTorus3D() {
///////////////
CSGBrush *CSGPolygon3D::_build_brush() {
- CSGBrush *brush = memnew(CSGBrush);
+ CSGBrush *new_brush = memnew(CSGBrush);
if (polygon.size() < 3) {
- return brush;
+ return new_brush;
}
// Triangulate polygon shape.
@@ -1739,7 +1739,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
int shape_sides = shape_polygon.size();
Vector<int> shape_faces = Geometry2D::triangulate_polygon(shape_polygon);
- ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, brush, "Failed to triangulate CSGPolygon. Make sure the polygon doesn't have any intersecting edges.");
+ ERR_FAIL_COND_V_MSG(shape_faces.size() < 3, new_brush, "Failed to triangulate CSGPolygon. Make sure the polygon doesn't have any intersecting edges.");
// Get polygon enclosing Rect2.
Rect2 shape_rect(shape_polygon[0], Vector2());
@@ -1764,12 +1764,12 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
if (!path) {
- return brush;
+ return new_brush;
}
curve = path->get_curve();
if (curve.is_null() || curve->get_point_count() < 2) {
- return brush;
+ return new_brush;
}
}
@@ -1806,7 +1806,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
int face_count = extrusions * extrusion_face_count + end_count * shape_face_count;
// Initialize variables used to create the mesh.
- Ref<Material> material = get_material();
+ Ref<Material> base_material = get_material();
Vector<Vector3> faces;
Vector<Vector2> uvs;
@@ -1896,7 +1896,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
smoothw[face] = false;
- materialsw[face] = material;
+ materialsw[face] = base_material;
invertw[face] = flip_faces;
face++;
}
@@ -2003,7 +2003,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = flip_faces;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
@@ -2018,7 +2018,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = smooth_faces;
invertw[face] = flip_faces;
- materialsw[face] = material;
+ materialsw[face] = base_material;
face++;
}
@@ -2041,14 +2041,14 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
smoothw[face] = false;
- materialsw[face] = material;
+ materialsw[face] = base_material;
invertw[face] = flip_faces;
face++;
}
}
face_count -= faces_removed;
- ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
+ ERR_FAIL_COND_V_MSG(face != face_count, new_brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
}
if (faces_removed > 0) {
@@ -2059,9 +2059,9 @@ CSGBrush *CSGPolygon3D::_build_brush() {
invert.resize(face_count);
}
- brush->build_from_faces(faces, uvs, smooth, materials, invert);
+ new_brush->build_from_faces(faces, uvs, smooth, materials, invert);
- return brush;
+ return new_brush;
}
void CSGPolygon3D::_notification(int p_what) {
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index 7e92d667b3..06f8f5a403 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -64,9 +64,10 @@
A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this CSG shape scans for collisions. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
+ The physics layers this CSG shape scans for collisions. Only effective if [member use_collision] is [code]true[/code]. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
+ The priority used to solve colliding when occurring penetration. Only effective if [member use_collision] is [code]true[/code]. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level.
</member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
@@ -75,7 +76,7 @@
Snap makes the mesh snap to a given distance so that the faces of two meshes can be perfectly aligned. A lower value results in greater precision but may be harder to adjust.
</member>
<member name="use_collision" type="bool" setter="set_use_collision" getter="is_using_collision" default="false">
- Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden.
+ Adds a collision shape to the physics engine for our CSG shape. This will always act like a static body. Note that the collision shape is still active even if the CSG shape itself is hidden. See also [member collision_mask] and [member collision_priority].
</member>
</members>
<constants>
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index ba9b96db74..73771b3639 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -57,7 +57,7 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
}
String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
if (Object::cast_to<CSGSphere3D>(cs)) {
return "Radius";
@@ -79,7 +79,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo,
}
Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
if (Object::cast_to<CSGSphere3D>(cs)) {
CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
@@ -105,7 +105,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo
}
void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
Transform3D gt = cs->get_global_transform();
//gt.orthonormalize();
@@ -208,7 +208,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i
}
void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
if (Object::cast_to<CSGSphere3D>(cs)) {
CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
@@ -308,7 +308,7 @@ bool CSGShape3DGizmoPlugin::is_selectable_when_hidden() const {
void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
- CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node());
+ CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
Vector<Vector3> faces = cs->get_brush_faces();
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index 3322ff0a1b..89705e4ee0 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -230,7 +230,7 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::UsedChann
h = MAX(h / 2, 1);
}
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
+ p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
void image_decompress_cvtt(Image *p_image) {
@@ -339,5 +339,5 @@ void image_decompress_cvtt(Image *p_image) {
w >>= 1;
h >>= 1;
}
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
+ p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
diff --git a/modules/denoise/lightmap_denoiser.cpp b/modules/denoise/lightmap_denoiser.cpp
index a0dbd07b10..2b9221bc43 100644
--- a/modules/denoise/lightmap_denoiser.cpp
+++ b/modules/denoise/lightmap_denoiser.cpp
@@ -51,7 +51,7 @@ Ref<Image> LightmapDenoiserOIDN::denoise_image(const Ref<Image> &p_image) {
return p_image;
}
- img->create(img->get_width(), img->get_height(), false, img->get_format(), data);
+ img->set_data(img->get_width(), img->get_height(), false, img->get_format(), data);
return img;
}
diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
index 5181ae76ce..2e0d1f5079 100644
--- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml
+++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
@@ -21,13 +21,6 @@
[b]Note:[/b] The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state.
</description>
</method>
- <method name="close_connection">
- <return type="void" />
- <param index="0" name="wait_usec" type="int" default="100" />
- <description>
- Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server.
- </description>
- </method>
<method name="create_client">
<return type="int" enum="Error" />
<param index="0" name="address" type="String" />
@@ -37,7 +30,7 @@
<param index="4" name="out_bandwidth" type="int" default="0" />
<param index="5" name="local_port" type="int" default="0" />
<description>
- Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
+ Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method MultiplayerPeer.close] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
</description>
</method>
<method name="create_mesh">
@@ -55,7 +48,7 @@
<param index="3" name="in_bandwidth" type="int" default="0" />
<param index="4" name="out_bandwidth" type="int" default="0" />
<description>
- Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created.
+ Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method MultiplayerPeer.close] first) or [constant ERR_CANT_CREATE] if the server could not be created.
</description>
</method>
<method name="get_peer" qualifiers="const">
@@ -77,8 +70,5 @@
<member name="host" type="ENetConnection" setter="" getter="get_host">
The underlying [ENetConnection] created after [method create_client] and [method create_server].
</member>
- <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true">
- Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server.
- </member>
</members>
</class>
diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml
index 67760ba5e8..52f45b2338 100644
--- a/modules/enet/doc_classes/ENetPacketPeer.xml
+++ b/modules/enet/doc_classes/ENetPacketPeer.xml
@@ -80,7 +80,7 @@
<return type="void" />
<param index="0" name="ping_interval" type="int" />
<description>
- Sets the [code]ping_interval[/code] in milliseconds at which pings will be sent to a peer. Pings are used both to monitor the liveness of the connection and also to dynamically adjust the throttle during periods of low traffic so that the throttle has reasonable responsiveness during traffic spikes.
+ Sets the [code]ping_interval[/code] in milliseconds at which pings will be sent to a peer. Pings are used both to monitor the liveness of the connection and also to dynamically adjust the throttle during periods of low traffic so that the throttle has reasonable responsiveness during traffic spikes. The default ping interval is [code]500[/code] milliseconds.
</description>
</method>
<method name="reset">
@@ -115,33 +115,43 @@
<param index="2" name="deceleration" type="int" />
<description>
Configures throttle parameter for a peer.
- Unreliable packets are dropped by ENet in response to the varying conditions of the Internet connection to the peer. The throttle represents a probability that an unreliable packet should not be dropped and thus sent by ENet to the peer. By measuring fluctuations in round trip times of reliable packets over the specified [code]interval[/code], ENet will either increase the probably by the amount specified in the [code]acceleration[/code] parameter, or decrease it by the amount specified in the [code]deceleration[/code] parameter (both are ratios to [constant PACKET_THROTTLE_SCALE]).
+ Unreliable packets are dropped by ENet in response to the varying conditions of the Internet connection to the peer. The throttle represents a probability that an unreliable packet should not be dropped and thus sent by ENet to the peer. By measuring fluctuations in round trip times of reliable packets over the specified [code]interval[/code], ENet will either increase the probability by the amount specified in the [code]acceleration[/code] parameter, or decrease it by the amount specified in the [code]deceleration[/code] parameter (both are ratios to [constant PACKET_THROTTLE_SCALE]).
When the throttle has a value of [constant PACKET_THROTTLE_SCALE], no unreliable packets are dropped by ENet, and so 100% of all unreliable packets will be sent.
- When the throttle has a value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable packets will be sent.
+ When the throttle has a value of [code]0[/code], all unreliable packets are dropped by ENet, and so 0% of all unreliable packets will be sent.
Intermediate values for the throttle represent intermediate probabilities between 0% and 100% of unreliable packets being sent. The bandwidth limits of the local and foreign hosts are taken into account to determine a sensible limit for the throttle probability above which it should not raise even in the best of conditions.
</description>
</method>
</methods>
<constants>
<constant name="STATE_DISCONNECTED" value="0" enum="PeerState">
+ The peer is disconnected.
</constant>
<constant name="STATE_CONNECTING" value="1" enum="PeerState">
+ The peer is currently attempting to connect.
</constant>
<constant name="STATE_ACKNOWLEDGING_CONNECT" value="2" enum="PeerState">
+ The peer has acknowledged the connection request.
</constant>
<constant name="STATE_CONNECTION_PENDING" value="3" enum="PeerState">
+ The peer is currently connecting.
</constant>
<constant name="STATE_CONNECTION_SUCCEEDED" value="4" enum="PeerState">
+ The peer has successfully connected, but is not ready to communicate with yet ([constant STATE_CONNECTED]).
</constant>
<constant name="STATE_CONNECTED" value="5" enum="PeerState">
+ The peer is currently connected and ready to communicate with.
</constant>
<constant name="STATE_DISCONNECT_LATER" value="6" enum="PeerState">
+ The peer is slated to disconnect after it has no more outgoing packets to send.
</constant>
<constant name="STATE_DISCONNECTING" value="7" enum="PeerState">
+ The peer is currently disconnecting.
</constant>
<constant name="STATE_ACKNOWLEDGING_DISCONNECT" value="8" enum="PeerState">
+ The peer has acknowledged the disconnection request.
</constant>
<constant name="STATE_ZOMBIE" value="9" enum="PeerState">
+ The peer has lost connection, but is not considered truly disconnected (as the peer didn't acknowledge the disconnection request).
</constant>
<constant name="PEER_PACKET_LOSS" value="0" enum="PeerStatistic">
Mean packet loss of reliable packets as a ratio with respect to the [constant PACKET_LOSS_SCALE].
@@ -150,6 +160,7 @@
Packet loss variance.
</constant>
<constant name="PEER_PACKET_LOSS_EPOCH" value="2" enum="PeerStatistic">
+ The time at which packet loss statistics were last updated (in milliseconds since the connection started). The interval for packet loss statistics updates is 10 seconds, and at least one packet must have been sent since the last statistics update.
</constant>
<constant name="PEER_ROUND_TRIP_TIME" value="3" enum="PeerStatistic">
Mean packet round trip time for reliable packets.
@@ -164,24 +175,31 @@
Variance of the last trip time recorded.
</constant>
<constant name="PEER_PACKET_THROTTLE" value="7" enum="PeerStatistic">
+ The peer's current throttle status.
</constant>
<constant name="PEER_PACKET_THROTTLE_LIMIT" value="8" enum="PeerStatistic">
+ The maximum number of unreliable packets that should not be dropped. This value is always greater than or equal to [code]1[/code]. The initial value is equal to [constant PACKET_THROTTLE_SCALE].
</constant>
<constant name="PEER_PACKET_THROTTLE_COUNTER" value="9" enum="PeerStatistic">
+ Internal value used to increment the packet throttle counter. The value is hardcoded to [code]7[/code] and cannot be changed. You probably want to look at [constant PEER_PACKET_THROTTLE_ACCELERATION] instead.
</constant>
<constant name="PEER_PACKET_THROTTLE_EPOCH" value="10" enum="PeerStatistic">
+ The time at which throttle statistics were last updated (in milliseconds since the connection started). The interval for throttle statistics updates is [constant PEER_PACKET_THROTTLE_INTERVAL].
</constant>
<constant name="PEER_PACKET_THROTTLE_ACCELERATION" value="11" enum="PeerStatistic">
+ The throttle's acceleration factor. Higher values will make ENet adapt to fluctuating network conditions faster, causing unrelaible packets to be sent [i]more[/i] often. The default value is [code]2[/code].
</constant>
<constant name="PEER_PACKET_THROTTLE_DECELERATION" value="12" enum="PeerStatistic">
+ The throttle's deceleration factor. Higher values will make ENet adapt to fluctuating network conditions faster, causing unrelaible packets to be sent [i]less[/i] often. The default value is [code]2[/code].
</constant>
<constant name="PEER_PACKET_THROTTLE_INTERVAL" value="13" enum="PeerStatistic">
+ The interval over which the lowest mean round trip time should be measured for use by the throttle mechanism (in milliseconds). The default value is [code]5000[/code].
</constant>
<constant name="PACKET_LOSS_SCALE" value="65536">
The reference scale for packet loss. See [method get_statistic] and [constant PEER_PACKET_LOSS].
</constant>
<constant name="PACKET_THROTTLE_SCALE" value="32">
- The reference value for throttle configuration. See [method throttle_configure].
+ The reference value for throttle configuration. The default value is [code]32[/code]. See [method throttle_configure].
</constant>
<constant name="FLAG_RELIABLE" value="1">
Mark the packet to be sent as reliable.
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index dfdd08c9f4..31ae643b59 100644
--- a/modules/enet/enet_multiplayer_peer.cpp
+++ b/modules/enet/enet_multiplayer_peer.cpp
@@ -44,6 +44,22 @@ int ENetMultiplayerPeer::get_packet_peer() const {
return incoming_packets.front()->get().from;
}
+MultiplayerPeer::TransferMode ENetMultiplayerPeer::get_packet_mode() const {
+ ERR_FAIL_COND_V_MSG(!_is_active(), TRANSFER_MODE_RELIABLE, "The multiplayer instance isn't currently active.");
+ ERR_FAIL_COND_V(incoming_packets.size() == 0, TRANSFER_MODE_RELIABLE);
+ return incoming_packets.front()->get().transfer_mode;
+}
+
+int ENetMultiplayerPeer::get_packet_channel() const {
+ ERR_FAIL_COND_V_MSG(!_is_active(), 1, "The multiplayer instance isn't currently active.");
+ ERR_FAIL_COND_V(incoming_packets.size() == 0, 1);
+ int ch = incoming_packets.front()->get().channel;
+ if (ch >= SYSCH_MAX) { // First 2 channels are reserved.
+ return ch - SYSCH_MAX + 1;
+ }
+ return 0;
+}
+
Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) {
ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
set_refuse_new_connections(false);
@@ -114,182 +130,40 @@ Error ENetMultiplayerPeer::add_mesh_peer(int p_id, Ref<ENetConnection> p_host) {
return OK;
}
-bool ENetMultiplayerPeer::_parse_server_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event) {
- switch (p_type) {
- case ENetConnection::EVENT_CONNECT: {
- if (is_refusing_new_connections()) {
- p_event.peer->reset();
- return false;
- }
- // Client joined with invalid ID, probably trying to exploit us.
- if (p_event.data < 2 || peers.has((int)p_event.data)) {
- p_event.peer->reset();
- return false;
- }
- int id = p_event.data;
- p_event.peer->set_meta(SNAME("_net_id"), id);
- peers[id] = p_event.peer;
-
- emit_signal(SNAME("peer_connected"), id);
- if (server_relay) {
- _notify_peers(id, true);
- }
- return false;
- }
- case ENetConnection::EVENT_DISCONNECT: {
- int id = p_event.peer->get_meta(SNAME("_net_id"));
- if (!peers.has(id)) {
- // Never fully connected.
- return false;
- }
-
- emit_signal(SNAME("peer_disconnected"), id);
- peers.erase(id);
- if (server_relay) {
- _notify_peers(id, false);
- }
- return false;
- }
- case ENetConnection::EVENT_RECEIVE: {
- if (p_event.channel_id == SYSCH_CONFIG) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V_MSG(false, "Only server can send config messages");
- } else {
- if (p_event.packet->dataLength < 8) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V_MSG(false, "Invalid packet size");
- }
-
- uint32_t source = decode_uint32(&p_event.packet->data[0]);
- int target = decode_uint32(&p_event.packet->data[4]);
-
- uint32_t id = p_event.peer->get_meta(SNAME("_net_id"));
- // Someone is cheating and trying to fake the source!
- if (source != id) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V_MSG(false, "Someone is cheating and trying to fake the source!");
- }
-
- Packet packet;
- packet.packet = p_event.packet;
- packet.channel = p_event.channel_id;
- packet.from = id;
-
- // Even if relaying is disabled, these targets are valid as incoming packets.
- if (target == 1 || target == 0 || target < -1) {
- packet.packet->referenceCount++;
- incoming_packets.push_back(packet);
- }
-
- if (server_relay && target != 1) {
- packet.packet->referenceCount++;
- _relay(source, target, p_event.channel_id, p_event.packet);
- packet.packet->referenceCount--;
- _destroy_unused(p_event.packet);
- }
- // Destroy packet later
- }
- return false;
- }
- default:
- return true;
+void ENetMultiplayerPeer::_store_packet(int32_t p_source, ENetConnection::Event &p_event) {
+ Packet packet;
+ packet.packet = p_event.packet;
+ packet.channel = p_event.channel_id;
+ packet.from = p_source;
+ if (p_event.packet->flags & ENET_PACKET_FLAG_RELIABLE) {
+ packet.transfer_mode = TRANSFER_MODE_RELIABLE;
+ } else if (p_event.packet->flags & ENET_PACKET_FLAG_UNSEQUENCED) {
+ packet.transfer_mode = TRANSFER_MODE_UNRELIABLE;
+ } else {
+ packet.transfer_mode = TRANSFER_MODE_UNRELIABLE_ORDERED;
}
+ packet.packet->referenceCount++;
+ incoming_packets.push_back(packet);
}
-bool ENetMultiplayerPeer::_parse_client_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event) {
- switch (p_type) {
- case ENetConnection::EVENT_CONNECT: {
- connection_status = CONNECTION_CONNECTED;
- emit_signal(SNAME("peer_connected"), 1);
- emit_signal(SNAME("connection_succeeded"));
- return false;
+void ENetMultiplayerPeer::_disconnect_inactive_peers() {
+ HashSet<int> to_drop;
+ for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
+ if (E.value->is_active()) {
+ continue;
}
- case ENetConnection::EVENT_DISCONNECT: {
- if (connection_status == CONNECTION_CONNECTED) {
- // Client just disconnected from server.
- emit_signal(SNAME("server_disconnected"));
- } else {
- emit_signal(SNAME("connection_failed"));
- }
- close_connection();
- return true;
+ to_drop.insert(E.key);
+ }
+ for (const int &P : to_drop) {
+ peers.erase(P);
+ if (hosts.has(P)) {
+ hosts.erase(P);
}
- case ENetConnection::EVENT_RECEIVE: {
- if (p_event.channel_id == SYSCH_CONFIG) {
- // Config message
- if (p_event.packet->dataLength != 8) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V(false);
- }
-
- int msg = decode_uint32(&p_event.packet->data[0]);
- int id = decode_uint32(&p_event.packet->data[4]);
-
- switch (msg) {
- case SYSMSG_ADD_PEER: {
- peers[id] = Ref<ENetPacketPeer>();
- emit_signal(SNAME("peer_connected"), id);
-
- } break;
- case SYSMSG_REMOVE_PEER: {
- peers.erase(id);
- emit_signal(SNAME("peer_disconnected"), id);
- } break;
- }
- _destroy_unused(p_event.packet);
- } else {
- if (p_event.packet->dataLength < 8) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V_MSG(false, "Invalid packet size");
- }
-
- uint32_t source = decode_uint32(&p_event.packet->data[0]);
- Packet packet;
- packet.packet = p_event.packet;
- packet.from = source;
- packet.channel = p_event.channel_id;
-
- packet.packet->referenceCount++;
- incoming_packets.push_back(packet);
- // Destroy packet later
- }
- return false;
+ if (active_mode == MODE_CLIENT) {
+ ERR_CONTINUE(P != TARGET_PEER_SERVER);
+ emit_signal(SNAME("server_disconnected"));
}
- default:
- return true;
- }
-}
-
-bool ENetMultiplayerPeer::_parse_mesh_event(ENetConnection::EventType p_type, ENetConnection::Event &p_event, int p_peer_id) {
- switch (p_type) {
- case ENetConnection::EVENT_CONNECT:
- p_event.peer->reset();
- return false;
- case ENetConnection::EVENT_DISCONNECT:
- if (peers.has(p_peer_id)) {
- emit_signal(SNAME("peer_disconnected"), p_peer_id);
- peers.erase(p_peer_id);
- }
- hosts.erase(p_peer_id);
- return true;
- case ENetConnection::EVENT_RECEIVE: {
- if (p_event.packet->dataLength < 8) {
- _destroy_unused(p_event.packet);
- ERR_FAIL_V_MSG(false, "Invalid packet size");
- }
-
- Packet packet;
- packet.packet = p_event.packet;
- packet.from = p_peer_id;
- packet.channel = p_event.channel_id;
-
- packet.packet->referenceCount++;
- incoming_packets.push_back(packet);
- return false;
- } break;
- default:
- // Nothing to do
- return true;
+ emit_signal(SNAME("peer_disconnected"), P);
}
}
@@ -298,74 +172,96 @@ void ENetMultiplayerPeer::poll() {
_pop_current_packet();
+ _disconnect_inactive_peers();
+
switch (active_mode) {
case MODE_CLIENT: {
- if (peers.has(1) && !peers[1]->is_active()) {
- if (connection_status == CONNECTION_CONNECTED) {
- // Client just disconnected from server.
- emit_signal(SNAME("server_disconnected"));
- } else {
- emit_signal(SNAME("connection_failed"));
- }
- close_connection();
+ if (!peers.has(1)) {
+ close();
return;
}
ENetConnection::Event event;
ENetConnection::EventType ret = hosts[0]->service(0, event);
- if (ret == ENetConnection::EVENT_ERROR) {
- return;
- }
do {
- if (_parse_client_event(ret, event)) {
- return;
+ if (ret == ENetConnection::EVENT_CONNECT) {
+ connection_status = CONNECTION_CONNECTED;
+ emit_signal(SNAME("peer_connected"), 1);
+ emit_signal(SNAME("connection_succeeded"));
+ } else if (ret == ENetConnection::EVENT_DISCONNECT) {
+ if (connection_status == CONNECTION_CONNECTED) {
+ // Client just disconnected from server.
+ emit_signal(SNAME("server_disconnected"));
+ emit_signal(SNAME("peer_disconnected"), 1);
+ } else {
+ emit_signal(SNAME("connection_failed"));
+ }
+ close();
+ } else if (ret == ENetConnection::EVENT_RECEIVE) {
+ _store_packet(1, event);
+ } else if (ret != ENetConnection::EVENT_NONE) {
+ close(); // Error.
}
- } while (hosts[0]->check_events(ret, event) > 0);
+ } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0);
} break;
case MODE_SERVER: {
- for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (!(E.value->is_active())) {
- emit_signal(SNAME("peer_disconnected"), E.value->get_meta(SNAME("_net_id")));
- peers.erase(E.key);
- }
- }
ENetConnection::Event event;
ENetConnection::EventType ret = hosts[0]->service(0, event);
- if (ret == ENetConnection::EVENT_ERROR) {
- return;
- }
do {
- if (_parse_server_event(ret, event)) {
- return;
+ if (ret == ENetConnection::EVENT_CONNECT) {
+ if (is_refusing_new_connections()) {
+ event.peer->reset();
+ continue;
+ }
+ // Client joined with invalid ID, probably trying to exploit us.
+ if (event.data < 2 || peers.has((int)event.data)) {
+ event.peer->reset();
+ continue;
+ }
+ int id = event.data;
+ event.peer->set_meta(SNAME("_net_id"), id);
+ peers[id] = event.peer;
+ emit_signal(SNAME("peer_connected"), id);
+ } else if (ret == ENetConnection::EVENT_DISCONNECT) {
+ int id = event.peer->get_meta(SNAME("_net_id"));
+ if (!peers.has(id)) {
+ // Never fully connected.
+ continue;
+ }
+ emit_signal(SNAME("peer_disconnected"), id);
+ peers.erase(id);
+ } else if (ret == ENetConnection::EVENT_RECEIVE) {
+ int32_t source = event.peer->get_meta(SNAME("_net_id"));
+ _store_packet(source, event);
+ } else if (ret != ENetConnection::EVENT_NONE) {
+ close(); // Error
}
- } while (hosts[0]->check_events(ret, event) > 0);
+ } while (hosts.has(0) && hosts[0]->check_events(ret, event) > 0);
} break;
case MODE_MESH: {
- for (const KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (!(E.value->is_active())) {
- emit_signal(SNAME("peer_disconnected"), E.key);
- peers.erase(E.key);
- if (hosts.has(E.key)) {
- hosts.erase(E.key);
- }
- }
- }
+ HashSet<int> to_drop;
for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
ENetConnection::Event event;
ENetConnection::EventType ret = E.value->service(0, event);
- if (ret == ENetConnection::EVENT_ERROR) {
- if (peers.has(E.key)) {
- emit_signal(SNAME("peer_disconnected"), E.key);
- peers.erase(E.key);
- }
- hosts.erase(E.key);
- continue;
- }
do {
- if (_parse_mesh_event(ret, event, E.key)) {
+ if (ret == ENetConnection::EVENT_CONNECT) {
+ event.peer->reset();
+ } else if (ret == ENetConnection::EVENT_RECEIVE) {
+ _store_packet(E.key, event);
+ } else if (ret == ENetConnection::EVENT_NONE) {
+ break; // Keep polling the others.
+ } else {
+ to_drop.insert(E.key); // Error or disconnect.
break; // Keep polling the others.
}
} while (E.value->check_events(ret, event) > 0);
}
+ for (const int &P : to_drop) {
+ if (peers.has(P)) {
+ emit_signal(SNAME("peer_disconnected"), P);
+ peers.erase(P);
+ }
+ hosts.erase(P);
+ }
} break;
default:
return;
@@ -376,29 +272,45 @@ bool ENetMultiplayerPeer::is_server() const {
return active_mode == MODE_SERVER;
}
-void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) {
+bool ENetMultiplayerPeer::is_server_relay_supported() const {
+ return active_mode == MODE_SERVER || active_mode == MODE_CLIENT;
+}
+
+void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool p_force) {
+ ERR_FAIL_COND(!_is_active() || !peers.has(p_peer));
+ peers[p_peer]->peer_disconnect(0); // Will be removed during next poll.
+ if (active_mode == MODE_CLIENT || active_mode == MODE_SERVER) {
+ hosts[0]->flush();
+ } else {
+ ERR_FAIL_COND(!hosts.has(p_peer));
+ hosts[p_peer]->flush();
+ }
+ if (p_force) {
+ peers.erase(p_peer);
+ if (hosts.has(p_peer)) {
+ hosts.erase(p_peer);
+ }
+ if (active_mode == MODE_CLIENT) {
+ hosts.clear(); // Avoid flushing again.
+ close();
+ }
+ }
+}
+
+void ENetMultiplayerPeer::close() {
if (!_is_active()) {
return;
}
_pop_current_packet();
- bool peers_disconnected = false;
for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
if (E.value.is_valid() && E.value->get_state() == ENetPacketPeer::STATE_CONNECTED) {
- E.value->peer_disconnect_now(unique_id);
- peers_disconnected = true;
+ E.value->peer_disconnect_now(0);
}
}
-
- if (peers_disconnected) {
- for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
- E.value->flush();
- }
-
- if (wait_usec > 0) {
- OS::get_singleton()->delay_usec(wait_usec); // Wait for disconnection packets to send
- }
+ for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
+ E.value->flush();
}
active_mode = MODE_NONE;
@@ -422,8 +334,8 @@ Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_si
current_packet = incoming_packets.front()->get();
incoming_packets.pop_front();
- *r_buffer = (const uint8_t *)(&current_packet.packet->data[8]);
- r_buffer_size = current_packet.packet->dataLength - 8;
+ *r_buffer = (const uint8_t *)(current_packet.packet->data);
+ r_buffer_size = current_packet.packet->dataLength;
return OK;
}
@@ -436,9 +348,9 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size
int packet_flags = 0;
int channel = SYSCH_RELIABLE;
- int transfer_channel = get_transfer_channel();
- if (transfer_channel > 0) {
- channel = SYSCH_MAX + transfer_channel - 1;
+ int tr_channel = get_transfer_channel();
+ if (tr_channel > 0) {
+ channel = SYSCH_MAX + tr_channel - 1;
} else {
switch (get_transfer_mode()) {
case TRANSFER_MODE_UNRELIABLE: {
@@ -457,15 +369,13 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size
}
#ifdef DEBUG_ENABLED
- if ((packet_flags & ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) && p_buffer_size + 8 > ENET_HOST_DEFAULT_MTU) {
- WARN_PRINT_ONCE(vformat("Sending %d bytes unrealiably which is above the MTU (%d), this will result in higher packet loss", p_buffer_size + 8, ENET_HOST_DEFAULT_MTU));
+ if ((packet_flags & ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) && p_buffer_size > ENET_HOST_DEFAULT_MTU) {
+ WARN_PRINT_ONCE(vformat("Sending %d bytes unrealiably which is above the MTU (%d), this will result in higher packet loss", p_buffer_size, ENET_HOST_DEFAULT_MTU));
}
#endif
- ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags);
- encode_uint32(unique_id, &packet->data[0]); // Source ID
- encode_uint32(target_peer, &packet->data[4]); // Dest ID
- memcpy(&packet->data[8], p_buffer, p_buffer_size);
+ ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size, packet_flags);
+ memcpy(&packet->data[0], p_buffer, p_buffer_size);
if (is_server()) {
if (target_peer == 0) {
@@ -548,16 +458,6 @@ void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enabled) {
MultiplayerPeer::set_refuse_new_connections(p_enabled);
}
-void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) {
- ERR_FAIL_COND_MSG(_is_active(), "Server relaying can't be toggled while the multiplayer instance is active.");
-
- server_relay = p_enabled;
-}
-
-bool ENetMultiplayerPeer::is_server_relay_enabled() const {
- return server_relay;
-}
-
Ref<ENetConnection> ENetMultiplayerPeer::get_host() const {
ERR_FAIL_COND_V(!_is_active(), nullptr);
ERR_FAIL_COND_V(active_mode == MODE_MESH, nullptr);
@@ -577,84 +477,16 @@ void ENetMultiplayerPeer::_destroy_unused(ENetPacket *p_packet) {
}
}
-void ENetMultiplayerPeer::_relay(int p_from, int p_to, enet_uint8 p_channel, ENetPacket *p_packet) {
- if (p_to == 0) {
- // Re-send to everyone but sender :|
- for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (E.key == p_from) {
- continue;
- }
-
- E.value->send(p_channel, p_packet);
- }
- } else if (p_to < 0) {
- // Re-send to everyone but excluded and sender.
- for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (E.key == p_from || E.key == -p_to) { // Do not resend to self, also do not send to excluded
- continue;
- }
-
- E.value->send(p_channel, p_packet);
- }
- } else {
- // To someone else, specifically
- ERR_FAIL_COND(!peers.has(p_to));
- ENetPacket *packet = enet_packet_create(p_packet->data, p_packet->dataLength, p_packet->flags);
- peers[p_to]->send(p_channel, packet);
- }
-}
-
-void ENetMultiplayerPeer::_notify_peers(int p_id, bool p_connected) {
- if (p_connected) {
- ERR_FAIL_COND(!peers.has(p_id));
- // Someone connected, notify all the peers available.
- Ref<ENetPacketPeer> peer = peers[p_id];
- ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
- encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]);
- encode_uint32(p_id, &packet->data[4]);
- for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (E.key == p_id) {
- continue;
- }
- // Send new peer to existing peer.
- E.value->send(SYSCH_CONFIG, packet);
- // Send existing peer to new peer.
- // This packet will be automatically destroyed by ENet after send.
- ENetPacket *packet2 = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
- encode_uint32(SYSMSG_ADD_PEER, &packet2->data[0]);
- encode_uint32(E.key, &packet2->data[4]);
- peer->send(SYSCH_CONFIG, packet2);
- }
- _destroy_unused(packet);
- } else {
- // Server just received a client disconnect and is in relay mode, notify everyone else.
- ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
- encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
- encode_uint32(p_id, &packet->data[4]);
- for (KeyValue<int, Ref<ENetPacketPeer>> &E : peers) {
- if (E.key == p_id) {
- continue;
- }
- E.value->send(SYSCH_CONFIG, packet);
- }
- _destroy_unused(packet);
- }
-}
-
void ENetMultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "max_channels", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("create_client", "address", "port", "channel_count", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("create_mesh", "unique_id"), &ENetMultiplayerPeer::create_mesh);
ClassDB::bind_method(D_METHOD("add_mesh_peer", "peer_id", "host"), &ENetMultiplayerPeer::add_mesh_peer);
- ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &ENetMultiplayerPeer::close_connection, DEFVAL(100));
ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip);
- ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &ENetMultiplayerPeer::set_server_relay_enabled);
- ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &ENetMultiplayerPeer::is_server_relay_enabled);
ClassDB::bind_method(D_METHOD("get_host"), &ENetMultiplayerPeer::get_host);
ClassDB::bind_method(D_METHOD("get_peer", "id"), &ENetMultiplayerPeer::get_peer);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "host", PROPERTY_HINT_RESOURCE_TYPE, "ENetConnection", PROPERTY_USAGE_NONE), "", "get_host");
}
@@ -664,7 +496,7 @@ ENetMultiplayerPeer::ENetMultiplayerPeer() {
ENetMultiplayerPeer::~ENetMultiplayerPeer() {
if (_is_active()) {
- close_connection();
+ close();
}
}
diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h
index 3152068d46..2665b69669 100644
--- a/modules/enet/enet_multiplayer_peer.h
+++ b/modules/enet/enet_multiplayer_peer.h
@@ -47,10 +47,9 @@ private:
};
enum {
- SYSCH_CONFIG = 0,
- SYSCH_RELIABLE = 1,
- SYSCH_UNRELIABLE = 2,
- SYSCH_MAX = 3
+ SYSCH_RELIABLE = 0,
+ SYSCH_UNRELIABLE = 1,
+ SYSCH_MAX = 2
};
enum Mode {
@@ -66,8 +65,6 @@ private:
int target_peer = 0;
- bool server_relay = true;
-
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
HashMap<int, Ref<ENetConnection>> hosts;
@@ -77,18 +74,16 @@ private:
ENetPacket *packet = nullptr;
int from = 0;
int channel = 0;
+ TransferMode transfer_mode = TRANSFER_MODE_RELIABLE;
};
List<Packet> incoming_packets;
Packet current_packet;
+ void _store_packet(int32_t p_source, ENetConnection::Event &p_event);
void _pop_current_packet();
- bool _parse_server_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event);
- bool _parse_client_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event);
- bool _parse_mesh_event(ENetConnection::EventType p_event_type, ENetConnection::Event &p_event, int p_peer_id);
- void _relay(int p_from, int p_to, enet_uint8 p_channel, ENetPacket *p_packet);
- void _notify_peers(int p_id, bool p_connected);
+ void _disconnect_inactive_peers();
void _destroy_unused(ENetPacket *p_packet);
_FORCE_INLINE_ bool _is_active() const { return active_mode != MODE_NONE; }
@@ -99,10 +94,18 @@ protected:
public:
virtual void set_target_peer(int p_peer) override;
+
virtual int get_packet_peer() const override;
+ virtual TransferMode get_packet_mode() const override;
+ virtual int get_packet_channel() const override;
virtual void poll() override;
+ virtual void close() override;
+ virtual void disconnect_peer(int p_peer, bool p_force = false) override;
+
virtual bool is_server() const override;
+ virtual bool is_server_relay_supported() const override;
+
// Overridden so we can instrument the DTLSServer when needed.
virtual void set_refuse_new_connections(bool p_enabled) override;
@@ -120,13 +123,7 @@ public:
Error create_mesh(int p_id);
Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host);
- void close_connection(uint32_t wait_usec = 100);
-
- void disconnect_peer(int p_peer, bool now = false);
-
void set_bind_ip(const IPAddress &p_ip);
- void set_server_relay_enabled(bool p_enabled);
- bool is_server_relay_enabled() const;
Ref<ENetConnection> get_host() const;
Ref<ENetPacketPeer> get_peer(int p_id) const;
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
index 7d5557d197..3d66b27556 100644
--- a/modules/etcpak/image_compress_etcpak.cpp
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -233,7 +233,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
}
// Replace original image with compressed one.
- r_img->create(width, height, mipmaps, target_format, dest_data);
+ r_img->set_data(width, height, mipmaps, target_format, dest_data);
print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index d0b4632ebe..c8eda53a2d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -18,13 +18,11 @@
<param index="2" name="b8" type="int" />
<param index="3" name="a8" type="int" default="255" />
<description>
- Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255.
- [code]r8[/code] red channel
- [code]g8[/code] green channel
- [code]b8[/code] blue channel
- [code]a8[/code] alpha channel
+ Returns a [Color] constructed from red ([param r8]), green ([param g8]), blue ([param b8]), and optionally alpha ([param a8]) integer channels, each divided by [code]255.0[/code] for their final value.
[codeblock]
- red = Color8(255, 0, 0)
+ var red = Color8(255, 0, 0) # Same as Color(1, 0, 0)
+ var dark_blue = Color8(0, 0, 51) # Same as Color(0, 0, 0.2).
+ var my_color = Color8(306, 255, 0, 102) # Same as Color(1.2, 1, 0, 0.4).
[/codeblock]
</description>
</method>
@@ -33,9 +31,9 @@
<param index="0" name="condition" type="bool" />
<param index="1" name="message" type="String" default="&quot;&quot;" />
<description>
- Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
- [b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
- The optional [code]message[/code] argument, if given, is shown in addition to the generic "Assertion failed" message. It must be a static string, so format strings can't be used. You can use this to provide additional details about why the assertion failed.
+ Asserts that the [param condition] is [code]true[/code]. If the [param condition] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
+ An optional [param message] can be shown in addition to the generic "Assertion failed" message. You can use this to provide additional details about why the assertion failed.
+ [b]Warning:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
[codeblock]
# Imagine we always want speed to be between 0 and 20.
var speed = -10
@@ -50,7 +48,7 @@
<return type="String" />
<param index="0" name="char" type="int" />
<description>
- Returns a character as a String of the given Unicode code point (which is compatible with ASCII code).
+ Returns a single character (as a [String]) of the given Unicode code point (which is compatible with ASCII code).
[codeblock]
a = char(65) # a is "A"
a = char(65 + 32) # a is "a"
@@ -63,14 +61,14 @@
<param index="0" name="what" type="Variant" />
<param index="1" name="type" type="int" />
<description>
- Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values.
+ Converts [param what] to [param type] in the best way possible. The [param type] uses the [enum Variant.Type] values.
[codeblock]
- a = Vector2(1, 0)
- # Prints 1
- print(a.length())
- a = convert(a, TYPE_STRING)
- # Prints 6 as "(1, 0)" is 6 characters
- print(a.length())
+ var a = [4, 2.5, 1.2]
+ print(a is Array) # Prints true
+
+ var b = convert(a, TYPE_PACKED_BYTE_ARRAY)
+ print(b) # Prints [4, 2, 1]
+ print(b is Array) # Prints false
[/codeblock]
</description>
</method>
@@ -78,7 +76,7 @@
<return type="Object" />
<param index="0" name="dictionary" type="Dictionary" />
<description>
- Converts a [param dictionary] (previously created with [method inst_to_dict]) back to an Object instance. Useful for deserializing.
+ Converts a [param dictionary] (created with [method inst_to_dict]) back to an Object instance. Can be useful for deserializing.
</description>
</method>
<method name="get_stack">
@@ -95,19 +93,19 @@
func bar():
print(get_stack())
[/codeblock]
- would print
+ Starting from [code]_ready()[/code], [code]bar()[/code] would print:
[codeblock]
[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]
[/codeblock]
- [b]Note:[/b] [method get_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method get_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will return an empty array.
</description>
</method>
<method name="inst_to_dict">
<return type="Dictionary" />
<param index="0" name="instance" type="Object" />
<description>
- Returns the passed [param instance] converted to a Dictionary (useful for serializing).
+ Returns the passed [param instance] converted to a Dictionary. Can be useful for serializing.
[codeblock]
var foo = "bar"
func _ready():
@@ -126,11 +124,13 @@
<return type="int" />
<param index="0" name="var" type="Variant" />
<description>
- Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc.
- [b]Note:[/b] Generates a fatal error if Variant can not provide a length.
+ Returns the length of the given Variant [param var]. The length can be the character count of a [String], the element count of any array type or the size of a [Dictionary]. For every other Variant type, a run-time error is generated and execution is stopped.
[codeblock]
a = [1, 2, 3, 4]
len(a) # Returns 4
+
+ b = "Hello!"
+ len(b) # Returns 6
[/codeblock]
</description>
</method>
@@ -138,25 +138,25 @@
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
+ Returns a [Resource] from the filesystem located at the absolute [param path]. Unless it's already referenced elsewhere (such as in another script or in the scene), the resource is loaded from disk on function call, which might cause a slight delay, especially when loading large scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Load a scene called main located in the root of the project directory and cache it in a variable.
+ # Load a scene called "main" located in the root of the project directory and cache it in a variable.
var main = load("res://main.tscn") # main will contain a PackedScene resource.
[/codeblock]
- [b]Important:[/b] The path must be absolute, a local path will just return [code]null[/code].
- This method is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
- [b]Note:[/b] You have to import the files into the engine first to load them using [method load]. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
+ [b]Important:[/b] The path must be absolute. A relative path will always return [code]null[/code].
+ This function is a simplified version of [method ResourceLoader.load], which can be used for more advanced scenarios.
+ [b]Note:[/b] Files have to be imported into the engine first to load them using this function. If you want to load [Image]s at run-time, you may use [method Image.load]. If you want to import audio files, you can use the snippet described in [member AudioStreamMP3.data].
</description>
</method>
<method name="preload">
<return type="Resource" />
<param index="0" name="path" type="String" />
<description>
- Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load].
+ Returns a [Resource] from the filesystem located at [param path]. During run-time, the resource is loaded when the script is being parsed. This function effectively acts as a reference to that resource. Note that this function requires [param path] to be a constant [String]. If you want to load a resource from a dynamic/variable path, use [method load].
[b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
[codeblock]
- # Instance a scene.
+ # Create instance of a scene.
var diamond = preload("res://diamond.tscn").instantiate()
[/codeblock]
</description>
@@ -165,24 +165,24 @@
<return type="void" />
<description>
Like [method @GlobalScope.print], but includes the current stack frame when running with the debugger turned on.
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Test print
- At: res://test.gd:15:_process()
+ At: res://test.gd:15:_process()
[/codeblock]
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack frame, this will print the thread ID.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="print_stack">
<return type="void" />
<description>
Prints a stack trace at the current code location. See also [method get_stack].
- Output in the console would look something like this:
+ The output in the console may look like the following:
[codeblock]
Frame 0 - res://test.gd:16 in function '_process'
[/codeblock]
- [b]Note:[/b] [method print_stack] only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
- [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID.
+ [b]Note:[/b] This function only works if the running instance is connected to a debugging server (i.e. an editor instance). [method print_stack] will not work in projects exported in release mode, or in projects exported in debug mode if not connected to a debugging server.
+ [b]Note:[/b] Calling this function from a [Thread] is not supported. Doing so will instead print the thread ID.
</description>
</method>
<method name="range" qualifiers="vararg">
@@ -229,7 +229,7 @@
<method name="str" qualifiers="vararg">
<return type="String" />
<description>
- Converts one or more arguments to string in the best way possible.
+ Converts one or more arguments to a [String] in the best way possible.
[codeblock]
var a = [10, 20, 30]
var b = str(a);
@@ -242,7 +242,7 @@
<return type="bool" />
<param index="0" name="type" type="StringName" />
<description>
- Returns whether the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
+ Returns [code]true[/code] if the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
[codeblock]
type_exists("Sprite2D") # Returns true
type_exists("NonExistentClass") # Returns false
@@ -259,11 +259,11 @@
</constant>
<constant name="INF" value="inf">
Positive floating-point infinity. This is the result of floating-point division when the divisor is [code]0.0[/code]. For negative infinity, use [code]-INF[/code]. Dividing by [code]-0.0[/code] will result in negative infinity if the numerator is positive, so dividing by [code]0.0[/code] is not the same as dividing by [code]-0.0[/code] (despite [code]0.0 == -0.0[/code] returning [code]true[/code]).
- [b]Note:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
+ [b]Warning:[/b] Numeric infinity is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer number by [code]0[/code] will not result in [constant INF] and will result in a run-time error instead.
</constant>
<constant name="NAN" value="nan">
"Not a Number", an invalid floating-point value. [constant NAN] has special properties, including that it is not equal to itself ([code]NAN == NAN[/code] returns [code]false[/code]). It is output by some invalid operations, such as dividing floating-point [code]0.0[/code] by [code]0.0[/code].
- [b]Note:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
+ [b]Warning:[/b] "Not a Number" is only a concept with floating-point numbers, and has no equivalent for integers. Dividing an integer [code]0[/code] by [code]0[/code] will not result in [constant NAN] and will result in a run-time error instead.
</constant>
</constants>
<annotations>
@@ -294,7 +294,7 @@
<annotation name="@export_color_no_alpha">
<return type="void" />
<description>
- Export a [Color] property without an alpha (fixed as [code]1.0[/code]).
+ Export a [Color] property without transparency (its alpha fixed as [code]1.0[/code]).
See also [constant PROPERTY_HINT_COLOR_NO_ALPHA].
[codeblock]
@export_color_no_alpha var modulate_color: Color
@@ -320,7 +320,7 @@
[codeblock]
@export_enum("Rebecca", "Mary", "Leah") var character_name: String
@export_enum("Warrior", "Magician", "Thief") var character_class: int
- @export_enum("Walking:30", "Running:60", "Riding:200") var character_speed: int
+ @export_enum("Slow:30", "Average:60", "Very Fast:200") var character_speed: int
[/codeblock]
</description>
</annotation>
@@ -451,7 +451,7 @@
<description>
Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock.
If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for parameters, [code]@export_group("", "")[/code].
- Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups.
+ Groups cannot be nested, use [annotation @export_subgroup] to add subgroups within groups.
See also [constant PROPERTY_USAGE_GROUP].
[codeblock]
@export_group("My Properties")
@@ -473,7 +473,7 @@
Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
See also [constant PROPERTY_HINT_MULTILINE_TEXT].
[codeblock]
- @export_multiline var character_bio
+ @export_multiline var character_biography
[/codeblock]
</description>
</annotation>
@@ -507,7 +507,7 @@
<param index="3" name="extra_hints" type="String" default="&quot;&quot;" />
<description>
Export a numeric property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [code]EditorSettings.interface/inspector/default_float_step[/code] setting.
- If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"no_slider"[/code] hint will hide the slider element of the editor widget.
+ If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"hide_slider"[/code] hint will hide the slider element of the editor widget.
Hints also allow to indicate the units for the edited value. Using [code]"radians"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock. [code]"degrees"[/code] allows to add a degree sign as a unit suffix. Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
See also [constant PROPERTY_HINT_RANGE].
[codeblock]
@@ -547,11 +547,11 @@
<return type="void" />
<param index="0" name="icon_path" type="String" />
<description>
- Add a custom icon to the current script. The icon is displayed in the Scene dock for every node that the script is attached to. For named classes the icon is also displayed in various editor dialogs.
+ Add a custom icon to the current script. After loading an icon at [param icon_path], the icon is displayed in the Scene dock for every node that the script is attached to. For named classes, the icon is also displayed in various editor dialogs.
[codeblock]
@icon("res://path/to/class/icon.svg")
[/codeblock]
- [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported yet.
+ [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported.
</description>
</annotation>
<annotation name="@onready">
@@ -590,7 +590,7 @@
<return type="void" />
<param index="0" name="warning" type="String" />
<description>
- Mark the following statement to ignore the specified warning. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
+ Mark the following statement to ignore the specified [param warning]. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
[codeblock]
func test():
print("hello")
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 578e7a34f3..8246c96c15 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -4,7 +4,7 @@
A script implemented in the GDScript programming language.
</brief_description>
<description>
- A script implemented in the GDScript programming language. The script extends the functionality of all objects that instance it.
+ A script implemented in the GDScript programming language. The script extends the functionality of all objects that instantiate it.
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 8b27307d0c..420401cb79 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -256,7 +256,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
String word = str.substr(from + 1, to - from);
// Keywords need to be exceptions, except for keywords that represent a value.
- if (word == "true" || word == "false" || word == "null" || word == "PI" || word == "TAU" || word == "INF" || word == "NAN" || word == "self" || word == "super" || !keywords.has(word)) {
+ if (word == "true" || word == "false" || word == "null" || word == "PI" || word == "TAU" || word == "INF" || word == "NAN" || word == "self" || word == "super" || !reserved_keywords.has(word)) {
if (!is_symbol(str[to]) || str[to] == '"' || str[to] == '\'' || str[to] == ')' || str[to] == ']' || str[to] == '}') {
is_binary_op = true;
}
@@ -338,8 +338,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
col = global_function_color;
}
}
- } else if (keywords.has(word)) {
- col = keywords[word];
+ } else if (class_names.has(word)) {
+ col = class_names[word];
+ } else if (reserved_keywords.has(word)) {
+ col = reserved_keywords[word];
} else if (member_keywords.has(word)) {
col = member_keywords[word];
}
@@ -563,7 +565,8 @@ PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const {
}
void GDScriptSyntaxHighlighter::_update_cache() {
- keywords.clear();
+ class_names.clear();
+ reserved_keywords.clear();
member_keywords.clear();
global_functions.clear();
color_regions.clear();
@@ -580,7 +583,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<StringName> types;
ClassDB::get_class_list(&types);
for (const StringName &E : types) {
- keywords[E] = types_color;
+ class_names[E] = types_color;
}
/* User types. */
@@ -588,14 +591,14 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
- keywords[E] = usertype_color;
+ class_names[E] = usertype_color;
}
/* Autoloads. */
for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
const ProjectSettings::AutoloadInfo &info = E.value;
if (info.is_singleton) {
- keywords[info.name] = usertype_color;
+ class_names[info.name] = usertype_color;
}
}
@@ -606,7 +609,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<String> core_types;
gdscript->get_core_type_words(&core_types);
for (const String &E : core_types) {
- keywords[StringName(E)] = basetype_color;
+ class_names[StringName(E)] = basetype_color;
}
/* Reserved words. */
@@ -616,9 +619,9 @@ void GDScriptSyntaxHighlighter::_update_cache() {
gdscript->get_reserved_words(&keyword_list);
for (const String &E : keyword_list) {
if (gdscript->is_control_flow_keyword(E)) {
- keywords[StringName(E)] = control_flow_keyword_color;
+ reserved_keywords[StringName(E)] = control_flow_keyword_color;
} else {
- keywords[StringName(E)] = keyword_color;
+ reserved_keywords[StringName(E)] = keyword_color;
}
}
@@ -653,23 +656,23 @@ void GDScriptSyntaxHighlighter::_update_cache() {
add_color_region(beg, end, string_color, end.is_empty());
}
- const Ref<Script> script = _get_edited_resource();
- if (script.is_valid()) {
+ const Ref<Script> scr = _get_edited_resource();
+ if (scr.is_valid()) {
/* Member types. */
const Color member_variable_color = EDITOR_GET("text_editor/theme/highlighting/member_variable_color");
- StringName instance_base = script->get_instance_base_type();
+ StringName instance_base = scr->get_instance_base_type();
if (instance_base != StringName()) {
List<PropertyInfo> plist;
ClassDB::get_property_list(instance_base, &plist);
for (const PropertyInfo &E : plist) {
- String name = E.name;
+ String prop_name = E.name;
if (E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP) {
continue;
}
- if (name.contains("/")) {
+ if (prop_name.contains("/")) {
continue;
}
- member_keywords[name] = member_variable_color;
+ member_keywords[prop_name] = member_variable_color;
}
List<String> clist;
@@ -680,7 +683,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
}
- const String text_edit_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
+ const String text_edit_color_theme = EDITOR_GET("text_editor/theme/color_theme");
const bool godot_2_theme = text_edit_color_theme == "Godot 2";
if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) {
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 60b5b092d4..7c22eb30b1 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -47,7 +47,8 @@ private:
Vector<ColorRegion> color_regions;
HashMap<int, int> color_region_cache;
- HashMap<StringName, Color> keywords;
+ HashMap<StringName, Color> class_names;
+ HashMap<StringName, Color> reserved_keywords;
HashMap<StringName, Color> member_keywords;
HashSet<StringName> global_functions;
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 54cadf7df3..b4da9c1224 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -111,9 +111,9 @@ GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
if (p_script->initializer) {
return p_script->initializer;
} else {
- GDScript *base = p_script->_base;
- if (base != nullptr) {
- return _super_constructor(base);
+ GDScript *base_src = p_script->_base;
+ if (base_src != nullptr) {
+ return _super_constructor(base_src);
} else {
return nullptr;
}
@@ -121,9 +121,9 @@ GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
}
void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) {
- GDScript *base = p_script->_base;
- if (base != nullptr) {
- _super_implicit_constructor(base, p_instance, r_error);
+ GDScript *base_src = p_script->_base;
+ if (base_src != nullptr) {
+ _super_implicit_constructor(base_src, p_instance, r_error);
if (r_error.error != Callable::CallError::CALL_OK) {
return;
}
@@ -151,7 +151,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
/* STEP 2, INITIALIZE AND CONSTRUCT */
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
instances.insert(instance->owner);
}
@@ -160,7 +160,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
instance->script = Ref<GDScript>();
instance->owner->set_script_instance(nullptr);
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
instances.erase(p_owner);
}
ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
@@ -177,7 +177,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
instance->script = Ref<GDScript>();
instance->owner->set_script_instance(nullptr);
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
instances.erase(p_owner);
}
ERR_FAIL_V_MSG(nullptr, "Error constructing a GDScriptInstance.");
@@ -396,9 +396,9 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
if (top->native.is_valid()) {
if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
+ GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be assigned to an object of type: '" + p_this->get_class() + "'");
}
- ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + ".");
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be assigned to an object of type '" + p_this->get_class() + "'" + ".");
}
}
@@ -418,7 +418,7 @@ PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this)
}
bool GDScript::instance_has(const Object *p_this) const {
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
return instances.has((Object *)p_this);
}
@@ -620,11 +620,11 @@ void GDScript::_update_doc() {
}
if (!is_enum) {
DocData::ConstantDoc constant_doc;
- String doc_description;
+ String const_description;
if (doc_constants.has(E.key)) {
- doc_description = doc_constants[E.key];
+ const_description = doc_constants[E.key];
}
- DocData::constant_doc_from_variant(constant_doc, E.key, E.value, doc_description);
+ DocData::constant_doc_from_variant(constant_doc, E.key, E.value, const_description);
doc.constants.push_back(constant_doc);
}
}
@@ -675,35 +675,35 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
}
if (c->extends_used) {
- String path = "";
+ String ext_path = "";
if (String(c->extends_path) != "" && String(c->extends_path) != get_path()) {
- path = c->extends_path;
- if (path.is_relative_path()) {
- String base = get_path();
- if (base.is_empty() || base.is_relative_path()) {
- ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
+ ext_path = c->extends_path;
+ if (ext_path.is_relative_path()) {
+ String base_path = get_path();
+ if (base_path.is_empty() || base_path.is_relative_path()) {
+ ERR_PRINT(("Could not resolve relative path for parent class: " + ext_path).utf8().get_data());
} else {
- path = base.get_base_dir().path_join(path);
+ ext_path = base_path.get_base_dir().path_join(ext_path);
}
}
} else if (c->extends.size() != 0) {
- const StringName &base = c->extends[0];
+ const StringName &base_class = c->extends[0];
- if (ScriptServer::is_global_class(base)) {
- path = ScriptServer::get_global_class_path(base);
+ if (ScriptServer::is_global_class(base_class)) {
+ ext_path = ScriptServer::get_global_class_path(base_class);
}
}
- if (!path.is_empty()) {
- if (path != get_path()) {
- Ref<GDScript> bf = ResourceLoader::load(path);
+ if (!ext_path.is_empty()) {
+ if (ext_path != get_path()) {
+ Ref<GDScript> bf = ResourceLoader::load(ext_path);
if (bf.is_valid()) {
base_cache = bf;
bf->inheriters_cache.insert(get_instance_id());
}
} else {
- ERR_PRINT(("Path extending itself in " + path).utf8().get_data());
+ ERR_PRINT(("Path extending itself in " + ext_path).utf8().get_data());
}
}
}
@@ -843,7 +843,7 @@ String GDScript::_get_debug_path() const {
Error GDScript::reload(bool p_keep_state) {
bool has_instances;
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
has_instances = instances.size();
}
@@ -1050,6 +1050,11 @@ Error GDScript::load_byte_code(const String &p_path) {
return ERR_COMPILATION_FAILED;
}
+void GDScript::set_path(const String &p_path, bool p_take_over) {
+ Script::set_path(p_path, p_take_over);
+ this->path = p_path;
+}
+
Error GDScript::load_source_code(const String &p_path) {
Vector<uint8_t> sourcef;
Error err;
@@ -1187,7 +1192,7 @@ GDScript::GDScript() :
script_list(this) {
#ifdef DEBUG_ENABLED
{
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->script_list.add(&script_list);
}
@@ -1258,7 +1263,7 @@ void GDScript::_init_rpc_methods_properties() {
GDScript::~GDScript() {
{
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
// Order matters since clearing the stack may already cause
@@ -1295,7 +1300,7 @@ GDScript::~GDScript() {
#ifdef DEBUG_ENABLED
{
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->script_list.remove(&script_list);
}
@@ -1722,7 +1727,7 @@ GDScriptInstance::GDScriptInstance() {
}
GDScriptInstance::~GDScriptInstance() {
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
while (SelfList<GDScriptFunctionState> *E = pending_func_states.first()) {
// Order matters since clearing the stack may already cause
@@ -1825,7 +1830,7 @@ void GDScriptLanguage::finish() {
void GDScriptLanguage::profiling_start() {
#ifdef DEBUG_ENABLED
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
@@ -1847,7 +1852,7 @@ void GDScriptLanguage::profiling_start() {
void GDScriptLanguage::profiling_stop() {
#ifdef DEBUG_ENABLED
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
profiling = false;
#endif
@@ -1857,7 +1862,7 @@ int GDScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr,
int current = 0;
#ifdef DEBUG_ENABLED
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
@@ -1880,7 +1885,7 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_
int current = 0;
#ifdef DEBUG_ENABLED
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
@@ -1926,7 +1931,7 @@ void GDScriptLanguage::reload_all_scripts() {
print_verbose("GDScript: Reloading all scripts");
List<Ref<GDScript>> scripts;
{
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScript> *elem = script_list.first();
while (elem) {
@@ -1942,10 +1947,10 @@ void GDScriptLanguage::reload_all_scripts() {
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
- for (Ref<GDScript> &script : scripts) {
- print_verbose("GDScript: Reloading: " + script->get_path());
- script->load_source_code(script->get_path());
- script->reload(true);
+ for (Ref<GDScript> &scr : scripts) {
+ print_verbose("GDScript: Reloading: " + scr->get_path());
+ scr->load_source_code(scr->get_path());
+ scr->reload(true);
}
#endif
}
@@ -1955,7 +1960,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
List<Ref<GDScript>> scripts;
{
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScript> *elem = script_list.first();
while (elem) {
@@ -1974,21 +1979,21 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
- for (Ref<GDScript> &script : scripts) {
- bool reload = script == p_script || to_reload.has(script->get_base());
+ for (Ref<GDScript> &scr : scripts) {
+ bool reload = scr == p_script || to_reload.has(scr->get_base());
if (!reload) {
continue;
}
- to_reload.insert(script, HashMap<ObjectID, List<Pair<StringName, Variant>>>());
+ to_reload.insert(scr, HashMap<ObjectID, List<Pair<StringName, Variant>>>());
if (!p_soft_reload) {
//save state and remove script from instances
- HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script];
+ HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[scr];
- while (script->instances.front()) {
- Object *obj = script->instances.front()->get();
+ while (scr->instances.front()) {
+ Object *obj = scr->instances.front()->get();
//save instance info
List<Pair<StringName, Variant>> state;
if (obj->get_script_instance()) {
@@ -2001,8 +2006,8 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//same thing for placeholders
#ifdef TOOLS_ENABLED
- while (script->placeholders.size()) {
- Object *obj = (*script->placeholders.begin())->get_owner();
+ while (scr->placeholders.size()) {
+ Object *obj = (*scr->placeholders.begin())->get_owner();
//save instance info
if (obj->get_script_instance()) {
@@ -2012,13 +2017,13 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
obj->set_script(Variant());
} else {
// no instance found. Let's remove it so we don't loop forever
- script->placeholders.erase(*script->placeholders.begin());
+ scr->placeholders.erase(*scr->placeholders.begin());
}
}
#endif
- for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : script->pending_reload_state) {
+ for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : scr->pending_reload_state) {
map[F.key] = F.value; //pending to reload, use this one instead
}
}
@@ -2043,9 +2048,9 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
}
obj->set_script(scr);
- ScriptInstance *script_instance = obj->get_script_instance();
+ ScriptInstance *script_inst = obj->get_script_instance();
- if (!script_instance) {
+ if (!script_inst) {
//failed, save reload state for next time if not saved
if (!scr->pending_reload_state.has(obj->get_instance_id())) {
scr->pending_reload_state[obj->get_instance_id()] = saved_state;
@@ -2053,14 +2058,14 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
continue;
}
- if (script_instance->is_placeholder() && scr->is_placeholder_fallback_enabled()) {
- PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_instance);
+ if (script_inst->is_placeholder() && scr->is_placeholder_fallback_enabled()) {
+ PlaceHolderScriptInstance *placeholder = static_cast<PlaceHolderScriptInstance *>(script_inst);
for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
placeholder->property_set_fallback(G->get().first, G->get().second);
}
} else {
for (List<Pair<StringName, Variant>>::Element *G = saved_state.front(); G; G = G->next()) {
- script_instance->set(G->get().first, G->get().second);
+ script_inst->set(G->get().first, G->get().second);
}
}
@@ -2078,7 +2083,7 @@ void GDScriptLanguage::frame() {
#ifdef DEBUG_ENABLED
if (profiling) {
- MutexLock lock(this->lock);
+ MutexLock lock(this->mutex);
SelfList<GDScriptFunction> *elem = function_list.first();
while (elem) {
@@ -2339,26 +2344,26 @@ GDScriptLanguage::~GDScriptLanguage() {
// Clear dependencies between scripts, to ensure cyclic references are broken (to avoid leaks at exit).
SelfList<GDScript> *s = script_list.first();
while (s) {
- GDScript *script = s->self();
+ GDScript *scr = s->self();
// This ensures the current script is not released before we can check what's the next one
// in the list (we can't get the next upfront because we don't know if the reference breaking
// will cause it -or any other after it, for that matter- to be released so the next one
// is not the same as before).
- script->reference();
+ scr->reference();
- for (KeyValue<StringName, GDScriptFunction *> &E : script->member_functions) {
+ for (KeyValue<StringName, GDScriptFunction *> &E : scr->member_functions) {
GDScriptFunction *func = E.value;
for (int i = 0; i < func->argument_types.size(); i++) {
func->argument_types.write[i].script_type_ref = Ref<Script>();
}
func->return_type.script_type_ref = Ref<Script>();
}
- for (KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
+ for (KeyValue<StringName, GDScript::MemberInfo> &E : scr->member_indices) {
E.value.data_type.script_type_ref = Ref<Script>();
}
s = s->next();
- script->unreference();
+ scr->unreference();
}
singleton = nullptr;
@@ -2390,20 +2395,20 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
}
Error err;
- Ref<GDScript> script = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
+ Ref<GDScript> scr = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
// TODO: Reintroduce binary and encrypted scripts.
- if (script.is_null()) {
+ if (scr.is_null()) {
// Don't fail loading because of parsing error.
- script.instantiate();
+ scr.instantiate();
}
if (r_error) {
*r_error = OK;
}
- return script;
+ return scr;
}
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index e4b12d4ddb..72ad890fbc 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -222,6 +222,7 @@ public:
virtual Error reload(bool p_keep_state = false) override;
+ virtual void set_path(const String &p_path, bool p_take_over = false) override;
void set_script_path(const String &p_path) { path = p_path; } //because subclasses need a path too...
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);
@@ -342,7 +343,7 @@ class GDScriptLanguage : public ScriptLanguage {
friend class GDScriptInstance;
- Mutex lock;
+ Mutex mutex;
friend class GDScript;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 32d9aec84f..704dda8045 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -262,19 +262,19 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
if (p_class->extends_path.is_relative_path()) {
p_class->extends_path = class_type.script_path.get_base_dir().path_join(p_class->extends_path).simplify_path();
}
- Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path);
- if (parser.is_null()) {
+ Ref<GDScriptParserRef> ext_parser = get_parser_for(p_class->extends_path);
+ if (ext_parser.is_null()) {
push_error(vformat(R"(Could not resolve super class path "%s".)", p_class->extends_path), p_class);
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = ext_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", p_class->extends_path), p_class);
return err;
}
- base = parser->get_parser()->head->get_datatype();
+ base = ext_parser->get_parser()->head->get_datatype();
} else {
if (p_class->extends.is_empty()) {
push_error("Could not resolve an empty super class path.", p_class);
@@ -289,18 +289,18 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
if (base_path == parser->script_path) {
base = parser->head->get_datatype();
} else {
- Ref<GDScriptParserRef> parser = get_parser_for(base_path);
- if (parser.is_null()) {
+ Ref<GDScriptParserRef> base_parser = get_parser_for(base_path);
+ if (base_parser.is_null()) {
push_error(vformat(R"(Could not resolve super class "%s".)", name), p_class);
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = base_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
- base = parser->get_parser()->head->get_datatype();
+ base = base_parser->get_parser()->head->get_datatype();
}
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
@@ -309,13 +309,13 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Ref<GDScriptParserRef> parser = get_parser_for(info.path);
- if (parser.is_null()) {
+ Ref<GDScriptParserRef> info_parser = get_parser_for(info.path);
+ if (info_parser.is_null()) {
push_error(vformat(R"(Could not parse singleton from "%s".)", info.path), p_class);
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Error err = info_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
@@ -985,21 +985,26 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
if (getter_function == nullptr) {
push_error(vformat(R"(Getter "%s" not found.)", member.variable->getter_pointer->name), member.variable);
-
- } else if (getter_function->parameters.size() != 0 || getter_function->datatype.has_no_type()) {
- push_error(vformat(R"(Function "%s" cannot be used as getter because of its signature.)", getter_function->identifier->name), member.variable);
-
- } else if (!is_type_compatible(member.variable->datatype, getter_function->datatype, true)) {
- push_error(vformat(R"(Function with return type "%s" cannot be used as getter for a property of type "%s".)", getter_function->datatype.to_string(), member.variable->datatype.to_string()), member.variable);
-
} else {
- has_valid_getter = true;
+ GDScriptParser::DataType return_datatype = getter_function->datatype;
+ if (getter_function->return_type != nullptr) {
+ return_datatype = getter_function->return_type->datatype;
+ return_datatype.is_meta_type = false;
+ }
+
+ if (getter_function->parameters.size() != 0 || return_datatype.has_no_type()) {
+ push_error(vformat(R"(Function "%s" cannot be used as getter because of its signature.)", getter_function->identifier->name), member.variable);
+ } else if (!is_type_compatible(member.variable->datatype, return_datatype, true)) {
+ push_error(vformat(R"(Function with return type "%s" cannot be used as getter for a property of type "%s".)", return_datatype.to_string(), member.variable->datatype.to_string()), member.variable);
+ } else {
+ has_valid_getter = true;
#ifdef DEBUG_ENABLED
- if (member.variable->datatype.builtin_type == Variant::INT && getter_function->datatype.builtin_type == Variant::FLOAT) {
- parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
- }
+ if (member.variable->datatype.builtin_type == Variant::INT && return_datatype.builtin_type == Variant::FLOAT) {
+ parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
+ }
#endif
+ }
}
}
@@ -1041,7 +1046,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
}
-void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
+void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node, bool p_is_root) {
ERR_FAIL_COND_MSG(p_node == nullptr, "Trying to resolve type of a null node.");
switch (p_node->type) {
@@ -1114,7 +1119,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
case GDScriptParser::Node::SUBSCRIPT:
case GDScriptParser::Node::TERNARY_OPERATOR:
case GDScriptParser::Node::UNARY_OPERATOR:
- reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node), true);
+ reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node), p_is_root);
break;
case GDScriptParser::Node::BREAK:
case GDScriptParser::Node::BREAKPOINT:
@@ -1377,7 +1382,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
if (all_is_constant) {
switch (args.size()) {
case 1:
- reduced = args[0];
+ reduced = (int32_t)args[0];
break;
case 2:
reduced = Vector2i(args[0], args[1]);
@@ -1411,7 +1416,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else?
p_for->variable->set_datatype(variable_type);
} else if (p_for->list) {
- resolve_node(p_for->list);
+ resolve_node(p_for->list, false);
if (p_for->list->datatype.has_container_element_type()) {
variable_type = p_for->list->datatype.get_container_element_type();
variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
@@ -1439,7 +1444,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
}
void GDScriptAnalyzer::resolve_while(GDScriptParser::WhileNode *p_while) {
- resolve_node(p_while->condition);
+ resolve_node(p_while->condition, false);
resolve_suite(p_while->loop);
p_while->set_datatype(p_while->loop->get_datatype());
@@ -1602,8 +1607,8 @@ void GDScriptAnalyzer::resolve_assert(GDScriptParser::AssertNode *p_assert) {
reduce_expression(p_assert->condition);
if (p_assert->message != nullptr) {
reduce_expression(p_assert->message);
- if (!p_assert->message->is_constant || p_assert->message->reduced_value.get_type() != Variant::STRING) {
- push_error(R"(Expected constant string for assert error message.)", p_assert->message);
+ if (!p_assert->message->get_datatype().has_no_type() && (p_assert->message->get_datatype().kind != GDScriptParser::DataType::BUILTIN || p_assert->message->get_datatype().builtin_type != Variant::STRING)) {
+ push_error(R"(Expected string for assert error message.)", p_assert->message);
}
}
@@ -1824,7 +1829,7 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
reduce_binary_op(static_cast<GDScriptParser::BinaryOpNode *>(p_expression));
break;
case GDScriptParser::Node::CALL:
- reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression), p_is_root);
+ reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression), false, p_is_root);
break;
case GDScriptParser::Node::CAST:
reduce_cast(static_cast<GDScriptParser::CastNode *>(p_expression));
@@ -2425,9 +2430,15 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
switch (err.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT: {
- PropertyInfo wrong_arg = function_info.arguments[err.argument];
+ String expected_type_name;
+ if (err.argument < function_info.arguments.size()) {
+ expected_type_name = type_from_property(function_info.arguments[err.argument]).to_string();
+ } else {
+ expected_type_name = Variant::get_type_name((Variant::Type)err.expected);
+ }
+
push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be %s but is %s.)*", function_name, err.argument + 1,
- type_from_property(wrong_arg).to_string(), p_call->arguments[err.argument]->get_datatype().to_string()),
+ expected_type_name, p_call->arguments[err.argument]->get_datatype().to_string()),
p_call->arguments[err.argument]);
} break;
case Callable::CallError::CALL_ERROR_INVALID_METHOD:
@@ -2548,6 +2559,16 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
mark_lambda_use_self();
}
+#ifdef DEBUG_ENABLED
+ if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
+ parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
+ }
+
+ if (is_static && !base_type.is_meta_type && !(callee_type != GDScriptParser::Node::SUBSCRIPT && parser->current_function != nullptr && parser->current_function->is_static)) {
+ parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, base_type.to_string());
+ }
+#endif // DEBUG_ENABLED
+
call_type = return_type;
} else {
bool found = false;
@@ -3093,11 +3114,11 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
result.kind = GDScriptParser::DataType::NATIVE;
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
if (autoload.path.to_lower().ends_with(GDScriptLanguage::get_singleton()->get_extension())) {
- Ref<GDScriptParserRef> parser = get_parser_for(autoload.path);
- if (parser.is_valid()) {
- Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ Ref<GDScriptParserRef> singl_parser = get_parser_for(autoload.path);
+ if (singl_parser.is_valid()) {
+ Error err = singl_parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err == OK) {
- result = type_from_metatype(parser->get_parser()->head->get_datatype());
+ result = type_from_metatype(singl_parser->get_parser()->head->get_datatype());
}
}
}
@@ -3216,7 +3237,13 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
}
p_preload->resolved_path = p_preload->resolved_path.simplify_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);
+ Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+
+ if (file_check->file_exists(p_preload->resolved_path)) {
+ push_error(vformat(R"(Preload file "%s" has no resource loaders (unrecognized file extension).)", p_preload->resolved_path), p_preload->path);
+ } else {
+ 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.
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 3966b81b6e..217a856ce0 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -63,7 +63,7 @@ class GDScriptAnalyzer {
void resolve_class_body(GDScriptParser::ClassNode *p_class);
void resolve_function_signature(GDScriptParser::FunctionNode *p_function);
void resolve_function_body(GDScriptParser::FunctionNode *p_function);
- void resolve_node(GDScriptParser::Node *p_node);
+ void resolve_node(GDScriptParser::Node *p_node, bool p_is_root = true);
void resolve_suite(GDScriptParser::SuiteNode *p_suite);
void resolve_if(GDScriptParser::IfNode *p_if);
void resolve_for(GDScriptParser::ForNode *p_for);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index fd418ced47..7acd1cdb96 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -522,11 +522,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Create temporary for result first since it will be deleted last.
GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type);
- GDScriptCodeGenerator::Address source = _parse_expression(codegen, r_error, cn->operand);
+ GDScriptCodeGenerator::Address src = _parse_expression(codegen, r_error, cn->operand);
- gen->write_cast(result, source, cast_type);
+ gen->write_cast(result, src, cast_type);
- if (source.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ if (src.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
@@ -1650,7 +1650,7 @@ void GDScriptCompiler::_add_locals_in_block(CodeGen &codegen, const GDScriptPars
}
Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals) {
- Error error = OK;
+ Error err = OK;
GDScriptCodeGenerator *gen = codegen.generator;
codegen.start_block();
@@ -1676,9 +1676,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
// Evaluate the match expression.
GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype()));
- GDScriptCodeGenerator::Address value_expr = _parse_expression(codegen, error, match->test);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address value_expr = _parse_expression(codegen, err, match->test);
+ if (err) {
+ return err;
}
// Assign to local.
@@ -1723,9 +1723,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
// For each pattern in branch.
GDScriptCodeGenerator::Address pattern_result = codegen.add_temporary();
for (int k = 0; k < branch->patterns.size(); k++) {
- pattern_result = _parse_match_pattern(codegen, error, branch->patterns[k], value, type, pattern_result, k == 0, false);
- if (error != OK) {
- return error;
+ pattern_result = _parse_match_pattern(codegen, err, branch->patterns[k], value, type, pattern_result, k == 0, false);
+ if (err != OK) {
+ return err;
}
}
@@ -1736,9 +1736,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->pop_temporary();
// Parse the branch block.
- error = _parse_block(codegen, branch->block, false); // Don't add locals again.
- if (error) {
- return error;
+ err = _parse_block(codegen, branch->block, false); // Don't add locals again.
+ if (err) {
+ return err;
}
codegen.end_block(); // Get out of extra block.
@@ -1753,9 +1753,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
} break;
case GDScriptParser::Node::IF: {
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
- GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, if_n->condition);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, if_n->condition);
+ if (err) {
+ return err;
}
gen->write_if(condition);
@@ -1764,17 +1764,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.generator->pop_temporary();
}
- error = _parse_block(codegen, if_n->true_block);
- if (error) {
- return error;
+ err = _parse_block(codegen, if_n->true_block);
+ if (err) {
+ return err;
}
if (if_n->false_block) {
gen->write_else();
- error = _parse_block(codegen, if_n->false_block);
- if (error) {
- return error;
+ err = _parse_block(codegen, if_n->false_block);
+ if (err) {
+ return err;
}
}
@@ -1788,9 +1788,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->start_for(iterator.type, _gdtype_from_datatype(for_n->list->get_datatype()));
- GDScriptCodeGenerator::Address list = _parse_expression(codegen, error, for_n->list);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address list = _parse_expression(codegen, err, for_n->list);
+ if (err) {
+ return err;
}
gen->write_for_assignment(iterator, list);
@@ -1801,9 +1801,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->write_for();
- error = _parse_block(codegen, for_n->loop);
- if (error) {
- return error;
+ err = _parse_block(codegen, for_n->loop);
+ if (err) {
+ return err;
}
gen->write_endfor();
@@ -1815,9 +1815,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
gen->start_while_condition();
- GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, while_n->condition);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition);
+ if (err) {
+ return err;
}
gen->write_while(condition);
@@ -1826,9 +1826,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.generator->pop_temporary();
}
- error = _parse_block(codegen, while_n->loop);
- if (error) {
- return error;
+ err = _parse_block(codegen, while_n->loop);
+ if (err) {
+ return err;
}
gen->write_endwhile();
@@ -1850,9 +1850,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
GDScriptCodeGenerator::Address return_value;
if (return_n->return_value != nullptr) {
- return_value = _parse_expression(codegen, error, return_n->return_value);
- if (error) {
- return error;
+ return_value = _parse_expression(codegen, err, return_n->return_value);
+ if (err) {
+ return err;
}
}
@@ -1865,17 +1865,17 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
#ifdef DEBUG_ENABLED
const GDScriptParser::AssertNode *as = static_cast<const GDScriptParser::AssertNode *>(s);
- GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, as->condition);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, as->condition);
+ if (err) {
+ return err;
}
GDScriptCodeGenerator::Address message;
if (as->message) {
- message = _parse_expression(codegen, error, as->message);
- if (error) {
- return error;
+ message = _parse_expression(codegen, err, as->message);
+ if (err) {
+ return err;
}
}
gen->write_assert(condition, message);
@@ -1908,9 +1908,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
codegen.generator->write_construct_array(local, Vector<GDScriptCodeGenerator::Address>());
}
}
- GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, err, lv->initializer);
+ if (err) {
+ return err;
}
if (lv->use_conversion_assign) {
gen->write_assign_with_conversion(local, src_address);
@@ -1946,9 +1946,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
default: {
// Expression.
if (s->is_expression()) {
- GDScriptCodeGenerator::Address expr = _parse_expression(codegen, error, static_cast<const GDScriptParser::ExpressionNode *>(s), true);
- if (error) {
- return error;
+ GDScriptCodeGenerator::Address expr = _parse_expression(codegen, err, static_cast<const GDScriptParser::ExpressionNode *>(s), true);
+ if (err) {
+ return err;
}
if (expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
codegen.generator->pop_temporary();
@@ -2180,7 +2180,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
}
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
- Error error = OK;
+ Error err = OK;
GDScriptParser::FunctionNode *function;
@@ -2190,9 +2190,9 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
function = p_variable->getter;
}
- _parse_function(error, p_script, p_class, function);
+ _parse_function(err, p_script, p_class, function);
- return error;
+ return err;
}
Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 4841884e2d..e4264ea55b 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -81,10 +81,10 @@ class GDScriptCompiler {
type.kind = GDScriptDataType::NATIVE;
type.native_type = obj->get_class_name();
- Ref<Script> script = obj->get_script();
- if (script.is_valid()) {
- type.script_type = script.ptr();
- Ref<GDScript> gdscript = script;
+ Ref<Script> scr = obj->get_script();
+ if (scr.is_valid()) {
+ type.script_type = scr.ptr();
+ Ref<GDScript> gdscript = scr;
if (gdscript.is_valid()) {
type.kind = GDScriptDataType::GDSCRIPT;
} else {
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index b38c7c6699..b5a209c805 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -104,10 +104,10 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
text += ": ";
// This makes the compiler complain if some opcode is unchecked in the switch.
- Opcode code = Opcode(_code_ptr[ip] & INSTR_MASK);
+ Opcode opcode = Opcode(_code_ptr[ip] & INSTR_MASK);
int instr_var_args = (_code_ptr[ip] & INSTR_ARGS_MASK) >> INSTR_BITS;
- switch (code) {
+ switch (opcode) {
case OPCODE_OPERATOR: {
int operation = _code_ptr[ip + 4];
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index c00036c9f0..f33d1409bc 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -61,8 +61,8 @@ bool GDScriptLanguage::is_using_templates() {
}
Ref<Script> GDScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
- Ref<GDScript> script;
- script.instantiate();
+ Ref<GDScript> scr;
+ scr.instantiate();
String processed_template = p_template;
bool type_hints = false;
#ifdef TOOLS_ENABLED
@@ -82,8 +82,8 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
processed_template = processed_template.replace("_BASE_", p_base_class_name)
.replace("_CLASS_", p_class_name)
.replace("_TS_", _get_indentation());
- script->set_source_code(processed_template);
- return script;
+ scr->set_source_code(processed_template);
+ return scr;
}
Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) {
@@ -318,10 +318,10 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
return;
}
- Ref<GDScript> script = instance->get_script();
- ERR_FAIL_COND(script.is_null());
+ Ref<GDScript> scr = instance->get_script();
+ ERR_FAIL_COND(scr.is_null());
- const HashMap<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices();
+ const HashMap<StringName, GDScript::MemberInfo> &mi = scr->debug_get_member_indices();
for (const KeyValue<StringName, GDScript::MemberInfo> &E : mi) {
p_members->push_back(E.key);
@@ -344,7 +344,7 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
const HashMap<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
- const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
+ const Variant *gl_array = GDScriptLanguage::get_singleton()->get_global_array();
List<Pair<String, Variant>> cinfo;
get_public_constants(&cinfo);
@@ -365,7 +365,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
continue;
}
- const Variant &var = globals[E.value];
+ const Variant &var = gl_array[E.value];
if (Object *obj = var) {
if (Object::cast_to<GDScriptNativeClass>(obj)) {
continue;
@@ -766,7 +766,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
ScriptLanguage::CodeCompletionOption slider2("or_less", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider2.insert_text = slider2.display.quote(p_quote_style);
r_result.insert(slider2.display, slider2);
- ScriptLanguage::CodeCompletionOption slider3("no_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption slider3("hide_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider3.insert_text = slider3.display.quote(p_quote_style);
r_result.insert(slider3.display, slider3);
}
@@ -1205,8 +1205,8 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
_find_built_in_variants(r_result);
static const char *_keywords[] = {
- "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
- "break", "continue", "pass", "return",
+ "true", "false", "PI", "TAU", "INF", "NAN", "null", "self", "super",
+ "break", "breakpoint", "continue", "pass", "return",
nullptr
};
@@ -1218,7 +1218,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
}
static const char *_keywords_with_space[] = {
- "and", "in", "not", "or", "as", "class", "extends", "is", "func", "signal", "await",
+ "and", "not", "or", "in", "as", "class", "class_name", "extends", "is", "func", "signal", "await",
"const", "enum", "static", "var", "if", "elif", "else", "for", "match", "while",
nullptr
};
@@ -2513,7 +2513,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
if (p_call->type == GDScriptParser::Node::PRELOAD) {
- if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
+ if (p_argidx == 0 && bool(EDITOR_GET("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
}
@@ -2820,7 +2820,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_forced = true;
} break;
case GDScriptParser::COMPLETION_RESOURCE_PATH: {
- if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths")) {
+ if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);
r_forced = true;
}
@@ -3302,17 +3302,17 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) {
const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(p_symbol);
if (autoload.is_singleton) {
- String script = autoload.path;
- if (!script.ends_with(".gd")) {
+ String scr_path = autoload.path;
+ if (!scr_path.ends_with(".gd")) {
// Not a script, try find the script anyway,
// may have some success.
- script = script.get_basename() + ".gd";
+ scr_path = scr_path.get_basename() + ".gd";
}
- if (FileAccess::exists(script)) {
+ if (FileAccess::exists(scr_path)) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_SCRIPT_LOCATION;
r_result.location = 0;
- r_result.script = ResourceLoader::load(script);
+ r_result.script = ResourceLoader::load(scr_path);
return OK;
}
}
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index cd3b7d69c5..98b3e40f1b 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -142,7 +142,7 @@ GDScriptFunction::GDScriptFunction() {
name = "<anonymous>";
#ifdef DEBUG_ENABLED
{
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->function_list.add(&function_list);
}
#endif
@@ -155,7 +155,7 @@ GDScriptFunction::~GDScriptFunction() {
#ifdef DEBUG_ENABLED
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
#endif
@@ -201,7 +201,7 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
}
if (p_extended_check) {
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
// Script gone?
if (!scripts_list.in_list()) {
@@ -219,7 +219,7 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
Variant GDScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
if (!scripts_list.in_list()) {
#ifdef DEBUG_ENABLED
@@ -304,7 +304,7 @@ GDScriptFunctionState::GDScriptFunctionState() :
GDScriptFunctionState::~GDScriptFunctionState() {
{
- MutexLock lock(GDScriptLanguage::singleton->lock);
+ MutexLock lock(GDScriptLanguage::singleton->mutex);
scripts_list.remove_from_list();
instances_list.remove_from_list();
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 980a946e23..4279edf394 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3765,13 +3765,19 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
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.)");
+ if (ClassDB::is_parent_class(export_type.native_type, SNAME("Resource"))) {
+ 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;
+ } else if (ClassDB::is_parent_class(export_type.native_type, SNAME("Node"))) {
+ variable->export_info.type = Variant::OBJECT;
+ variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
+ variable->export_info.hint_string = export_type.class_type->identifier->name;
+ } else {
+ push_error(R"(Export type can only be built-in, a resource, a node or an enum.)", variable);
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;
@@ -3953,28 +3959,22 @@ GDScriptParser::DataType GDScriptParser::SuiteNode::Local::get_datatype() const
}
String GDScriptParser::SuiteNode::Local::get_name() const {
- String name;
switch (type) {
case SuiteNode::Local::PARAMETER:
- name = "parameter";
- break;
+ return "parameter";
case SuiteNode::Local::CONSTANT:
- name = "constant";
- break;
+ return "constant";
case SuiteNode::Local::VARIABLE:
- name = "variable";
- break;
+ return "variable";
case SuiteNode::Local::FOR_VARIABLE:
- name = "for loop iterator";
- break;
+ return "for loop iterator";
case SuiteNode::Local::PATTERN_BIND:
- name = "pattern_bind";
- break;
+ return "pattern_bind";
case SuiteNode::Local::UNDEFINED:
- name = "<undefined>";
- break;
+ return "<undefined>";
+ default:
+ return String();
}
- return name;
}
String GDScriptParser::DataType::to_string() const {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index d4efab173b..f40887ddb8 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -469,7 +469,7 @@ public:
EnumNode *parent_enum = nullptr;
int index = -1;
bool resolved = false;
- int value = 0;
+ int64_t value = 0;
int line = 0;
int leftmost_column = 0;
int rightmost_column = 0;
@@ -578,19 +578,19 @@ public:
return m_enum->get_datatype();
case ENUM_VALUE: {
// Always integer.
- DataType type;
- type.type_source = DataType::ANNOTATED_EXPLICIT;
- type.kind = DataType::BUILTIN;
- type.builtin_type = Variant::INT;
- return type;
+ DataType out_type;
+ out_type.type_source = DataType::ANNOTATED_EXPLICIT;
+ out_type.kind = DataType::BUILTIN;
+ out_type.builtin_type = Variant::INT;
+ return out_type;
}
case SIGNAL: {
- DataType type;
- type.type_source = DataType::ANNOTATED_EXPLICIT;
- type.kind = DataType::BUILTIN;
- type.builtin_type = Variant::SIGNAL;
+ DataType out_type;
+ out_type.type_source = DataType::ANNOTATED_EXPLICIT;
+ out_type.kind = DataType::BUILTIN;
+ out_type.builtin_type = Variant::SIGNAL;
// TODO: Add parameter info.
- return type;
+ return out_type;
}
case GROUP: {
return DataType();
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 6c17afe939..9bbfd7aece 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -516,15 +516,15 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
_advance();
}
- int length = _current - _start;
+ int len = _current - _start;
- if (length == 1 && _peek(-1) == '_') {
+ if (len == 1 && _peek(-1) == '_') {
// Lone underscore.
return make_token(Token::UNDERSCORE);
}
- String name(_start, length);
- if (length < MIN_KEYWORD_LENGTH || length > MAX_KEYWORD_LENGTH) {
+ String name(_start, len);
+ if (len < MIN_KEYWORD_LENGTH || len > MAX_KEYWORD_LENGTH) {
// Cannot be a keyword, as the length doesn't match any.
return make_identifier(name);
}
@@ -538,7 +538,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
const int keyword_length = sizeof(keyword) - 1; \
static_assert(keyword_length <= MAX_KEYWORD_LENGTH, "There's a keyword longer than the defined maximum length"); \
static_assert(keyword_length >= MIN_KEYWORD_LENGTH, "There's a keyword shorter than the defined minimum length"); \
- if (keyword_length == length && name == keyword) { \
+ if (keyword_length == len && name == keyword) { \
return make_token(token_type); \
} \
}
@@ -551,13 +551,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::potential_identifier() {
}
// Check if it's a special literal
- if (length == 4) {
+ if (len == 4) {
if (name == "true") {
return make_literal(true);
} else if (name == "null") {
return make_literal(Variant());
}
- } else if (length == 5) {
+ } else if (len == 5) {
if (name == "false") {
return make_literal(false);
}
@@ -725,8 +725,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
}
// Create a string with the whole number.
- int length = _current - _start;
- String number = String(_start, length).replace("_", "");
+ int len = _current - _start;
+ String number = String(_start, len).replace("_", "");
// Convert to the appropriate literal type.
if (base == 16) {
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index afebe3c149..c73ba798aa 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -2216,7 +2216,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->state.line = line;
gdfs->state.script = _script;
{
- MutexLock lock(GDScriptLanguage::get_singleton()->lock);
+ MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
_script->pending_func_states.add(&gdfs->scripts_list);
if (p_instance) {
gdfs->state.instance = p_instance;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 1cae7bdfac..a0c107aa53 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -155,6 +155,10 @@ String GDScriptWarning::get_message() const {
case INT_ASSIGNED_TO_ENUM: {
return "Integer used when an enum value is expected. If this is intended cast the integer to the enum type.";
}
+ case STATIC_CALLED_ON_INSTANCE: {
+ CHECK_SYMBOLS(2);
+ return vformat(R"(The function '%s()' is a static function but was called from an instance. Instead, it should be directly called from the type: '%s.%s()'.)", symbols[0], symbols[1], symbols[0]);
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -215,6 +219,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"EMPTY_FILE",
"SHADOWED_GLOBAL_IDENTIFIER",
"INT_ASSIGNED_TO_ENUM",
+ "STATIC_CALLED_ON_INSTANCE",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index a639e7b44e..7e4e975510 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -78,6 +78,7 @@ public:
EMPTY_FILE, // A script file is empty.
SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
INT_ASSIGNED_TO_ENUM, // An integer value was assigned to an enum-typed variable without casting.
+ STATIC_CALLED_ON_INSTANCE, // A static method was called on an instance of a class instead of on the class itself.
WARNING_MAX,
};
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 46a9b33eb0..de3becbaf8 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -38,8 +38,8 @@
void ExtendGDScriptParser::update_diagnostics() {
diagnostics.clear();
- const List<ParserError> &errors = get_errors();
- for (const ParserError &error : errors) {
+ const List<ParserError> &parser_errors = get_errors();
+ for (const ParserError &error : parser_errors) {
lsp::Diagnostic diagnostic;
diagnostic.severity = lsp::DiagnosticSeverity::Error;
diagnostic.message = error.message;
@@ -47,9 +47,9 @@ void ExtendGDScriptParser::update_diagnostics() {
diagnostic.code = -1;
lsp::Range range;
lsp::Position pos;
- const PackedStringArray lines = get_lines();
- int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, lines.size() - 1);
- const String &line_text = lines[line];
+ const PackedStringArray line_array = get_lines();
+ int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, line_array.size() - 1);
+ const String &line_text = line_array[line];
pos.line = line;
pos.character = line_text.length() - line_text.strip_edges(true, false).length();
range.start = pos;
@@ -59,8 +59,8 @@ void ExtendGDScriptParser::update_diagnostics() {
diagnostics.push_back(diagnostic);
}
- const List<GDScriptWarning> &warnings = get_warnings();
- for (const GDScriptWarning &warning : warnings) {
+ const List<GDScriptWarning> &parser_warnings = get_warnings();
+ for (const GDScriptWarning &warning : parser_warnings) {
lsp::Diagnostic diagnostic;
diagnostic.severity = lsp::DiagnosticSeverity::Warning;
diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message();
@@ -83,8 +83,7 @@ void ExtendGDScriptParser::update_diagnostics() {
void ExtendGDScriptParser::update_symbols() {
members.clear();
- const GDScriptParser::Node *head = get_tree();
- if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
+ if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(get_tree())) {
parse_class_symbol(gdclass, class_symbol);
for (int i = 0; i < class_symbol.children.size(); i++) {
@@ -107,26 +106,26 @@ void ExtendGDScriptParser::update_symbols() {
void ExtendGDScriptParser::update_document_links(const String &p_code) {
document_links.clear();
- GDScriptTokenizer tokenizer;
+ GDScriptTokenizer scr_tokenizer;
Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- tokenizer.set_source_code(p_code);
+ scr_tokenizer.set_source_code(p_code);
while (true) {
- GDScriptTokenizer::Token token = tokenizer.scan();
+ GDScriptTokenizer::Token token = scr_tokenizer.scan();
if (token.type == GDScriptTokenizer::Token::TK_EOF) {
break;
} else if (token.type == GDScriptTokenizer::Token::LITERAL) {
const Variant &const_val = token.literal;
if (const_val.get_type() == Variant::STRING) {
- String path = const_val;
- bool exists = fs->file_exists(path);
+ String scr_path = const_val;
+ bool exists = fs->file_exists(scr_path);
if (!exists) {
- path = get_path().get_base_dir() + "/" + path;
- exists = fs->file_exists(path);
+ scr_path = get_path().get_base_dir() + "/" + scr_path;
+ exists = fs->file_exists(scr_path);
}
if (exists) {
String value = const_val;
lsp::DocumentLink link;
- link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path);
+ link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(scr_path);
link.range.start.line = LINE_NUMBER_TO_INDEX(token.start_line);
link.range.end.line = LINE_NUMBER_TO_INDEX(token.end_line);
link.range.start.character = LINE_NUMBER_TO_INDEX(token.start_column);
@@ -437,11 +436,11 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
if (!p_docs_down) { // inline comment
String inline_comment = lines[p_line];
- int comment_start = inline_comment.find("#");
+ int comment_start = inline_comment.find("##");
if (comment_start != -1) {
inline_comment = inline_comment.substr(comment_start, inline_comment.length()).strip_edges();
if (inline_comment.length() > 1) {
- doc_lines.push_back(inline_comment.substr(1, inline_comment.length()));
+ doc_lines.push_back(inline_comment.substr(2, inline_comment.length()));
}
}
}
@@ -454,8 +453,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
}
String line_comment = lines[i].strip_edges(true, false);
- if (line_comment.begins_with("#")) {
- line_comment = line_comment.substr(1, line_comment.length());
+ if (line_comment.begins_with("##")) {
+ line_comment = line_comment.substr(2, line_comment.length());
if (p_docs_down) {
doc_lines.push_back(line_comment);
} else {
@@ -731,7 +730,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
Array nested_classes;
Array constants;
- Array members;
+ Array class_members;
Array signals;
Array methods;
Array static_functions;
@@ -792,7 +791,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
api["signature"] = symbol->detail;
api["description"] = symbol->documentation;
}
- members.push_back(api);
+ class_members.push_back(api);
} break;
case ClassNode::Member::SIGNAL: {
Dictionary api;
@@ -824,7 +823,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
class_api["sub_classes"] = nested_classes;
class_api["constants"] = constants;
- class_api["members"] = members;
+ class_api["members"] = class_members;
class_api["signals"] = signals;
class_api["methods"] = methods;
class_api["static_functions"] = static_functions;
@@ -834,8 +833,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
Dictionary ExtendGDScriptParser::generate_api() const {
Dictionary api;
- const GDScriptParser::Node *head = get_tree();
- if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(head)) {
+ if (const GDScriptParser::ClassNode *gdclass = dynamic_cast<const GDScriptParser::ClassNode *>(get_tree())) {
api = dump_class_api(gdclass);
}
return api;
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index ead4ef1987..38bea314a0 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -61,12 +61,12 @@ void GDScriptLanguageServer::_notification(int p_what) {
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- String host = String(_EDITOR_GET("network/language_server/remote_host"));
- int port = (int)_EDITOR_GET("network/language_server/remote_port");
- bool use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
- if (host != this->host || port != this->port || use_thread != this->use_thread) {
- this->stop();
- this->start();
+ String remote_host = String(_EDITOR_GET("network/language_server/remote_host"));
+ int remote_port = (int)_EDITOR_GET("network/language_server/remote_port");
+ bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
+ if (remote_host != host || remote_port != port || remote_use_thread != use_thread) {
+ stop();
+ start();
}
} break;
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index ccde0521f2..3905e28bcb 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -42,6 +42,7 @@ void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose);
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
+ ClassDB::bind_method(D_METHOD("willSaveWaitUntil"), &GDScriptTextDocument::willSaveWaitUntil);
ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave);
ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
@@ -81,6 +82,16 @@ void GDScriptTextDocument::didChange(const Variant &p_param) {
sync_script_content(doc.uri, doc.text);
}
+void GDScriptTextDocument::willSaveWaitUntil(const Variant &p_param) {
+ lsp::TextDocumentItem doc = load_document_item(p_param);
+
+ String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri);
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_valid()) {
+ ScriptEditor::get_singleton()->clear_docs_from_script(scr);
+ }
+}
+
void GDScriptTextDocument::didSave(const Variant &p_param) {
lsp::TextDocumentItem doc = load_document_item(p_param);
Dictionary dict = p_param;
@@ -88,11 +99,16 @@ void GDScriptTextDocument::didSave(const Variant &p_param) {
sync_script_content(doc.uri, text);
- /*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri);
-
- Ref<GDScript> script = ResourceLoader::load(path);
- script->load_source_code(path);
- script->reload(true);*/
+ String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri);
+ Ref<GDScript> scr = ResourceLoader::load(path);
+ if (scr.is_valid() && (scr->load_source_code(path) == OK)) {
+ if (scr->is_tool()) {
+ scr->get_language()->reload_tool_script(scr, true);
+ } else {
+ scr->reload(true);
+ }
+ ScriptEditor::get_singleton()->update_docs_from_script(scr);
+ }
}
lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) {
@@ -213,8 +229,8 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
arr = native_member_completions.duplicate();
for (KeyValue<String, ExtendGDScriptParser *> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts) {
- ExtendGDScriptParser *script = E.value;
- const Array &items = script->get_member_completions();
+ ExtendGDScriptParser *scr = E.value;
+ const Array &items = scr->get_member_completions();
const int start_size = arr.size();
arr.resize(start_size + items.size());
@@ -417,14 +433,6 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
EditorFileSystem::get_singleton()->update_file(path);
- Error error;
- Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error);
- 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.
- }
- }
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index 87bc08a34e..456c7d71fe 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -45,6 +45,7 @@ protected:
void didOpen(const Variant &p_param);
void didClose(const Variant &p_param);
void didChange(const Variant &p_param);
+ void willSaveWaitUntil(const Variant &p_param);
void didSave(const Variant &p_param);
void sync_script_content(const String &p_path, const String &p_content);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 16461b0a6c..390460bed9 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -55,14 +55,14 @@ void GDScriptWorkspace::_bind_methods() {
}
void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStringArray args) {
- Ref<Script> script = obj->get_script();
+ Ref<Script> scr = obj->get_script();
- if (script->get_language()->get_name() != "GDScript") {
+ if (scr->get_language()->get_name() != "GDScript") {
return;
}
String function_signature = "func " + function;
- String source = script->get_source_code();
+ String source = scr->get_source_code();
if (source.contains(function_signature)) {
return;
@@ -98,7 +98,7 @@ void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStr
text_edit.newText = function_body;
- String uri = get_file_uri(script->get_path());
+ String uri = get_file_uri(scr->get_path());
lsp::ApplyWorkspaceEditParams params;
params.edit.add_edit(uri, text_edit);
@@ -118,12 +118,12 @@ void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) {
void GDScriptWorkspace::remove_cache_parser(const String &p_path) {
HashMap<String, ExtendGDScriptParser *>::Iterator parser = parse_results.find(p_path);
- HashMap<String, ExtendGDScriptParser *>::Iterator script = scripts.find(p_path);
- if (parser && script) {
- if (script->value && script->value == parser->value) {
- memdelete(script->value);
+ HashMap<String, ExtendGDScriptParser *>::Iterator scr = scripts.find(p_path);
+ if (parser && scr) {
+ if (scr->value && scr->value == parser->value) {
+ memdelete(scr->value);
} else {
- memdelete(script->value);
+ memdelete(scr->value);
memdelete(parser->value);
}
parse_results.erase(p_path);
@@ -131,8 +131,8 @@ void GDScriptWorkspace::remove_cache_parser(const String &p_path) {
} else if (parser) {
memdelete(parser->value);
parse_results.erase(p_path);
- } else if (script) {
- memdelete(script->value);
+ } else if (scr) {
+ memdelete(scr->value);
scripts.erase(p_path);
}
}
@@ -587,8 +587,8 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
while (!stack.is_empty()) {
current = Object::cast_to<Node>(stack.pop_back());
- Ref<GDScript> script = current->get_script();
- if (script.is_valid() && script->get_path() == path) {
+ Ref<GDScript> scr = current->get_script();
+ if (scr.is_valid() && scr->get_path() == path) {
break;
}
for (int i = 0; i < current->get_child_count(); ++i) {
@@ -596,8 +596,8 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
}
}
- Ref<GDScript> script = current->get_script();
- if (!script.is_valid() || script->get_path() != path) {
+ Ref<GDScript> scr = current->get_script();
+ if (!scr.is_valid() || scr->get_path() != path) {
current = owner_scene_node;
}
}
@@ -691,13 +691,13 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
- const ExtendGDScriptParser *script = E.value;
- const ClassMembers &members = script->get_members();
+ const ExtendGDScriptParser *scr = E.value;
+ const ClassMembers &members = scr->get_members();
if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
- for (const KeyValue<String, ClassMembers> &F : script->get_inner_classes()) {
+ for (const KeyValue<String, ClassMembers> &F : scr->get_inner_classes()) {
const ClassMembers *inner_class = &F.value;
if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) {
r_list.push_back(*symbol);
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index fbd40796c4..024da1cab7 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -546,7 +546,7 @@ struct TextDocumentSyncOptions {
* If present will save wait until requests are sent to the server. If omitted the request should not be
* sent.
*/
- bool willSaveWaitUntil = false;
+ bool willSaveWaitUntil = true;
/**
* If present save notifications are sent to the server. If omitted the notification should not be
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 6c346acb7e..15131afde7 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -479,9 +479,9 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
result.output = get_text_for_status(result.status) + "\n";
const List<GDScriptParser::ParserError> &errors = parser.get_errors();
- for (const GDScriptParser::ParserError &E : errors) {
- result.output += E.message + "\n"; // TODO: line, column?
- break; // Only the first error since the following might be cascading.
+ if (!errors.is_empty()) {
+ // Only the first error since the following might be cascading.
+ result.output += errors[0].message + "\n"; // TODO: line, column?
}
if (!p_is_generating) {
result.passed = check_output(result.output);
@@ -498,9 +498,9 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
result.output = get_text_for_status(result.status) + "\n";
const List<GDScriptParser::ParserError> &errors = parser.get_errors();
- for (const GDScriptParser::ParserError &E : errors) {
- result.output += E.message + "\n"; // TODO: line, column?
- break; // Only the first error since the following might be cascading.
+ if (!errors.is_empty()) {
+ // Only the first error since the following might be cascading.
+ result.output += errors[0].message + "\n"; // TODO: line, column?
}
if (!p_is_generating) {
result.passed = check_output(result.output);
diff --git a/modules/gdscript/tests/scripts/parser/features/class.gd b/modules/gdscript/tests/scripts/parser/features/class.gd
index 6652f85ad9..af24b32322 100644
--- a/modules/gdscript/tests/scripts/parser/features/class.gd
+++ b/modules/gdscript/tests/scripts/parser/features/class.gd
@@ -21,5 +21,5 @@ func test():
assert(test_sub.number == 25) # From Test.
assert(test_sub.other_string == "bye") # From TestSub.
- TestConstructor.new()
- TestConstructor.new(500)
+ var _test_constructor = TestConstructor.new()
+ _test_constructor = TestConstructor.new(500)
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out
index 5f999f573a..e1eeb46f78 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out
@@ -7,8 +7,8 @@ null
false
empty array
zero Vector2i
-{22:{4:["nesting", "arrays"]}}
-{4:["nesting", "arrays"]}
+{ 22: { 4: ["nesting", "arrays"] } }
+{ 4: ["nesting", "arrays"] }
["nesting", "arrays"]
nesting
arrays
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
index 5143d040a9..553d40d953 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
@@ -1,2 +1,2 @@
GDTEST_OK
-{"a":1, "b":2, "with spaces":3, "2":4}
+{ "a": 1, "b": 2, "with spaces": 3, "2": 4 }
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
index dd28609850..cf79845f53 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
@@ -1,2 +1,2 @@
GDTEST_OK
-{"hello":{"world":{"is":"beautiful"}}}
+{ "hello": { "world": { "is": "beautiful" } } }
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
index 8b8c33202f..508f0ff217 100644
--- a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
+++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
@@ -1,5 +1,5 @@
GDTEST_OK
-{8:{"key":"value"}}
-{"key":"value"}
+{ 8: { "key": "value" } }
+{ "key": "value" }
value
value
diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out
index d73c5eb7cd..13f759dd46 100644
--- a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out
+++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out
@@ -1 +1,5 @@
GDTEST_OK
+>> WARNING
+>> Line: 6
+>> RETURN_VALUE_DISCARDED
+>> The function 'i_return_int()' returns a value, but this value is never used.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd
new file mode 100644
index 0000000000..29d8501b78
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd
@@ -0,0 +1,11 @@
+class Player:
+ var x = 3
+
+func test():
+ # These should not emit a warning.
+ var _player = Player.new()
+ print(String.num_uint64(8589934592)) # 2 ^ 33
+
+ # This should emit a warning.
+ var some_string = String()
+ print(some_string.num_uint64(8589934592)) # 2 ^ 33
diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out
new file mode 100644
index 0000000000..3933a35178
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+>> WARNING
+>> Line: 11
+>> STATIC_CALLED_ON_INSTANCE
+>> The function 'num_uint64()' is a static function but was called from an instance. Instead, it should be directly called from the type: 'String.num_uint64()'.
+8589934592
+8589934592
diff --git a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out
index 5e7ccf534a..22929bf636 100644
--- a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out
+++ b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out
@@ -1,6 +1,6 @@
GDTEST_OK
-{1:(2, 0)}
-{3:(4, 0)}
+{ 1: (2, 0) }
+{ 3: (4, 0) }
[[(5, 0)]]
[[(6, 0)]]
[[(7, 0)]]
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
index c6645c2c34..809d0d28a9 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
@@ -69,6 +69,10 @@ func test():
value = Transform3D()
print(value == null)
+ # Projection
+ value = Projection()
+ print(value == null)
+
# Color
value = Color()
print(value == null)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
index 639f6027b9..27423ab8e7 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
@@ -33,3 +33,4 @@ false
false
false
false
+false
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
index ee622bf22f..f46afb0f18 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
@@ -69,6 +69,10 @@ func test():
value = Transform3D()
print(value != null)
+ # Projection
+ value = Projection()
+ print(value != null)
+
# Color
value = Color()
print(value != null)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
index d1e332afba..a11c47854a 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
@@ -33,3 +33,4 @@ true
true
true
true
+true
diff --git a/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.gd b/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.gd
new file mode 100644
index 0000000000..e24137a20d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.gd
@@ -0,0 +1,60 @@
+func test():
+ # All combinations of 1/2/3 arguments, each being int/float.
+
+ for number in range(5):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(5.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+
+ for number in range(1, 5):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1, 5.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+
+ for number in range(1, 5, 2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1, 5, 2.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1, 5.2, 2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1, 5.2, 2.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5, 2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5.2, 2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5, 2.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ for number in range(1.2, 5.2, 2.2):
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
diff --git a/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.out b/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/range_optimized_in_for_has_int_iterator.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.gd b/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.gd
new file mode 100644
index 0000000000..63c3b84305
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.gd
@@ -0,0 +1,77 @@
+func test():
+ # All combinations of 1/2/3 arguments, each being int/float.
+ # Store result in variable to ensure actual array is created (avoid `for` + `range` optimization).
+
+ var result
+
+ result = range(5)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(5.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+
+ result = range(1, 5)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1, 5.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+
+ result = range(1, 5, 2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1, 5, 2.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1, 5.2, 2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1, 5.2, 2.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5, 2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5.2, 2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5, 2.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
+
+ result = range(1.2, 5.2, 2.2)
+ for number in result:
+ if typeof(number) != TYPE_INT:
+ print("Number returned from `range` was not an int!")
diff --git a/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.out b/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/range_returns_ints.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
index d4468737a5..1f33de00cc 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.out
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -21,7 +21,7 @@ hello/world
RID(0)
Node::get_name
Node::[signal]property_list_changed
-{"hello":123}
+{ "hello": 123 }
["hello", 123]
[255, 0, 1]
[-1, 0, 1]
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index b1c2140039..53ec0fde34 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -53,7 +53,6 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
};
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
- bool check_subgroup_support = true; // assume we support subgroups
glslang::EShTargetClientVersion ClientVersion = glslang::EShTargetVulkan_1_2;
glslang::EShTargetLanguageVersion TargetVersion = glslang::EShTargetSpv_1_5;
@@ -63,7 +62,6 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
if (capabilities->version_major == 1 && capabilities->version_minor == 0) {
ClientVersion = glslang::EShTargetVulkan_1_0;
TargetVersion = glslang::EShTargetSpv_1_0;
- check_subgroup_support = false; // subgroups are not supported in Vulkan 1.0
} else if (capabilities->version_major == 1 && capabilities->version_minor == 1) {
ClientVersion = glslang::EShTargetVulkan_1_1;
TargetVersion = glslang::EShTargetSpv_1_3;
@@ -88,7 +86,7 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage
shader.setEnvClient(glslang::EShClientVulkan, ClientVersion);
shader.setEnvTarget(glslang::EShTargetSpv, TargetVersion);
- if (check_subgroup_support) {
+ {
uint32_t stage_bit = 1 << p_stage;
uint32_t subgroup_in_shaders = uint32_t(p_render_device->limit_get(RD::LIMIT_SUBGROUP_IN_SHADERS));
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index 189b5a831a..130c06d264 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -26,6 +26,7 @@ def get_doc_classes():
"GLTFSpecGloss",
"GLTFState",
"GLTFTexture",
+ "GLTFTextureSampler",
]
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index 4d1aa89ac9..8e48066623 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -9,6 +9,25 @@
<tutorials>
<link title="GLTF scene and node spec">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_004_ScenesNodes.md"</link>
</tutorials>
+ <methods>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFNode] instance. This can be used to keep per-node state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
+ </methods>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
</member>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 6c2f488c1c..d0740cf7ca 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -20,6 +20,14 @@
<description>
</description>
</method>
+ <method name="get_additional_data">
+ <return type="Variant" />
+ <param index="0" name="extension_name" type="StringName" />
+ <description>
+ Gets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the return value can be anything you set. If nothing was set, the return value is null.
+ </description>
+ </method>
<method name="get_animation_player">
<return type="AnimationPlayer" />
<param index="0" name="idx" type="int" />
@@ -93,6 +101,12 @@
<description>
</description>
</method>
+ <method name="get_texture_samplers">
+ <return type="GLTFTextureSampler[]" />
+ <description>
+ Retrieves the array of texture samplers that are used by the textures contained in the GLTF.
+ </description>
+ </method>
<method name="get_textures">
<return type="GLTFTexture[]" />
<description>
@@ -114,6 +128,15 @@
<description>
</description>
</method>
+ <method name="set_additional_data">
+ <return type="void" />
+ <param index="0" name="extension_name" type="StringName" />
+ <param index="1" name="additional_data" type="Variant" />
+ <description>
+ Sets additional arbitrary data in this [GLTFState] instance. This can be used to keep per-file state data in [GLTFDocumentExtension] classes, which is important because they are stateless.
+ The first argument should be the [GLTFDocumentExtension] name (does not have to match the extension name in the GLTF file), and the second argument can be anything you want.
+ </description>
+ </method>
<method name="set_animations">
<return type="void" />
<param index="0" name="animations" type="GLTFAnimation[]" />
@@ -180,6 +203,13 @@
<description>
</description>
</method>
+ <method name="set_texture_samplers">
+ <return type="void" />
+ <param index="0" name="texture_samplers" type="GLTFTextureSampler[]" />
+ <description>
+ Sets the array of texture samplers that are used by the textures contained in the GLTF.
+ </description>
+ </method>
<method name="set_textures">
<return type="void" />
<param index="0" name="textures" type="GLTFTexture[]" />
diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index c0bc424168..f4486fd504 100644
--- a/modules/gltf/doc_classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -7,6 +7,9 @@
<tutorials>
</tutorials>
<members>
+ <member name="sampler" type="int" setter="set_sampler" getter="get_sampler" default="-1">
+ ID of the texture sampler to use when sampling the image. If -1, then the default texture sampler is used (linear filtering, and repeat wrapping in both axes).
+ </member>
<member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0">
</member>
</members>
diff --git a/modules/gltf/doc_classes/GLTFTextureSampler.xml b/modules/gltf/doc_classes/GLTFTextureSampler.xml
new file mode 100644
index 0000000000..1cc69bfe73
--- /dev/null
+++ b/modules/gltf/doc_classes/GLTFTextureSampler.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFTextureSampler" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Represents a GLTF texture sampler
+ </brief_description>
+ <description>
+ Represents a texture sampler as defined by the base GLTF spec. Texture samplers in GLTF specify how to sample data from the texture's base image, when rendering the texture on an object.
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="mag_filter" type="int" setter="set_mag_filter" getter="get_mag_filter" default="9729">
+ Texture's magnification filter, used when texture appears larger on screen than the source image.
+ </member>
+ <member name="min_filter" type="int" setter="set_min_filter" getter="get_min_filter" default="9987">
+ Texture's minification filter, used when the texture appears smaller on screen than the source image.
+ </member>
+ <member name="wrap_s" type="int" setter="set_wrap_s" getter="get_wrap_s" default="10497">
+ Wrapping mode to use for S-axis (horizontal) texture coordinates.
+ </member>
+ <member name="wrap_t" type="int" setter="set_wrap_t" getter="get_wrap_t" default="10497">
+ Wrapping mode to use for T-axis (vertical) texture coordinates.
+ </member>
+ </members>
+</class>
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index f79731dd22..20c9508474 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -77,20 +77,19 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
} else {
parameters_arg += "export_extras=False,";
}
- if (p_options.has(SNAME("blender/meshes/skins")) && p_options[SNAME("blender/meshes/skins")]) {
+ if (p_options.has(SNAME("blender/meshes/skins"))) {
int32_t skins = p_options["blender/meshes/skins"];
if (skins == BLEND_BONE_INFLUENCES_NONE) {
- parameters_arg += "export_all_influences=False,";
+ parameters_arg += "export_skins=False,";
} else if (skins == BLEND_BONE_INFLUENCES_COMPATIBLE) {
- parameters_arg += "export_all_influences=False,";
+ parameters_arg += "export_all_influences=False,export_skins=True,";
} else if (skins == BLEND_BONE_INFLUENCES_ALL) {
- parameters_arg += "export_all_influences=True,";
+ parameters_arg += "export_all_influences=True,export_skins=True,";
}
- parameters_arg += "export_skins=True,";
} else {
parameters_arg += "export_skins=False,";
}
- if (p_options.has(SNAME("blender/materials/export_materials")) && p_options[SNAME("blender/materials/export_materials")]) {
+ if (p_options.has(SNAME("blender/materials/export_materials"))) {
int32_t exports = p_options["blender/materials/export_materials"];
if (exports == BLEND_MATERIAL_EXPORT_PLACEHOLDER) {
parameters_arg += "export_materials='PLACEHOLDER',";
@@ -115,7 +114,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
} else {
parameters_arg += "export_colors=False,";
}
- if (p_options.has(SNAME("blender/nodes/visible")) && p_options[SNAME("blender/nodes/visible")]) {
+ if (p_options.has(SNAME("blender/nodes/visible"))) {
int32_t visible = p_options["blender/nodes/visible"];
if (visible == BLEND_VISIBLE_VISIBLE_ONLY) {
parameters_arg += "use_visible=True,";
@@ -180,13 +179,13 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
"export_format='GLTF_SEPARATE',"
"export_yup=True," +
parameters_arg;
- String script =
+ String export_script =
String("import bpy, sys;") +
"print('Blender 3.0 or higher is required.', file=sys.stderr) if bpy.app.version < (3, 0, 0) else None;" +
vformat("bpy.ops.wm.open_mainfile(filepath='%s');", source_global) +
unpack_all +
vformat("bpy.ops.export_scene.gltf(export_keep_originals=True,%s);", common_args);
- print_verbose(script);
+ print_verbose(export_script);
// Run script with configured Blender binary.
@@ -201,7 +200,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
List<String> args;
args.push_back("--background");
args.push_back("--python-expr");
- args.push_back(script);
+ args.push_back(export_script);
String standard_out;
int ret;
@@ -350,9 +349,7 @@ static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
bool EditorFileSystemImportFormatSupportQueryBlend::is_active() const {
bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
- String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
-
- if (blend_enabled && !_test_blender_path(blender_path)) {
+ if (blend_enabled && !_test_blender_path(EDITOR_GET("filesystem/import/blender/blender3_path").operator String())) {
// Intending to import Blender, but blend not configured.
return true;
}
diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp
index 6923c765cb..d00bead61c 100644
--- a/modules/gltf/extensions/gltf_light.cpp
+++ b/modules/gltf/extensions/gltf_light.cpp
@@ -142,18 +142,17 @@ Light3D *GLTFLight::to_node() const {
light->set_color(color);
return light;
}
- const float range = CLAMP(this->range, 0, 4096);
if (light_type == "point") {
OmniLight3D *light = memnew(OmniLight3D);
light->set_param(OmniLight3D::PARAM_ENERGY, intensity);
- light->set_param(OmniLight3D::PARAM_RANGE, range);
+ light->set_param(OmniLight3D::PARAM_RANGE, CLAMP(range, 0, 4096));
light->set_color(color);
return light;
}
if (light_type == "spot") {
SpotLight3D *light = memnew(SpotLight3D);
light->set_param(SpotLight3D::PARAM_ENERGY, intensity);
- light->set_param(SpotLight3D::PARAM_RANGE, range);
+ light->set_param(SpotLight3D::PARAM_RANGE, CLAMP(range, 0, 4096));
light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad_to_deg(outer_cone_angle));
light->set_color(color);
// Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b
diff --git a/modules/gltf/gltf_defines.h b/modules/gltf/gltf_defines.h
index 9ee2397968..23bf33869e 100644
--- a/modules/gltf/gltf_defines.h
+++ b/modules/gltf/gltf_defines.h
@@ -58,6 +58,7 @@ class GLTFSkin;
class GLTFSpecGloss;
class GLTFState;
class GLTFTexture;
+class GLTFTextureSampler;
// GLTF index aliases.
using GLTFAccessorIndex = int;
@@ -73,6 +74,7 @@ using GLTFNodeIndex = int;
using GLTFSkeletonIndex = int;
using GLTFSkinIndex = int;
using GLTFTextureIndex = int;
+using GLTFTextureSamplerIndex = int;
enum GLTFType {
TYPE_SCALAR,
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 8d2e37be3a..99803ed05d 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -145,6 +145,12 @@ Error GLTFDocument::_serialize(Ref<GLTFState> state, const String &p_path) {
return Error::FAILED;
}
+ /* STEP SERIALIZE TEXTURE SAMPLERS */
+ err = _serialize_texture_samplers(state);
+ if (err != OK) {
+ return Error::FAILED;
+ }
+
/* STEP SERIALIZE ANIMATIONS */
err = _serialize_animations(state);
if (err != OK) {
@@ -465,23 +471,23 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
String GLTFDocument::_gen_unique_name(Ref<GLTFState> state, const String &p_name) {
const String s_name = p_name.validate_node_name();
- String name;
+ String u_name;
int index = 1;
while (true) {
- name = s_name;
+ u_name = s_name;
if (index > 1) {
- name += itos(index);
+ u_name += itos(index);
}
- if (!state->unique_names.has(name)) {
+ if (!state->unique_names.has(u_name)) {
break;
}
index++;
}
- state->unique_names.insert(name);
+ state->unique_names.insert(u_name);
- return name;
+ return u_name;
}
String GLTFDocument::_sanitize_animation_name(const String &p_name) {
@@ -489,39 +495,39 @@ String GLTFDocument::_sanitize_animation_name(const String &p_name) {
// (See animation/animation_player.cpp::add_animation)
// TODO: Consider adding invalid_characters or a validate_animation_name to animation_player to mirror Node.
- String name = p_name.validate_node_name();
- name = name.replace(",", "");
- name = name.replace("[", "");
- return name;
+ String anim_name = p_name.validate_node_name();
+ anim_name = anim_name.replace(",", "");
+ anim_name = anim_name.replace("[", "");
+ return anim_name;
}
String GLTFDocument::_gen_unique_animation_name(Ref<GLTFState> state, const String &p_name) {
const String s_name = _sanitize_animation_name(p_name);
- String name;
+ String u_name;
int index = 1;
while (true) {
- name = s_name;
+ u_name = s_name;
if (index > 1) {
- name += itos(index);
+ u_name += itos(index);
}
- if (!state->unique_animation_names.has(name)) {
+ if (!state->unique_animation_names.has(u_name)) {
break;
}
index++;
}
- state->unique_animation_names.insert(name);
+ state->unique_animation_names.insert(u_name);
- return name;
+ return u_name;
}
String GLTFDocument::_sanitize_bone_name(const String &p_name) {
- String name = p_name;
- name = name.replace(":", "_");
- name = name.replace("/", "_");
- return name;
+ String bone_name = p_name;
+ bone_name = bone_name.replace(":", "_");
+ bone_name = bone_name.replace("/", "_");
+ return bone_name;
}
String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkeletonIndex skel_i, const String &p_name) {
@@ -529,23 +535,23 @@ String GLTFDocument::_gen_unique_bone_name(Ref<GLTFState> state, const GLTFSkele
if (s_name.is_empty()) {
s_name = "bone";
}
- String name;
+ String u_name;
int index = 1;
while (true) {
- name = s_name;
+ u_name = s_name;
if (index > 1) {
- name += "_" + itos(index);
+ u_name += "_" + itos(index);
}
- if (!state->skeletons[skel_i]->unique_names.has(name)) {
+ if (!state->skeletons[skel_i]->unique_names.has(u_name)) {
break;
}
index++;
}
- state->skeletons.write[skel_i]->unique_names.insert(name);
+ state->skeletons.write[skel_i]->unique_names.insert(u_name);
- return name;
+ return u_name;
}
Error GLTFDocument::_parse_scenes(Ref<GLTFState> state) {
@@ -2584,10 +2590,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES
Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP
Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted
-#ifndef _MSC_VER
-#warning line loop and triangle fan are not supported and need to be converted to lines and triangles
-#endif
-
+ // TODO: Line loop and triangle fan are not supported and need to be converted to lines and triangles.
};
primitive = primitives2[mode];
@@ -2818,8 +2821,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (j == 0) {
const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array();
for (int k = 0; k < targets.size(); k++) {
- const String name = k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k);
- import_mesh->add_blend_shape(name);
+ import_mesh->add_blend_shape(k < target_names.size() ? (String)target_names[k] : String("morph_") + itos(k));
}
}
@@ -3028,12 +3030,12 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
d["mimeType"] = "image/png";
} else {
ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
- String name = state->images[i]->get_name();
- if (name.is_empty()) {
- name = itos(i);
+ String img_name = state->images[i]->get_name();
+ if (img_name.is_empty()) {
+ img_name = itos(i);
}
- name = _gen_unique_name(state, name);
- name = name.pad_zeros(3) + ".png";
+ img_name = _gen_unique_name(state, img_name);
+ img_name = img_name.pad_zeros(3) + ".png";
String texture_dir = "textures";
String path = p_path.get_base_dir();
String new_texture_dir = path + "/" + texture_dir;
@@ -3041,8 +3043,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
if (!da->dir_exists(new_texture_dir)) {
da->make_dir(new_texture_dir);
}
- image->save_png(new_texture_dir.path_join(name));
- d["uri"] = texture_dir.path_join(name).uri_encode();
+ image->save_png(new_texture_dir.path_join(img_name));
+ d["uri"] = texture_dir.path_join(img_name).uri_encode();
}
images.push_back(d);
}
@@ -3219,6 +3221,11 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> state) {
Ref<GLTFTexture> t = state->textures[i];
ERR_CONTINUE(t->get_src_image() == -1);
d["source"] = t->get_src_image();
+
+ GLTFTextureSamplerIndex sampler_index = t->get_sampler();
+ if (sampler_index != -1) {
+ d["sampler"] = sampler_index;
+ }
textures.push_back(d);
}
state->json["textures"] = textures;
@@ -3240,13 +3247,18 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) {
Ref<GLTFTexture> t;
t.instantiate();
t->set_src_image(d["source"]);
+ if (d.has("sampler")) {
+ t->set_sampler(d["sampler"]);
+ } else {
+ t->set_sampler(-1);
+ }
state->textures.push_back(t);
}
return OK;
}
-GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) {
+GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
ERR_FAIL_COND_V(p_texture.is_null(), -1);
Ref<GLTFTexture> gltf_texture;
gltf_texture.instantiate();
@@ -3254,6 +3266,7 @@ GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D>
GLTFImageIndex gltf_src_image_i = state->images.size();
state->images.push_back(p_texture);
gltf_texture->set_src_image(gltf_src_image_i);
+ gltf_texture->set_sampler(_set_sampler_for_mode(state, p_filter_mode, p_repeats));
GLTFTextureIndex gltf_texture_i = state->textures.size();
state->textures.push_back(gltf_texture);
return gltf_texture_i;
@@ -3268,6 +3281,102 @@ Ref<Texture2D> GLTFDocument::_get_texture(Ref<GLTFState> state, const GLTFTextur
return state->images[image];
}
+GLTFTextureSamplerIndex GLTFDocument::_set_sampler_for_mode(Ref<GLTFState> state, StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats) {
+ for (int i = 0; i < state->texture_samplers.size(); ++i) {
+ if (state->texture_samplers[i]->get_filter_mode() == p_filter_mode) {
+ return i;
+ }
+ }
+
+ GLTFTextureSamplerIndex gltf_sampler_i = state->texture_samplers.size();
+ Ref<GLTFTextureSampler> gltf_sampler;
+ gltf_sampler.instantiate();
+ gltf_sampler->set_filter_mode(p_filter_mode);
+ gltf_sampler->set_wrap_mode(p_repeats);
+ state->texture_samplers.push_back(gltf_sampler);
+ return gltf_sampler_i;
+}
+
+Ref<GLTFTextureSampler> GLTFDocument::_get_sampler_for_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture) {
+ ERR_FAIL_INDEX_V(p_texture, state->textures.size(), Ref<Texture2D>());
+ const GLTFTextureSamplerIndex sampler = state->textures[p_texture]->get_sampler();
+
+ if (sampler == -1) {
+ return state->default_texture_sampler;
+ } else {
+ ERR_FAIL_INDEX_V(sampler, state->texture_samplers.size(), Ref<GLTFTextureSampler>());
+
+ return state->texture_samplers[sampler];
+ }
+}
+
+Error GLTFDocument::_serialize_texture_samplers(Ref<GLTFState> state) {
+ if (!state->texture_samplers.size()) {
+ return OK;
+ }
+
+ Array samplers;
+ for (int32_t i = 0; i < state->texture_samplers.size(); ++i) {
+ Dictionary d;
+ Ref<GLTFTextureSampler> s = state->texture_samplers[i];
+ d["magFilter"] = s->get_mag_filter();
+ d["minFilter"] = s->get_min_filter();
+ d["wrapS"] = s->get_wrap_s();
+ d["wrapT"] = s->get_wrap_t();
+ samplers.push_back(d);
+ }
+ state->json["samplers"] = samplers;
+
+ return OK;
+}
+
+Error GLTFDocument::_parse_texture_samplers(Ref<GLTFState> state) {
+ state->default_texture_sampler.instantiate();
+ state->default_texture_sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR);
+ state->default_texture_sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR);
+ state->default_texture_sampler->set_wrap_s(GLTFTextureSampler::WrapMode::REPEAT);
+ state->default_texture_sampler->set_wrap_t(GLTFTextureSampler::WrapMode::REPEAT);
+
+ if (!state->json.has("samplers")) {
+ return OK;
+ }
+
+ const Array &samplers = state->json["samplers"];
+ for (int i = 0; i < samplers.size(); ++i) {
+ const Dictionary &d = samplers[i];
+
+ Ref<GLTFTextureSampler> sampler;
+ sampler.instantiate();
+
+ if (d.has("minFilter")) {
+ sampler->set_min_filter(d["minFilter"]);
+ } else {
+ sampler->set_min_filter(GLTFTextureSampler::FilterMode::LINEAR_MIPMAP_LINEAR);
+ }
+ if (d.has("magFilter")) {
+ sampler->set_mag_filter(d["magFilter"]);
+ } else {
+ sampler->set_mag_filter(GLTFTextureSampler::FilterMode::LINEAR);
+ }
+
+ if (d.has("wrapS")) {
+ sampler->set_wrap_s(d["wrapS"]);
+ } else {
+ sampler->set_wrap_s(GLTFTextureSampler::WrapMode::DEFAULT);
+ }
+
+ if (d.has("wrapT")) {
+ sampler->set_wrap_t(d["wrapT"]);
+ } else {
+ sampler->set_wrap_t(GLTFTextureSampler::WrapMode::DEFAULT);
+ }
+
+ state->texture_samplers.push_back(sampler);
+ }
+
+ return OK;
+}
+
Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Array materials;
for (int32_t i = 0; i < state->materials.size(); i++) {
@@ -3299,7 +3408,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
albedo_texture->set_name(material->get_name() + "_albedo");
- gltf_texture_index = _set_texture(state, albedo_texture);
+ gltf_texture_index = _set_texture(state, albedo_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (gltf_texture_index != -1) {
bct["index"] = gltf_texture_index;
@@ -3375,7 +3484,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
height = albedo_texture->get_height();
width = albedo_texture->get_width();
}
- orm_image->create(width, height, false, Image::FORMAT_RGBA8);
+ orm_image->initialize_data(width, height, false, Image::FORMAT_RGBA8);
if (ao_image.is_valid() && ao_image->get_size() != Vector2(width, height)) {
ao_image->resize(width, height, Image::INTERPOLATE_LANCZOS);
}
@@ -3429,7 +3538,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex orm_texture_index = -1;
if (has_ao || has_roughness || has_metalness) {
orm_texture->set_name(material->get_name() + "_orm");
- orm_texture_index = _set_texture(state, orm_texture);
+ orm_texture_index = _set_texture(state, orm_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (has_ao) {
Dictionary occt;
@@ -3484,7 +3593,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex gltf_texture_index = -1;
if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal");
- gltf_texture_index = _set_texture(state, tex);
+ gltf_texture_index = _set_texture(state, tex, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
nt["scale"] = material->get_normal_scale();
if (gltf_texture_index != -1) {
@@ -3507,7 +3616,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex gltf_texture_index = -1;
if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) {
emission_texture->set_name(material->get_name() + "_emission");
- gltf_texture_index = _set_texture(state, emission_texture);
+ gltf_texture_index = _set_texture(state, emission_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
}
if (gltf_texture_index != -1) {
@@ -3566,6 +3675,11 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("diffuseTexture")) {
const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"];
if (diffuse_texture_dict.has("index")) {
+ Ref<GLTFTextureSampler> diffuse_sampler = _get_sampler_for_texture(state, diffuse_texture_dict["index"]);
+ if (diffuse_sampler.is_valid()) {
+ material->set_texture_filter(diffuse_sampler->get_filter_mode());
+ material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, diffuse_sampler->get_wrap_mode());
+ }
Ref<Texture2D> diffuse_texture = _get_texture(state, diffuse_texture_dict["index"]);
if (diffuse_texture.is_valid()) {
spec_gloss->diffuse_img = diffuse_texture->get_image();
@@ -3614,6 +3728,9 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("baseColorTexture")) {
const Dictionary &bct = mr["baseColorTexture"];
if (bct.has("index")) {
+ Ref<GLTFTextureSampler> bct_sampler = _get_sampler_for_texture(state, bct["index"]);
+ material->set_texture_filter(bct_sampler->get_filter_mode());
+ material->set_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT, bct_sampler->get_wrap_mode());
material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, _get_texture(state, bct["index"]));
}
if (!mr.has("baseColorFactor")) {
@@ -3743,13 +3860,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
if (r_spec_gloss->diffuse_img.is_null()) {
return;
}
- Ref<Image> rm_img;
- rm_img.instantiate();
bool has_roughness = false;
bool has_metal = false;
p_material->set_roughness(1.0f);
p_material->set_metallic(1.0f);
- rm_img->create(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8);
+ Ref<Image> rm_img = Image::create_empty(r_spec_gloss->spec_gloss_img->get_width(), r_spec_gloss->spec_gloss_img->get_height(), false, Image::FORMAT_RGBA8);
r_spec_gloss->spec_gloss_img->decompress();
if (r_spec_gloss->diffuse_img.is_valid()) {
r_spec_gloss->diffuse_img->decompress();
@@ -4301,14 +4416,14 @@ Error GLTFDocument::_determine_skeleton_roots(Ref<GLTFState> state, const GLTFSk
Ref<GLTFSkeleton> skeleton = state->skeletons.write[skel_i];
- Vector<GLTFNodeIndex> owners;
- disjoint_set.get_representatives(owners);
+ Vector<GLTFNodeIndex> representatives;
+ disjoint_set.get_representatives(representatives);
Vector<GLTFNodeIndex> roots;
- for (int i = 0; i < owners.size(); ++i) {
+ for (int i = 0; i < representatives.size(); ++i) {
Vector<GLTFNodeIndex> set;
- disjoint_set.get_members(set, owners[i]);
+ disjoint_set.get_members(set, representatives[i]);
const GLTFNodeIndex root = _find_highest_node(state, set);
ERR_FAIL_COND_V(root < 0, FAILED);
roots.push_back(root);
@@ -4839,12 +4954,12 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
Array samplers = d["samplers"];
if (d.has("name")) {
- const String name = d["name"];
- const String name_lower = name.to_lower();
- if (name_lower.begins_with("loop") || name_lower.ends_with("loop") || name_lower.begins_with("cycle") || name_lower.ends_with("cycle")) {
+ const String anim_name = d["name"];
+ const String anim_name_lower = anim_name.to_lower();
+ if (anim_name_lower.begins_with("loop") || anim_name_lower.ends_with("loop") || anim_name_lower.begins_with("cycle") || anim_name_lower.ends_with("cycle")) {
animation->set_loop(true);
}
- animation->set_name(_gen_unique_animation_name(state, name));
+ animation->set_name(_gen_unique_animation_name(state, anim_name));
}
for (int j = 0; j < channels.size(); j++) {
@@ -5707,15 +5822,15 @@ T GLTFDocument::_interpolate_track(const Vector<real_t> &p_times, const Vector<T
void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, const GLTFAnimationIndex index, const int bake_fps) {
Ref<GLTFAnimation> anim = state->animations[index];
- String name = anim->get_name();
- if (name.is_empty()) {
+ String anim_name = anim->get_name();
+ if (anim_name.is_empty()) {
// No node represent these, and they are not in the hierarchy, so just make a unique name
- name = _gen_unique_name(state, "Animation");
+ anim_name = _gen_unique_name(state, "Animation");
}
Ref<Animation> animation;
animation.instantiate();
- animation->set_name(name);
+ animation->set_name(anim_name);
if (anim->get_loop()) {
animation->set_loop_mode(Animation::LOOP_LINEAR);
@@ -5938,7 +6053,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
} else {
library = ap->get_animation_library("");
}
- library->add_animation(name, animation);
+ library->add_animation(anim_name, animation);
}
void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
@@ -6174,7 +6289,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
for (int32_t key_i = 0; key_i < key_count; key_i++) {
Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.rotation_track.values.write[key_i] = Quaternion(rotation_radian);
+ p_track.rotation_track.values.write[key_i] = Quaternion::from_euler(rotation_radian);
}
} else if (path.contains(":scale")) {
p_track.scale_track.times = times;
@@ -6477,8 +6592,10 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess>
err = ext->import_preflight(state);
ERR_FAIL_COND_V(err != OK, err);
}
+
err = _parse_gltf_state(state, p_path, p_bake_fps);
ERR_FAIL_COND_V(err != OK, err);
+
return OK;
}
@@ -6834,6 +6951,11 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ /* PARSE TEXTURE SAMPLERS */
+ err = _parse_texture_samplers(state);
+
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+
/* PARSE TEXTURES */
err = _parse_textures(state);
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 750d3d403e..62b6e29fe0 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -95,9 +95,14 @@ private:
String _gen_unique_bone_name(Ref<GLTFState> state,
const GLTFSkeletonIndex skel_i,
const String &p_name);
- GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture);
+ GLTFTextureIndex _set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture,
+ StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats);
Ref<Texture2D> _get_texture(Ref<GLTFState> state,
const GLTFTextureIndex p_texture);
+ GLTFTextureSamplerIndex _set_sampler_for_mode(Ref<GLTFState> state,
+ StandardMaterial3D::TextureFilter p_filter_mode, bool p_repeats);
+ Ref<GLTFTextureSampler> _get_sampler_for_texture(Ref<GLTFState> state,
+ const GLTFTextureIndex p_texture);
Error _parse_json(const String &p_path, Ref<GLTFState> state);
Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state);
void _compute_node_heights(Ref<GLTFState> state);
@@ -145,10 +150,12 @@ private:
const bool p_for_vertex);
Error _parse_meshes(Ref<GLTFState> state);
Error _serialize_textures(Ref<GLTFState> state);
+ Error _serialize_texture_samplers(Ref<GLTFState> state);
Error _serialize_images(Ref<GLTFState> state, const String &p_path);
Error _serialize_lights(Ref<GLTFState> state);
Error _parse_images(Ref<GLTFState> state, const String &p_base_path);
Error _parse_textures(Ref<GLTFState> state);
+ Error _parse_texture_samplers(Ref<GLTFState> state);
Error _parse_materials(Ref<GLTFState> state);
void _set_texture_transform_uv1(const Dictionary &d, Ref<BaseMaterial3D> material);
void spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss,
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
index 3b952f8246..713779712c 100644
--- a/modules/gltf/gltf_document_extension.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -51,45 +51,35 @@ 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);
int err = OK;
- if (GDVIRTUAL_CALL(_import_post, p_state, p_root, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_import_post, p_state, p_root, err);
+ return Error(err);
}
Error GLTFDocumentExtension::import_preflight(Ref<GLTFState> p_state) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_import_preflight, p_state, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_import_preflight, p_state, err);
+ return Error(err);
}
Error GLTFDocumentExtension::import_post_parse(Ref<GLTFState> p_state) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_import_post_parse, p_state, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_import_post_parse, p_state, err);
+ return Error(err);
}
Error GLTFDocumentExtension::export_post(Ref<GLTFState> p_state) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_export_post, p_state, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_export_post, p_state, err);
+ return Error(err);
}
Error GLTFDocumentExtension::export_preflight(Node *p_root) {
ERR_FAIL_NULL_V(p_root, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_export_preflight, p_root, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_export_preflight, p_root, err);
+ return Error(err);
}
Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
@@ -97,10 +87,8 @@ Error GLTFDocumentExtension::import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_import_node, p_state, p_gltf_node, r_dict, p_node, err);
+ return Error(err);
}
Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
@@ -108,8 +96,6 @@ Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
int err = OK;
- if (GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err)) {
- return Error(err);
- }
- return OK;
+ GDVIRTUAL_CALL(_export_node, p_state, p_gltf_node, r_dict, p_node, err);
+ return Error(err);
}
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index a23fb39503..ac5665e396 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -64,6 +64,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_nodes", "root_nodes"), &GLTFState::set_root_nodes);
ClassDB::bind_method(D_METHOD("get_textures"), &GLTFState::get_textures);
ClassDB::bind_method(D_METHOD("set_textures", "textures"), &GLTFState::set_textures);
+ ClassDB::bind_method(D_METHOD("get_texture_samplers"), &GLTFState::get_texture_samplers);
+ ClassDB::bind_method(D_METHOD("set_texture_samplers", "texture_samplers"), &GLTFState::set_texture_samplers);
ClassDB::bind_method(D_METHOD("get_images"), &GLTFState::get_images);
ClassDB::bind_method(D_METHOD("set_images", "images"), &GLTFState::set_images);
ClassDB::bind_method(D_METHOD("get_skins"), &GLTFState::get_skins);
@@ -85,6 +87,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFState::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFState::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "json"), "set_json", "get_json"); // Dictionary
ADD_PROPERTY(PropertyInfo(Variant::INT, "major_version"), "set_major_version", "get_major_version"); // int
@@ -101,6 +105,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_path"), "set_base_path", "get_base_path"); // String
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "root_nodes"), "set_root_nodes", "get_root_nodes"); // Vector<int>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_textures", "get_textures"); // Vector<Ref<GLTFTexture>>
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "texture_samplers", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_texture_samplers", "get_texture_samplers"); //Vector<Ref<GLTFTextureSampler>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_images", "get_images"); // Vector<Ref<Texture>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skins", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skins", "get_skins"); // Vector<Ref<GLTFSkin>>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "cameras", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_cameras", "get_cameras"); // Vector<Ref<GLTFCamera>>
@@ -236,6 +241,14 @@ void GLTFState::set_textures(TypedArray<GLTFTexture> p_textures) {
GLTFTemplateConvert::set_from_array(textures, p_textures);
}
+TypedArray<GLTFTextureSampler> GLTFState::get_texture_samplers() {
+ return GLTFTemplateConvert::to_array(texture_samplers);
+}
+
+void GLTFState::set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers) {
+ GLTFTemplateConvert::set_from_array(texture_samplers, p_texture_samplers);
+}
+
TypedArray<Texture2D> GLTFState::get_images() {
return GLTFTemplateConvert::to_array(images);
}
@@ -347,3 +360,11 @@ String GLTFState::get_base_path() {
void GLTFState::set_base_path(String p_base_path) {
base_path = p_base_path;
}
+
+Variant GLTFState::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFState::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index 791431f376..e24017b0fd 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -42,6 +42,7 @@
#include "structures/gltf_skeleton.h"
#include "structures/gltf_skin.h"
#include "structures/gltf_texture.h"
+#include "structures/gltf_texture_sampler.h"
#include "core/templates/rb_map.h"
#include "scene/animation/animation_player.h"
@@ -77,6 +78,8 @@ class GLTFState : public Resource {
String scene_name;
Vector<int> root_nodes;
Vector<Ref<GLTFTexture>> textures;
+ Vector<Ref<GLTFTextureSampler>> texture_samplers;
+ Ref<GLTFTextureSampler> default_texture_sampler;
Vector<Ref<Texture2D>> images;
Vector<String> extensions_used;
Vector<String> extensions_required;
@@ -94,6 +97,7 @@ class GLTFState : public Resource {
HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -149,6 +153,9 @@ public:
TypedArray<GLTFTexture> get_textures();
void set_textures(TypedArray<GLTFTexture> p_textures);
+ TypedArray<GLTFTextureSampler> get_texture_samplers();
+ void set_texture_samplers(TypedArray<GLTFTextureSampler> p_texture_samplers);
+
TypedArray<Texture2D> get_images();
void set_images(TypedArray<Texture2D> p_images);
@@ -185,6 +192,9 @@ public:
AnimationPlayer *get_animation_player(int idx);
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
+
//void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) {
// this->scene_nodes = p_scene_nodes;
//}
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 6e7f7d6fed..b9027f6e3d 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -47,6 +47,7 @@
#include "structures/gltf_skeleton.h"
#include "structures/gltf_skin.h"
#include "structures/gltf_texture.h"
+#include "structures/gltf_texture_sampler.h"
#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
@@ -126,6 +127,7 @@ void initialize_gltf_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(GLTFSpecGloss);
GDREGISTER_CLASS(GLTFState);
GDREGISTER_CLASS(GLTFTexture);
+ GDREGISTER_CLASS(GLTFTextureSampler);
}
#ifdef TOOLS_ENABLED
diff --git a/modules/gltf/structures/gltf_node.cpp b/modules/gltf/structures/gltf_node.cpp
index 86280603fa..6fd36f93b7 100644
--- a/modules/gltf/structures/gltf_node.cpp
+++ b/modules/gltf/structures/gltf_node.cpp
@@ -57,6 +57,8 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_children", "children"), &GLTFNode::set_children);
ClassDB::bind_method(D_METHOD("get_light"), &GLTFNode::get_light);
ClassDB::bind_method(D_METHOD("set_light", "light"), &GLTFNode::set_light);
+ ClassDB::bind_method(D_METHOD("get_additional_data", "extension_name"), &GLTFNode::get_additional_data);
+ ClassDB::bind_method(D_METHOD("set_additional_data", "extension_name", "additional_data"), &GLTFNode::set_additional_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int
@@ -176,3 +178,11 @@ GLTFLightIndex GLTFNode::get_light() {
void GLTFNode::set_light(GLTFLightIndex p_light) {
light = p_light;
}
+
+Variant GLTFNode::get_additional_data(const StringName &p_extension_name) {
+ return additional_data[p_extension_name];
+}
+
+void GLTFNode::set_additional_data(const StringName &p_extension_name, Variant p_additional_data) {
+ additional_data[p_extension_name] = p_additional_data;
+}
diff --git a/modules/gltf/structures/gltf_node.h b/modules/gltf/structures/gltf_node.h
index 1a57ea32e2..90a4fa99ed 100644
--- a/modules/gltf/structures/gltf_node.h
+++ b/modules/gltf/structures/gltf_node.h
@@ -53,6 +53,7 @@ private:
Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
GLTFLightIndex light = -1;
+ Dictionary additional_data;
protected:
static void _bind_methods();
@@ -96,6 +97,9 @@ public:
GLTFLightIndex get_light();
void set_light(GLTFLightIndex p_light);
+
+ Variant get_additional_data(const StringName &p_extension_name);
+ void set_additional_data(const StringName &p_extension_name, Variant p_additional_data);
};
#endif // GLTF_NODE_H
diff --git a/modules/gltf/structures/gltf_texture.cpp b/modules/gltf/structures/gltf_texture.cpp
index 2a21cb3df8..5cc96e3221 100644
--- a/modules/gltf/structures/gltf_texture.cpp
+++ b/modules/gltf/structures/gltf_texture.cpp
@@ -33,8 +33,11 @@
void GLTFTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_src_image"), &GLTFTexture::get_src_image);
ClassDB::bind_method(D_METHOD("set_src_image", "src_image"), &GLTFTexture::set_src_image);
+ ClassDB::bind_method(D_METHOD("get_sampler"), &GLTFTexture::get_sampler);
+ ClassDB::bind_method(D_METHOD("set_sampler", "sampler"), &GLTFTexture::set_sampler);
ADD_PROPERTY(PropertyInfo(Variant::INT, "src_image"), "set_src_image", "get_src_image"); // int
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sampler"), "set_sampler", "get_sampler"); // int
}
GLTFImageIndex GLTFTexture::get_src_image() const {
@@ -44,3 +47,11 @@ GLTFImageIndex GLTFTexture::get_src_image() const {
void GLTFTexture::set_src_image(GLTFImageIndex val) {
src_image = val;
}
+
+GLTFTextureSamplerIndex GLTFTexture::get_sampler() const {
+ return sampler;
+}
+
+void GLTFTexture::set_sampler(GLTFTextureSamplerIndex val) {
+ sampler = val;
+}
diff --git a/modules/gltf/structures/gltf_texture.h b/modules/gltf/structures/gltf_texture.h
index b1d12dddfa..b26c8a7b07 100644
--- a/modules/gltf/structures/gltf_texture.h
+++ b/modules/gltf/structures/gltf_texture.h
@@ -39,6 +39,7 @@ class GLTFTexture : public Resource {
private:
GLTFImageIndex src_image = 0;
+ GLTFTextureSamplerIndex sampler = -1;
protected:
static void _bind_methods();
@@ -46,6 +47,8 @@ protected:
public:
GLTFImageIndex get_src_image() const;
void set_src_image(GLTFImageIndex val);
+ GLTFTextureSamplerIndex get_sampler() const;
+ void set_sampler(GLTFTextureSamplerIndex val);
};
#endif // GLTF_TEXTURE_H
diff --git a/modules/gltf/structures/gltf_texture_sampler.cpp b/modules/gltf/structures/gltf_texture_sampler.cpp
new file mode 100644
index 0000000000..6cf615b6cc
--- /dev/null
+++ b/modules/gltf/structures/gltf_texture_sampler.cpp
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* gltf_texture_sampler.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 "gltf_texture_sampler.h"
+
+void GLTFTextureSampler::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_mag_filter"), &GLTFTextureSampler::get_mag_filter);
+ ClassDB::bind_method(D_METHOD("set_mag_filter", "filter_mode"), &GLTFTextureSampler::set_mag_filter);
+ ClassDB::bind_method(D_METHOD("get_min_filter"), &GLTFTextureSampler::get_min_filter);
+ ClassDB::bind_method(D_METHOD("set_min_filter", "filter_mode"), &GLTFTextureSampler::set_min_filter);
+ ClassDB::bind_method(D_METHOD("get_wrap_s"), &GLTFTextureSampler::get_wrap_s);
+ ClassDB::bind_method(D_METHOD("set_wrap_s", "wrap_mode"), &GLTFTextureSampler::set_wrap_s);
+ ClassDB::bind_method(D_METHOD("get_wrap_t"), &GLTFTextureSampler::get_wrap_t);
+ ClassDB::bind_method(D_METHOD("set_wrap_t", "wrap_mode"), &GLTFTextureSampler::set_wrap_t);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mag_filter"), "set_mag_filter", "get_mag_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "min_filter"), "set_min_filter", "get_min_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_s"), "set_wrap_s", "get_wrap_s");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_t"), "set_wrap_t", "get_wrap_t");
+}
diff --git a/modules/gltf/structures/gltf_texture_sampler.h b/modules/gltf/structures/gltf_texture_sampler.h
new file mode 100644
index 0000000000..3fad31bbee
--- /dev/null
+++ b/modules/gltf/structures/gltf_texture_sampler.h
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* gltf_texture_sampler.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 GLTF_TEXTURE_SAMPLER_H
+#define GLTF_TEXTURE_SAMPLER_H
+
+#include "core/io/resource.h"
+#include "scene/resources/material.h"
+
+class GLTFTextureSampler : public Resource {
+ GDCLASS(GLTFTextureSampler, Resource);
+
+public:
+ enum FilterMode {
+ NEAREST = 9728,
+ LINEAR = 9729,
+ NEAREST_MIPMAP_NEAREST = 9984,
+ LINEAR_MIPMAP_NEAREST = 9985,
+ NEAREST_MIPMAP_LINEAR = 9986,
+ LINEAR_MIPMAP_LINEAR = 9987
+ };
+
+ enum WrapMode {
+ CLAMP_TO_EDGE = 33071,
+ MIRRORED_REPEAT = 33648,
+ REPEAT = 10497,
+ DEFAULT = REPEAT
+ };
+
+ int get_mag_filter() const {
+ return mag_filter;
+ }
+
+ void set_mag_filter(const int filter_mode) {
+ mag_filter = (FilterMode)filter_mode;
+ }
+
+ int get_min_filter() const {
+ return min_filter;
+ }
+
+ void set_min_filter(const int filter_mode) {
+ min_filter = (FilterMode)filter_mode;
+ }
+
+ int get_wrap_s() const {
+ return wrap_s;
+ }
+
+ void set_wrap_s(const int wrap_mode) {
+ wrap_s = (WrapMode)wrap_mode;
+ }
+
+ int get_wrap_t() const {
+ return wrap_t;
+ }
+
+ void set_wrap_t(const int wrap_mode) {
+ wrap_s = (WrapMode)wrap_mode;
+ }
+
+ StandardMaterial3D::TextureFilter get_filter_mode() const {
+ using TextureFilter = StandardMaterial3D::TextureFilter;
+
+ switch (min_filter) {
+ case NEAREST:
+ return TextureFilter::TEXTURE_FILTER_NEAREST;
+ case LINEAR:
+ return TextureFilter::TEXTURE_FILTER_LINEAR;
+ case NEAREST_MIPMAP_NEAREST:
+ case NEAREST_MIPMAP_LINEAR:
+ return TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS;
+ case LINEAR_MIPMAP_NEAREST:
+ case LINEAR_MIPMAP_LINEAR:
+ default:
+ return TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
+ }
+ }
+
+ void set_filter_mode(StandardMaterial3D::TextureFilter mode) {
+ using TextureFilter = StandardMaterial3D::TextureFilter;
+
+ switch (mode) {
+ case TextureFilter::TEXTURE_FILTER_NEAREST:
+ min_filter = FilterMode::NEAREST;
+ mag_filter = FilterMode::NEAREST;
+ break;
+ case TextureFilter::TEXTURE_FILTER_LINEAR:
+ min_filter = FilterMode::LINEAR;
+ mag_filter = FilterMode::LINEAR;
+ break;
+ case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
+ case TextureFilter::TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC:
+ min_filter = FilterMode::NEAREST_MIPMAP_LINEAR;
+ mag_filter = FilterMode::NEAREST;
+ break;
+ case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
+ case TextureFilter::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC:
+ default:
+ min_filter = FilterMode::LINEAR_MIPMAP_LINEAR;
+ mag_filter = FilterMode::LINEAR;
+ break;
+ }
+ }
+
+ bool get_wrap_mode() const {
+ // BaseMaterial3D presents wrapping as a boolean property. Either the texture is repeated
+ // in both dimensions, non-mirrored, or it isn't repeated at all. This will cause oddities
+ // when people import models having other wrapping mode combinations.
+ return (wrap_s == WrapMode::REPEAT) && (wrap_t == WrapMode::REPEAT);
+ }
+
+ void set_wrap_mode(bool mat_repeats) {
+ if (mat_repeats) {
+ wrap_s = WrapMode::REPEAT;
+ wrap_t = WrapMode::REPEAT;
+ } else {
+ wrap_s = WrapMode::CLAMP_TO_EDGE;
+ wrap_t = WrapMode::CLAMP_TO_EDGE;
+ }
+ }
+
+protected:
+ static void _bind_methods();
+
+private:
+ FilterMode mag_filter = FilterMode::LINEAR;
+ FilterMode min_filter = FilterMode::LINEAR_MIPMAP_LINEAR;
+ WrapMode wrap_s = WrapMode::REPEAT;
+ WrapMode wrap_t = WrapMode::REPEAT;
+};
+
+VARIANT_ENUM_CAST(GLTFTextureSampler::FilterMode);
+VARIANT_ENUM_CAST(GLTFTextureSampler::WrapMode);
+
+#endif // GLTF_TEXTURE_SAMPLER_H
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index b5afd8507d..9c6cbebf0e 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -617,7 +617,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
}
if (mb->is_pressed()) {
- Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation/navigation_scheme").operator int();
+ Node3DEditorViewport::NavigationScheme nav_scheme = (Node3DEditorViewport::NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int();
if ((nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA || nav_scheme == Node3DEditorViewport::NAVIGATION_MODO) && mb->is_alt_pressed()) {
input_action = INPUT_NONE;
} else if (mb->get_button_index() == MouseButton::LEFT) {
@@ -1434,7 +1434,7 @@ GridMapEditor::~GridMapEditor() {
void GridMapEditorPlugin::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) {
+ switch ((int)EDITOR_GET("editors/grid_map/editor_side")) {
case 0: { // Left.
Node3DEditor::get_singleton()->move_control_to_left_panel(grid_map_editor);
} break;
@@ -1472,7 +1472,7 @@ GridMapEditorPlugin::GridMapEditorPlugin() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/grid_map/editor_side", PROPERTY_HINT_ENUM, "Left,Right"));
grid_map_editor = memnew(GridMapEditor);
- switch ((int)EditorSettings::get_singleton()->get("editors/grid_map/editor_side")) {
+ switch ((int)EDITOR_GET("editors/grid_map/editor_side")) {
case 0: { // Left.
Node3DEditor::get_singleton()->add_control_to_left_panel(grid_map_editor);
} break;
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index a64dc4a80b..6fd38d9445 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -241,7 +241,7 @@ protected:
void _notification(int p_what);
public:
- virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const override { return "GridMap"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 05ce2b6147..de50e9ea1e 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -157,13 +157,13 @@ uint32_t GridMap::get_collision_mask() const {
void GridMap::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t collision_layer = get_collision_layer();
+ uint32_t collision_layer_new = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << (p_layer_number - 1);
+ collision_layer_new |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << (p_layer_number - 1));
+ collision_layer_new &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(collision_layer);
+ set_collision_layer(collision_layer_new);
}
bool GridMap::get_collision_layer_value(int p_layer_number) const {
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 6f0bc16a26..457b263e16 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -140,7 +140,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField
}
}
- p_image->create(width, height, false, Image::FORMAT_RGBE9995, imgdata);
+ p_image->set_data(width, height, false, Image::FORMAT_RGBE9995, imgdata);
return OK;
}
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index ce20ac9060..9bbe467352 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -33,8 +33,8 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include "thirdparty/jpeg-compressor/jpgd.h"
-#include "thirdparty/jpeg-compressor/jpge.h"
+#include <jpgd.h>
+#include <jpge.h>
#include <string.h>
Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p_buffer_len) {
@@ -99,7 +99,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
fmt = Image::FORMAT_RGB8;
}
- p_image->create(image_width, image_height, false, fmt, data);
+ p_image->set_data(image_width, image_height, false, fmt, data);
return OK;
}
@@ -132,10 +132,6 @@ static Ref<Image> _jpegd_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-static Error _jpgd_save_func(const String &p_path, const Ref<Image> &p_img, float p_quality) {
- return OK;
-}
-
class ImageLoaderJPGOSFile : public jpge::output_stream {
public:
Ref<FileAccess> f;
@@ -157,21 +153,18 @@ public:
}
};
-static Vector<uint8_t> _jpgd_buffer_save_func(const Ref<Image> &p_img, float p_quality) {
- ERR_FAIL_COND_V(p_img.is_null() || p_img->is_empty(), Vector<uint8_t>());
+static Error _jpgd_save_to_output_stream(jpge::output_stream *p_output_stream, const Ref<Image> &p_img, float p_quality) {
+ ERR_FAIL_COND_V(p_img.is_null() || p_img->is_empty(), ERR_INVALID_PARAMETER);
Ref<Image> image = p_img;
if (image->get_format() != Image::FORMAT_RGB8) {
- image->convert(Image::FORMAT_ETC2_RGB8);
+ image->convert(Image::FORMAT_RGB8);
}
jpge::params p;
p.m_quality = CLAMP(p_quality * 100, 1, 100);
- Vector<uint8_t> output;
- ImageLoaderJPGOSBuffer ob;
- ob.buffer = &output;
jpge::jpeg_encoder enc;
- enc.init(&ob, image->get_width(), image->get_height(), 3, p);
+ enc.init(p_output_stream, image->get_width(), image->get_height(), 3, p);
const uint8_t *src_data = image->get_data().ptr();
for (int i = 0; i < image->get_height(); i++) {
@@ -180,9 +173,28 @@ static Vector<uint8_t> _jpgd_buffer_save_func(const Ref<Image> &p_img, float p_q
enc.process_scanline(nullptr);
+ return OK;
+}
+
+static Vector<uint8_t> _jpgd_buffer_save_func(const Ref<Image> &p_img, float p_quality) {
+ Vector<uint8_t> output;
+ ImageLoaderJPGOSBuffer ob;
+ ob.buffer = &output;
+ if (_jpgd_save_to_output_stream(&ob, p_img, p_quality) != OK) {
+ return Vector<uint8_t>();
+ }
return output;
}
+static Error _jpgd_save_func(const String &p_path, const Ref<Image> &p_img, float p_quality) {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save JPG at path: '%s'.", p_path));
+ ImageLoaderJPGOSFile ob;
+ ob.f = file;
+ return _jpgd_save_to_output_stream(&ob, p_img, p_quality);
+}
+
ImageLoaderJPG::ImageLoaderJPG() {
Image::_jpg_mem_loader_func = _jpegd_mem_loader_func;
Image::save_jpg_func = _jpgd_save_func;
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 5b039e65c0..9111827c1b 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -251,15 +251,11 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
}
for (int i = 0; i < atlas_slices; i++) {
- Ref<Image> albedo;
- albedo.instantiate();
- albedo->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBA8);
+ Ref<Image> albedo = Image::create_empty(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBA8);
albedo->set_as_black();
albedo_images.write[i] = albedo;
- Ref<Image> emission;
- emission.instantiate();
- emission->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH);
+ Ref<Image> emission = Image::create_empty(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH);
emission->set_as_black();
emission_images.write[i] = emission;
}
@@ -278,7 +274,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
return BAKE_OK;
}
-void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
+void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &p_probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
HashMap<Vertex, uint32_t, VertexHash> vertex_map;
//fill triangles array and vertex array
@@ -403,8 +399,8 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
}
//also consider probe positions for bounds
- for (int i = 0; i < probe_positions.size(); i++) {
- Vector3 pp(probe_positions[i].position[0], probe_positions[i].position[1], probe_positions[i].position[2]);
+ for (int i = 0; i < p_probe_positions.size(); i++) {
+ Vector3 pp(p_probe_positions[i].position[0], p_probe_positions[i].position[1], p_probe_positions[i].position[2]);
bounds.expand_to(pp);
}
bounds.grow_by(0.1); //grow a bit to avoid numerical error
@@ -478,9 +474,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
grid_usage.write[j] = count > 0 ? 255 : 0;
}
- Ref<Image> img;
- img.instantiate();
- img->create(grid_size, grid_size, false, Image::FORMAT_L8, grid_usage);
+ Ref<Image> img = Image::create_from_data(grid_size, grid_size, false, Image::FORMAT_L8, grid_usage);
img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png");
}
#endif
@@ -520,7 +514,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
}
seams_buffer = rd->storage_buffer_create(sb.size(), sb);
- Vector<uint8_t> pb = probe_positions.to_byte_array();
+ Vector<uint8_t> pb = p_probe_positions.to_byte_array();
if (pb.size() == 0) {
pb.resize(sizeof(Probe));
}
@@ -660,9 +654,7 @@ LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShade
#ifdef DEBUG_TEXTURES
for (int i = 0; i < atlas_slices; i++) {
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBA8);
img->save_png("res://5_dilated_" + itos(i) + ".png");
}
@@ -778,7 +770,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
panorama_tex->convert(Image::FORMAT_RGBAF);
} else {
panorama_tex.instantiate();
- panorama_tex->create(8, 8, false, Image::FORMAT_RGBAF);
+ panorama_tex->initialize_data(8, 8, false, Image::FORMAT_RGBAF);
panorama_tex->fill(Color(0, 0, 0, 1));
}
@@ -953,13 +945,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int i = 0; i < atlas_slices; i++) {
Vector<uint8_t> s = rd->texture_get_data(position_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
img->save_exr("res://1_position_" + itos(i) + ".exr", false);
s = rd->texture_get_data(normal_tex, i);
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ img->set_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->save_exr("res://1_normal_" + itos(i) + ".exr", false);
}
#endif
@@ -1182,9 +1172,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int i = 0; i < atlas_slices; i++) {
Vector<uint8_t> s = rd->texture_get_data(light_source_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false);
}
#endif
@@ -1415,14 +1403,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
#if 0
for (int i = 0; i < probe_positions.size(); i++) {
- Ref<Image> img;
- img.instantiate();
- img->create(6, 4, false, Image::FORMAT_RGB8);
+ Ref<Image> img = Image::create_empty(6, 4, false, Image::FORMAT_RGB8);
for (int j = 0; j < 6; j++) {
Vector<uint8_t> s = rd->texture_get_data(lightprobe_tex, i * 6 + j);
- Ref<Image> img2;
- img2.instantiate();
- img2->create(2, 2, false, Image::FORMAT_RGBAF, s);
+ Ref<Image> img2 = Image::create_from_data(2, 2, false, Image::FORMAT_RGBAF, s);
img2->convert(Image::FORMAT_RGB8);
img->blit_rect(img2, Rect2i(0, 0, 2, 2), Point2i((j % 3) * 2, (j / 3) * 2));
}
@@ -1449,9 +1433,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (denoiser.is_valid()) {
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
Ref<Image> denoised = denoiser->denoise_image(img);
if (denoised != img) {
@@ -1484,9 +1466,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
}
#endif
@@ -1640,9 +1620,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
}
#endif
@@ -1652,9 +1630,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
img->convert(Image::FORMAT_RGBH); //remove alpha
bake_textures.push_back(img);
}
@@ -1667,9 +1643,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
#ifdef DEBUG_TEXTURES
{
- Ref<Image> img2;
- img2.instantiate();
- img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data);
+ Ref<Image> img2 = Image::create_from_data(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data);
img2->save_exr("res://6_lightprobes.exr", false);
}
#endif
diff --git a/modules/mono/.gitignore b/modules/mono/.gitignore
index fa6d00cbbb..2d62f9f88a 100644
--- a/modules/mono/.gitignore
+++ b/modules/mono/.gitignore
@@ -1,2 +1,5 @@
# Do not ignore solution files inside the mono module. Overrides Godot's global gitignore.
!*.sln
+
+# Generated by build_assemblies.py.
+SdkPackageVersions.props
diff --git a/modules/mono/Directory.Build.targets b/modules/mono/Directory.Build.targets
index 98410b93ae..e666b3ac9d 100644
--- a/modules/mono/Directory.Build.targets
+++ b/modules/mono/Directory.Build.targets
@@ -2,6 +2,8 @@
<PropertyGroup>
<_HasNuGetPackage Condition=" '$(_HasNuGetPackage)' == '' And '$(PackageId)' != '' And '$(GeneratePackageOnBuild.ToLower())' == 'true' ">true</_HasNuGetPackage>
<_HasNuGetPackage Condition=" '$(_HasNuGetPackage)' == '' ">false</_HasNuGetPackage>
+ <_HasSymbolsNuGetPackage Condition=" '$(_HasSymbolsNuGetPackage)' == '' And '$(PackageId)' != '' And '$(IncludeSymbols.ToLower())' == 'true' And '$(SymbolPackageFormat)' == 'snupkg' ">true</_HasSymbolsNuGetPackage>
+ <_HasSymbolsNuGetPackage Condition=" '$(_HasSymbolsNuGetPackage)' == '' ">false</_HasSymbolsNuGetPackage>
</PropertyGroup>
<Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack"
Condition=" '$(_HasNuGetPackage)' == 'true' ">
@@ -10,13 +12,15 @@
<GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
</PropertyGroup>
<Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
+ <Copy Condition=" '$(_HasSymbolsNuGetPackage)' == 'true' " SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).snupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
</Target>
<Target Name="PushNuGetPackagesToLocalSource" BeforeTargets="Pack"
Condition=" '$(_HasNuGetPackage)' == 'true' And '$(PushNuGetToLocalSource)' != '' ">
<Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(PushNuGetToLocalSource)\" />
+ <Copy Condition=" '$(_HasSymbolsNuGetPackage)' == 'true' " SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).snupkg" DestinationFolder="$(PushNuGetToLocalSource)\" />
</Target>
<Target Name="ClearNuGetLocalPackageCache" BeforeTargets="Pack"
Condition=" '$(_HasNuGetPackage)' == 'true' And '$(ClearNuGetLocalCache.ToLower())' == 'true' ">
- <RemoveDir Directories="$(NugetPackageRoot)/$(PackageId.ToLower())/$(PackageVersion)"/>
+ <RemoveDir Directories="$(NugetPackageRoot)/$(PackageId.ToLower())/$(PackageVersion)" />
</Target>
</Project>
diff --git a/modules/mono/SdkPackageVersions.props b/modules/mono/SdkPackageVersions.props
deleted file mode 100644
index 65094aa34f..0000000000
--- a/modules/mono/SdkPackageVersions.props
+++ /dev/null
@@ -1,8 +0,0 @@
-<Project>
- <PropertyGroup>
- <PackageFloatingVersion_Godot>4.0.*-*</PackageFloatingVersion_Godot>
- <PackageVersion_GodotSharp>4.0.0-dev</PackageVersion_GodotSharp>
- <PackageVersion_Godot_NET_Sdk>4.0.0-dev8</PackageVersion_Godot_NET_Sdk>
- <PackageVersion_Godot_SourceGenerators>4.0.0-dev8</PackageVersion_Godot_SourceGenerators>
- </PropertyGroup>
-</Project>
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index d28c3a0c3a..7343af0b39 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -256,7 +256,57 @@ def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, flo
return 0
+def generate_sdk_package_versions():
+ # I can't believe importing files in Python is so convoluted when not
+ # following the golden standard for packages/modules.
+ import os
+ import sys
+ from os.path import dirname
+
+ # We want ../../../methods.py.
+ script_path = dirname(os.path.abspath(__file__))
+ root_path = dirname(dirname(dirname(script_path)))
+
+ sys.path.insert(0, root_path)
+ from methods import get_version_info
+
+ version_info = get_version_info("")
+ sys.path.remove(root_path)
+
+ version_str = "{major}.{minor}.{patch}".format(**version_info)
+ version_status = version_info["status"]
+ if version_status != "stable": # Pre-release
+ # If version was overridden to be e.g. "beta3", we insert a dot between
+ # "beta" and "3" to follow SemVer 2.0.
+ import re
+
+ match = re.search(r"[\d]+$", version_status)
+ if match:
+ pos = match.start()
+ version_status = version_status[:pos] + "." + version_status[pos:]
+ version_str += "-" + version_status
+
+ props = """<Project>
+ <PropertyGroup>
+ <PackageVersion_GodotSharp>{0}</PackageVersion_GodotSharp>
+ <PackageVersion_Godot_NET_Sdk>{0}</PackageVersion_Godot_NET_Sdk>
+ <PackageVersion_Godot_SourceGenerators>{0}</PackageVersion_Godot_SourceGenerators>
+ </PropertyGroup>
+</Project>
+""".format(
+ version_str
+ )
+
+ # We write in ../SdkPackageVersions.props.
+ with open(os.path.join(dirname(script_path), "SdkPackageVersions.props"), "w") as f:
+ f.write(props)
+ f.close()
+
+
def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local, float_size):
+ # Generate SdkPackageVersions.props
+ generate_sdk_package_versions()
+
# Godot API
exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local, float_size)
if exit_code != 0:
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index c4547b4323..1f4b085bfb 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -227,8 +227,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'.");
- JSON json;
- f->store_string(json.stringify(classes_dict, "\t"));
+ f->store_string(JSON::stringify(classes_dict, "\t"));
print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file));
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 97a1d5c8d8..345d2e4694 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2398,9 +2398,9 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
if (EngineDebugger::is_active()) {
CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
"Script inherits from native type '" + String(native_name) +
- "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
+ "', so it can't be assigned to an object of type: '" + p_this->get_class() + "'");
}
- ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'.");
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be assigned to an object of type: '" + p_this->get_class() + "'.");
}
Callable::CallError unchecked_error;
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index d469c28d4a..e5e53acb07 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -48,20 +48,10 @@ class CSharpScript;
class CSharpInstance;
class CSharpLanguage;
-#ifdef NO_SAFE_CAST
-template <typename TScriptInstance, typename TScriptLanguage>
-TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
- if (!p_inst) {
- return nullptr;
- }
- return p_inst->get_language() == TScriptLanguage::get_singleton() ? static_cast<TScriptInstance *>(p_inst) : nullptr;
-}
-#else
template <typename TScriptInstance, typename TScriptLanguage>
TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
return dynamic_cast<TScriptInstance *>(p_inst);
}
-#endif
#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
index 7ec3f88e5d..19fdd51dab 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -56,7 +56,7 @@ namespace GodotPlugins.Game
}
";
- context.AddSource("GodotPlugins.Game_Generated",
+ context.AddSource("GodotPlugins.Game.generated",
SourceText.From(source, Encoding.UTF8));
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 1ee31eb1a9..d5d80df643 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -87,7 +87,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptMethods_Generated";
+ + "_ScriptMethods.generated";
var source = new StringBuilder();
@@ -188,14 +188,14 @@ namespace Godot.SourceGenerators
if (godotClassMethods.Length > 0)
{
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
- source.Append("NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n {\n");
+ source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
foreach (var method in godotClassMethods)
{
GenerateMethodInvoker(method, source);
}
- source.Append(" return base.InvokeGodotClassMethod(method, args, argCount, out ret);\n");
+ source.Append(" return base.InvokeGodotClassMethod(method, args, out ret);\n");
source.Append(" }\n");
}
@@ -364,7 +364,7 @@ namespace Godot.SourceGenerators
source.Append(" if (method == MethodName.");
source.Append(methodName);
- source.Append(" && argCount == ");
+ source.Append(" && args.Count == ");
source.Append(method.ParamTypes.Length);
source.Append(") {\n");
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index e8a9e28d0c..ccfb405d26 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -96,8 +96,8 @@ namespace Godot.SourceGenerators
string.Empty;
bool hasNamespace = classNs.Length != 0;
- var uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPath_Generated";
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPath.generated";
var source = new StringBuilder();
@@ -126,7 +126,7 @@ namespace Godot.SourceGenerators
source.Append("\n}\n");
}
- context.AddSource(uniqueHint.ToString(), SourceText.From(source.ToString(), Encoding.UTF8));
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
}
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
@@ -157,7 +157,7 @@ namespace Godot.SourceGenerators
sourceBuilder.Append("})]\n");
- context.AddSource("AssemblyScriptTypes_Generated",
+ context.AddSource("AssemblyScriptTypes.generated",
SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index b331e2e794..1198c633d9 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptProperties_Generated";
+ + "_ScriptProperties.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
index 65dadcb801..98b9745c16 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptPropertyDefVal_Generated";
+ + "_ScriptPropertyDefVal.generated";
var source = new StringBuilder();
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
index a40220565f..11e0a6fa21 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -73,7 +73,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSerialization_Generated";
+ + "_ScriptSerialization.generated";
var source = new StringBuilder();
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 ea7cc3fe38..50196b84f0 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -82,7 +82,7 @@ namespace Godot.SourceGenerators
bool isInnerClass = symbol.ContainingType != null;
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
- + "_ScriptSignals_Generated";
+ + "_ScriptSignals.generated";
var source = new StringBuilder();
@@ -167,6 +167,7 @@ namespace Godot.SourceGenerators
Common.ReportSignalDelegateSignatureMustReturnVoid(context, signalDelegateSymbol);
}
}
+
continue;
}
@@ -257,14 +258,14 @@ namespace Godot.SourceGenerators
{
source.Append(
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
- source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
+ source.Append("NativeVariantPtrArgs args)\n {\n");
foreach (var signal in godotSignalDelegates)
{
GenerateSignalEventInvoker(signal, source);
}
- source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
+ source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args);\n");
source.Append(" }\n");
}
@@ -404,7 +405,7 @@ namespace Godot.SourceGenerators
source.Append(" if (signal == SignalName.");
source.Append(signalName);
- source.Append(" && argCount == ");
+ source.Append(" && args.Count == ");
source.Append(invokeMethodData.ParamTypes.Length);
source.Append(") {\n");
source.Append(" backing_");
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 0d2bea2363..745a8b73f8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -17,6 +17,8 @@ namespace GodotTools.Export
{
public partial class ExportPlugin : EditorExportPlugin
{
+ private List<string> _tempFolders = new List<string>();
+
public void RegisterExportSettings()
{
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
@@ -111,62 +113,78 @@ namespace GodotTools.Export
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
- // TODO: This works for now, as we only implemented support for x86 family desktop so far, but it needs to be fixed
- string arch = features.Contains("x86_64") ? "x86_64" : "x86";
-
- string ridOS = DetermineRuntimeIdentifierOS(platform);
- string ridArch = DetermineRuntimeIdentifierArch(arch);
- string runtimeIdentifier = $"{ridOS}-{ridArch}";
-
- // Create temporary publish output directory
-
- string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
- $"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
-
- if (!Directory.Exists(publishOutputTempDir))
- Directory.CreateDirectory(publishOutputTempDir);
-
- // Execute dotnet publish
-
- if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
- runtimeIdentifier, publishOutputTempDir))
+ var archs = new List<string>();
+ if (features.Contains("x86_64"))
{
- throw new InvalidOperationException("Failed to build project.");
+ archs.Add("x86_64");
}
-
- string soExt = ridOS switch
+ else if (features.Contains("x86_32"))
{
- OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
- OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
- _ => "so"
- };
-
- if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
- // NativeAOT shared library output
- && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
+ archs.Add("x86_32");
+ }
+ else if (features.Contains("arm64"))
{
- throw new NotSupportedException(
- "Publish succeeded but project assembly not found in the output directory");
+ archs.Add("arm64");
}
-
- // Copy all files from the dotnet publish output directory to
- // a data directory next to the Godot output executable.
-
- string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
-
- if (Directory.Exists(outputDataDir))
- Directory.Delete(outputDataDir, recursive: true); // Clean first
-
- Directory.CreateDirectory(outputDataDir);
-
- foreach (string dir in Directory.GetDirectories(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ else if (features.Contains("universal"))
{
- Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(publishOutputTempDir.Length + 1)));
+ if (platform == OS.Platforms.MacOS)
+ {
+ archs.Add("x86_64");
+ archs.Add("arm64");
+ }
}
- foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ foreach (var arch in archs)
{
- File.Copy(file, Path.Combine(outputDataDir, file.Substring(publishOutputTempDir.Length + 1)));
+ string ridOS = DetermineRuntimeIdentifierOS(platform);
+ string ridArch = DetermineRuntimeIdentifierArch(arch);
+ string runtimeIdentifier = $"{ridOS}-{ridArch}";
+ string projectDataDirName = $"{DetermineDataDirNameForProject()}_{arch}";
+ if (platform == OS.Platforms.MacOS)
+ {
+ projectDataDirName = Path.Combine("Contents", "Resources", projectDataDirName);
+ }
+
+ // Create temporary publish output directory
+
+ string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
+ $"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
+
+ _tempFolders.Add(publishOutputTempDir);
+
+ if (!Directory.Exists(publishOutputTempDir))
+ Directory.CreateDirectory(publishOutputTempDir);
+
+ // Execute dotnet publish
+
+ if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
+ runtimeIdentifier, publishOutputTempDir))
+ {
+ throw new InvalidOperationException("Failed to build project.");
+ }
+
+ string soExt = ridOS switch
+ {
+ OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
+ OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
+ _ => "so"
+ };
+
+ if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
+ // NativeAOT shared library output
+ && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
+ {
+ throw new NotSupportedException(
+ "Publish succeeded but project assembly not found in the output directory");
+ }
+
+ // Add to the exported project shared object list.
+
+ foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
+ {
+ AddSharedObject(file, tags: null, projectDataDirName);
+ }
}
}
@@ -198,6 +216,12 @@ namespace GodotTools.Export
if (Directory.Exists(aotTempDir))
Directory.Delete(aotTempDir, recursive: true);
+ foreach (string folder in _tempFolders)
+ {
+ Directory.Delete(folder, recursive: true);
+ }
+ _tempFolders.Clear();
+
// TODO: The following is just a workaround until the export plugins can be made to abort with errors
// We check for empty as well, because it's set to empty after hot-reloading
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 95a44d3b7e..b90321b586 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1614,7 +1614,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
<< " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, "
- << "NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n"
+ << "NativeVariantPtrArgs args, out godot_variant ret)\n"
<< INDENT1 "{\n";
for (const MethodInterface &imethod : itype.methods) {
@@ -1630,7 +1630,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// We check both native names (snake_case) and proxy names (PascalCase)
output << INDENT2 "if ((method == " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
<< " || method == MethodName." << imethod.proxy_name
- << ") && argCount == " << itos(imethod.arguments.size())
+ << ") && args.Count == " << itos(imethod.arguments.size())
<< " && " << CS_METHOD_HAS_GODOT_CLASS_METHOD << "((godot_string_name)"
<< CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << ".NativeValue))\n"
<< INDENT2 "{\n";
@@ -1682,7 +1682,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
if (is_derived_type) {
- output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, argCount, out ret);\n";
+ output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, out ret);\n";
} else {
output << INDENT2 "ret = default;\n"
<< INDENT2 "return false;\n";
@@ -2200,6 +2200,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output) {
String arguments_sig;
+ String delegate_type_params;
+
+ if (!p_isignal.arguments.is_empty()) {
+ delegate_type_params += "<";
+ }
// Retrieve information from the arguments
const ArgumentInterface &first = p_isignal.arguments.front()->get();
@@ -2220,11 +2225,18 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
if (&iarg != &first) {
arguments_sig += ", ";
+ delegate_type_params += ", ";
}
arguments_sig += arg_type->cs_type;
arguments_sig += " ";
arguments_sig += iarg.name;
+
+ delegate_type_params += arg_type->cs_type;
+ }
+
+ if (!p_isignal.arguments.is_empty()) {
+ delegate_type_params += ">";
}
// Generate signal
@@ -2248,15 +2260,46 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("\")]");
}
- String delegate_name = p_isignal.proxy_name;
- delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
+ bool is_parameterless = p_isignal.arguments.size() == 0;
- // 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");
+ // Delegate name is [SignalName]EventHandler
+ String delegate_name = is_parameterless ? "Action" : p_isignal.proxy_name + "EventHandler";
+
+ if (!is_parameterless) {
+ // 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");
+
+ // Generate Callable trampoline for the delegate
+ p_output << MEMBER_BEGIN "private static unsafe void " << p_isignal.proxy_name << "Trampoline"
+ << "(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)\n"
+ << INDENT1 "{\n"
+ << INDENT2 "Callable.ThrowIfArgCountMismatch(args, " << itos(p_isignal.arguments.size()) << ");\n"
+ << INDENT2 "((" << delegate_name << ")delegateObj)(";
+
+ int idx = 0;
+ for (const ArgumentInterface &iarg : p_isignal.arguments) {
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
+
+ if (idx != 0) {
+ p_output << ",";
+ }
+
+ // TODO: We don't need to use VariantConversionCallbacks. We have the type information so we can use [cs_variant_to_managed] and [cs_managed_to_variant].
+ p_output << "\n" INDENT3 "VariantConversionCallbacks.GetToManagedCallback<"
+ << arg_type->cs_type << ">()(args[" << itos(idx) << "])";
+
+ idx++;
+ }
+
+ p_output << ");\n"
+ << INDENT2 "ret = default;\n"
+ << INDENT1 "}\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);
@@ -2292,6 +2335,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("static ");
}
+ if (!is_parameterless) {
+ // `unsafe` is needed for taking the trampoline's function pointer
+ p_output << "unsafe ";
+ }
+
p_output.append("event ");
p_output.append(delegate_name);
p_output.append(" ");
@@ -2304,8 +2352,13 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append("add => Connect(SignalName.");
}
- p_output.append(p_isignal.proxy_name);
- p_output.append(", new Callable(value));\n");
+ if (is_parameterless) {
+ // Delegate type is Action. No need for custom trampoline.
+ p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
+ } else {
+ p_output << p_isignal.proxy_name
+ << ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
+ }
if (p_itype.is_singleton) {
p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName.");
@@ -2313,8 +2366,14 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(INDENT2 "remove => Disconnect(SignalName.");
}
- p_output.append(p_isignal.proxy_name);
- p_output.append(", new Callable(value));\n");
+ if (is_parameterless) {
+ // Delegate type is Action. No need for custom trampoline.
+ p_output << p_isignal.proxy_name << ", Callable.From(value));\n";
+ } else {
+ p_output << p_isignal.proxy_name
+ << ", Callable.CreateWithUnsafeTrampoline(value, &" << p_isignal.proxy_name << "Trampoline));\n";
+ }
+
p_output.append(CLOSE_BLOCK_L1);
}
@@ -3119,9 +3178,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
for (const KeyValue<StringName, ClassDB::ClassInfo::EnumInfo> &E : enum_map) {
StringName enum_proxy_cname = E.key;
String enum_proxy_name = enum_proxy_cname.operator String();
- if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
- // We have several conflicts between enums and PascalCase properties,
- // so we append 'Enum' to the enum name in those cases.
+ if (itype.find_property_by_proxy_name(enum_proxy_name) || itype.find_method_by_proxy_name(enum_proxy_name) || itype.find_signal_by_proxy_name(enum_proxy_name)) {
+ // In case the enum name conflicts with other PascalCase members,
+ // we append 'Enum' to the enum name in those cases.
+ // We have several conflicts between enums and PascalCase properties.
enum_proxy_name += "Enum";
enum_proxy_cname = StringName(enum_proxy_name);
}
@@ -3170,7 +3230,15 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
int64_t *value = class_info->constant_map.getptr(StringName(constant_name));
ERR_FAIL_NULL_V(value, false);
- ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
+ String constant_proxy_name = snake_to_pascal_case(constant_name, true);
+
+ if (itype.find_property_by_proxy_name(constant_proxy_name) || itype.find_method_by_proxy_name(constant_proxy_name) || itype.find_signal_by_proxy_name(constant_proxy_name)) {
+ // In case the constant name conflicts with other PascalCase members,
+ // we append 'Constant' to the constant name in those cases.
+ constant_proxy_name += "Constant";
+ }
+
+ ConstantInterface iconstant(constant_name, constant_proxy_name, *value);
iconstant.const_doc = nullptr;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -3326,11 +3394,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
case Variant::PROJECTION: {
- Projection transform = p_val.operator Projection();
- if (transform == Projection()) {
+ Projection projection = p_val.operator Projection();
+ if (projection == Projection()) {
r_iarg.default_argument = "Projection.Identity";
} else {
- r_iarg.default_argument = "new Projection(new Vector4" + transform.matrix[0].operator String() + ", new Vector4" + transform.matrix[1].operator String() + ", new Vector4" + transform.matrix[2].operator String() + ", new Vector4" + transform.matrix[3].operator String() + ")";
+ r_iarg.default_argument = "new Projection(new Vector4" + projection.columns[0].operator String() + ", new Vector4" + projection.columns[1].operator String() + ", new Vector4" + projection.columns[2].operator String() + ", new Vector4" + projection.columns[3].operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 40296eef10..dc69567261 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -140,7 +140,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::RESOURCE_PATHS: {
- if (bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
+ if (bool(EDITOR_GET("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), suggestions);
}
} break;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index 1c98dfcdf6..f1b46e293b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -489,25 +489,37 @@ namespace Godot.Collections
ICollection<T>,
IEnumerable<T>
{
+ private static godot_variant ToVariantFunc(in Array<T> godotArray) =>
+ VariantUtils.CreateFromArray(godotArray);
+
+ private static Array<T> FromVariantFunc(in godot_variant variant) =>
+ VariantUtils.ConvertToArrayObject<T>(variant);
+
// ReSharper disable StaticMemberInGenericType
// Warning is about unique static fields being created for each generic type combination:
// https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
// In our case this is exactly what we want.
- private static unsafe delegate* managed<in T, godot_variant> _convertToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, T> _convertToManagedCallback;
+ private static readonly unsafe delegate* managed<in T, godot_variant> ConvertToVariantCallback;
+ private static readonly unsafe delegate* managed<in godot_variant, T> ConvertToManagedCallback;
// ReSharper restore StaticMemberInGenericType
static unsafe Array()
{
- _convertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
- _convertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
+ VariantConversionCallbacks.GenericConversionCallbacks[typeof(Array<T>)] =
+ (
+ (IntPtr)(delegate* managed<in Array<T>, godot_variant>)&ToVariantFunc,
+ (IntPtr)(delegate* managed<in godot_variant, Array<T>>)&FromVariantFunc
+ );
+
+ ConvertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
+ ConvertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
}
private static unsafe void ValidateVariantConversionCallbacks()
{
- if (_convertToVariantCallback == null || _convertToManagedCallback == null)
+ if (ConvertToVariantCallback == null || ConvertToManagedCallback == null)
{
throw new InvalidOperationException(
$"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
@@ -653,7 +665,7 @@ namespace Godot.Collections
get
{
_underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
- return _convertToManagedCallback(borrowElem);
+ return ConvertToManagedCallback(borrowElem);
}
set
{
@@ -663,7 +675,7 @@ namespace Godot.Collections
godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
godot_variant* itemPtr = &ptrw[index];
(*itemPtr).Dispose();
- *itemPtr = _convertToVariantCallback(value);
+ *itemPtr = ConvertToVariantCallback(value);
}
}
@@ -675,7 +687,7 @@ namespace Godot.Collections
/// <returns>The index of the item, or -1 if not found.</returns>
public unsafe int IndexOf(T item)
{
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
@@ -693,7 +705,7 @@ namespace Godot.Collections
if (index < 0 || index > Count)
throw new ArgumentOutOfRangeException(nameof(index));
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
}
@@ -726,7 +738,7 @@ namespace Godot.Collections
/// <returns>The new size after adding the item.</returns>
public unsafe void Add(T item)
{
- using var variantValue = _convertToVariantCallback(item);
+ using var variantValue = ConvertToVariantCallback(item);
var self = (godot_array)_underlyingArray.NativeValue;
_ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
index ae44f8f4ba..354212da1b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -22,8 +22,7 @@ namespace Godot.Bridge
}
bool methodInvoked = godotObject.InvokeGodotClassMethod(CustomUnsafe.AsRef(method),
- new NativeVariantPtrArgs(args),
- argCount, out godot_variant retValue);
+ new NativeVariantPtrArgs(args, argCount), out godot_variant retValue);
if (!methodInvoked)
{
@@ -102,7 +101,7 @@ namespace Godot.Bridge
return godot_bool.False;
}
- *outRet = Marshaling.ConvertManagedObjectToVariant(ret);
+ *outRet = ret.CopyNativeVariant();
return godot_bool.True;
}
catch (Exception e)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index 57240624bc..44ea8fc83d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -9,7 +9,7 @@ namespace Godot.Bridge
{
// @formatter:off
public delegate* unmanaged<IntPtr, godot_variant**, int, godot_bool*, void> SignalAwaiter_SignalCallback;
- public delegate* unmanaged<IntPtr, godot_variant**, uint, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
+ public delegate* unmanaged<IntPtr, void*, godot_variant**, int, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
public delegate* unmanaged<IntPtr, godot_array*, godot_bool> DelegateUtils_TrySerializeDelegateWithGCHandle;
public delegate* unmanaged<godot_array*, IntPtr*, godot_bool> DelegateUtils_TryDeserializeDelegateWithGCHandle;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 092724a6b1..d83cf43eb2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -339,7 +339,7 @@ namespace Godot.Bridge
*outOwnerIsNull = godot_bool.False;
owner.RaiseGodotClassSignalCallbacks(CustomUnsafe.AsRef(eventSignalName),
- new NativeVariantPtrArgs(args), argCount);
+ new NativeVariantPtrArgs(args, argCount));
}
catch (Exception e)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
index bdedd2e87a..f9309ca13e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -26,11 +26,12 @@ namespace Godot
/// }
/// </code>
/// </example>
- public readonly struct Callable
+ public readonly partial struct Callable
{
private readonly Object _target;
private readonly StringName _method;
private readonly Delegate _delegate;
+ private readonly unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> _trampoline;
/// <summary>
/// Object that contains the method.
@@ -48,10 +49,10 @@ namespace Godot
public Delegate Delegate => _delegate;
/// <summary>
- /// Converts a <see cref="Delegate"/> to a <see cref="Callable"/>.
+ /// Trampoline function pointer for dynamically invoking <see cref="Callable.Delegate"/>.
/// </summary>
- /// <param name="delegate">The delegate to convert.</param>
- public static implicit operator Callable(Delegate @delegate) => new Callable(@delegate);
+ public unsafe delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> Trampoline
+ => _trampoline;
/// <summary>
/// Constructs a new <see cref="Callable"/> for the method called <paramref name="method"/>
@@ -59,22 +60,21 @@ namespace Godot
/// </summary>
/// <param name="target">Object that contains the method.</param>
/// <param name="method">Name of the method that will be called.</param>
- public Callable(Object target, StringName method)
+ public unsafe Callable(Object target, StringName method)
{
_target = target;
_method = method;
_delegate = null;
+ _trampoline = null;
}
- /// <summary>
- /// Constructs a new <see cref="Callable"/> for the given <paramref name="delegate"/>.
- /// </summary>
- /// <param name="delegate">Delegate method that will be called.</param>
- public Callable(Delegate @delegate)
+ private unsafe Callable(Delegate @delegate,
+ delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
{
_target = @delegate?.Target as Object;
_method = null;
_delegate = @delegate;
+ _trampoline = trampoline;
}
private const int VarArgsSpanThreshold = 5;
@@ -149,5 +149,59 @@ namespace Godot
NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
}
}
+
+ /// <summary>
+ /// <para>
+ /// Constructs a new <see cref="Callable"/> using the <paramref name="trampoline"/>
+ /// function pointer to dynamically invoke the given <paramref name="delegate"/>.
+ /// </para>
+ /// <para>
+ /// The parameters passed to the <paramref name="trampoline"/> function are:
+ /// </para>
+ /// <list type="number">
+ /// <item>
+ /// <term>delegateObj</term>
+ /// <description>The given <paramref name="delegate"/>, upcast to <see cref="object"/>.</description>
+ /// </item>
+ /// <item>
+ /// <term>args</term>
+ /// <description>Array of <see cref="godot_variant"/> arguments.</description>
+ /// </item>
+ /// <item>
+ /// <term>ret</term>
+ /// <description>Return value of type <see cref="godot_variant"/>.</description>
+ /// </item>
+ ///</list>
+ /// <para>
+ /// The delegate should be downcast to a more specific delegate type before invoking.
+ /// </para>
+ /// </summary>
+ /// <example>
+ /// Usage example:
+ ///
+ /// <code>
+ /// static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ /// {
+ /// if (args.Count != 1)
+ /// throw new ArgumentException($&quot;Callable expected {1} arguments but received {args.Count}.&quot;);
+ ///
+ /// TResult res = ((Func&lt;int, string&gt;)delegateObj)(
+ /// VariantConversionCallbacks.GetToManagedCallback&lt;int&gt;()(args[0])
+ /// );
+ ///
+ /// ret = VariantConversionCallbacks.GetToVariantCallback&lt;string&gt;()(res);
+ /// }
+ ///
+ /// var callable = Callable.CreateWithUnsafeTrampoline((int num) =&gt; &quot;foo&quot; + num.ToString(), &amp;Trampoline);
+ /// var res = (string)callable.Call(10);
+ /// Console.WriteLine(res);
+ /// </code>
+ /// </example>
+ /// <param name="delegate">Delegate method that will be called.</param>
+ /// <param name="trampoline">Trampoline function pointer for invoking the delegate.</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe Callable CreateWithUnsafeTrampoline(Delegate @delegate,
+ delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void> trampoline)
+ => new(@delegate, trampoline);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
new file mode 100644
index 0000000000..6c6a104019
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.generics.cs
@@ -0,0 +1,480 @@
+using System;
+using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
+
+namespace Godot;
+
+#nullable enable
+
+public readonly partial struct Callable
+{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ThrowIfArgCountMismatch(NativeVariantPtrArgs args, int countExpected,
+ [CallerArgumentExpression("args")] string? paramName = null)
+ {
+ if (countExpected != args.Count)
+ ThrowArgCountMismatch(countExpected, args.Count, paramName);
+
+ static void ThrowArgCountMismatch(int countExpected, int countReceived, string? paramName)
+ {
+ throw new ArgumentException(
+ "Invalid argument count for invoking callable." +
+ $" Expected {countExpected} arguments, received {countReceived}.",
+ paramName);
+ }
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Callable"/> for the given <paramref name="action"/>.
+ /// </summary>
+ /// <param name="action">Action method that will be called.</param>
+ public static unsafe Callable From(
+ Action action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 0);
+
+ ((Action)delegateObj)();
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0>(
+ Action<T0> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 1);
+
+ ((Action<T0>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1>(
+ Action<T0, T1> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 2);
+
+ ((Action<T0, T1>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2>(
+ Action<T0, T1, T2> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 3);
+
+ ((Action<T0, T1, T2>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3>(
+ Action<T0, T1, T2, T3> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 4);
+
+ ((Action<T0, T1, T2, T3>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4>(
+ Action<T0, T1, T2, T3, T4> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 5);
+
+ ((Action<T0, T1, T2, T3, T4>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5>(
+ Action<T0, T1, T2, T3, T4, T5> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 6);
+
+ ((Action<T0, T1, T2, T3, T4, T5>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6>(
+ Action<T0, T1, T2, T3, T4, T5, T6> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 7);
+
+ ((Action<T0, T1, T2, T3, T4, T5, T6>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7>(
+ Action<T0, T1, T2, T3, T4, T5, T6, T7> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 8);
+
+ ((Action<T0, T1, T2, T3, T4, T5, T6, T7>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
+ VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From(Action)"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8>(
+ Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> action
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 9);
+
+ ((Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
+ VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
+ VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
+ );
+
+ ret = default;
+ }
+
+ return CreateWithUnsafeTrampoline(action, &Trampoline);
+ }
+
+ /// <summary>
+ /// Constructs a new <see cref="Callable"/> for the given <paramref name="func"/>.
+ /// </summary>
+ /// <param name="func">Action method that will be called.</param>
+ public static unsafe Callable From<TResult>(
+ Func<TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 0);
+
+ TResult res = ((Func<TResult>)delegateObj)();
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, TResult>(
+ Func<T0, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 1);
+
+ TResult res = ((Func<T0, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, TResult>(
+ Func<T0, T1, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 2);
+
+ TResult res = ((Func<T0, T1, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, TResult>(
+ Func<T0, T1, T2, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 3);
+
+ TResult res = ((Func<T0, T1, T2, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, TResult>(
+ Func<T0, T1, T2, T3, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 4);
+
+ TResult res = ((Func<T0, T1, T2, T3, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, TResult>(
+ Func<T0, T1, T2, T3, T4, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 5);
+
+ TResult res = ((Func<T0, T1, T2, T3, T4, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 6);
+
+ TResult res = ((Func<T0, T1, T2, T3, T4, T5, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 7);
+
+ TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 8);
+
+ TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
+ VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+
+ /// <inheritdoc cref="From{TResult}(Func{TResult})"/>
+ public static unsafe Callable From<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>(
+ Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult> func
+ )
+ {
+ static void Trampoline(object delegateObj, NativeVariantPtrArgs args, out godot_variant ret)
+ {
+ ThrowIfArgCountMismatch(args, 9);
+
+ TResult res = ((Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TResult>)delegateObj)(
+ VariantConversionCallbacks.GetToManagedCallback<T0>()(args[0]),
+ VariantConversionCallbacks.GetToManagedCallback<T1>()(args[1]),
+ VariantConversionCallbacks.GetToManagedCallback<T2>()(args[2]),
+ VariantConversionCallbacks.GetToManagedCallback<T3>()(args[3]),
+ VariantConversionCallbacks.GetToManagedCallback<T4>()(args[4]),
+ VariantConversionCallbacks.GetToManagedCallback<T5>()(args[5]),
+ VariantConversionCallbacks.GetToManagedCallback<T6>()(args[6]),
+ VariantConversionCallbacks.GetToManagedCallback<T7>()(args[7]),
+ VariantConversionCallbacks.GetToManagedCallback<T8>()(args[8])
+ );
+
+ ret = VariantConversionCallbacks.GetToVariantCallback<TResult>()(res);
+ }
+
+ return CreateWithUnsafeTrampoline(func, &Trampoline);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 3c75d18943..d19e0c08f2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -30,33 +30,23 @@ namespace Godot
}
[UnmanagedCallersOnly]
- internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
- godot_variant* outRet)
+ internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, void* trampoline,
+ godot_variant** args, int argc, godot_variant* outRet)
{
try
{
- // TODO: Optimize
- var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
- var managedArgs = new object?[argc];
-
- var parameterInfos = @delegate.Method.GetParameters();
- var paramsLength = parameterInfos.Length;
-
- if (argc != paramsLength)
+ if (trampoline == null)
{
- throw new InvalidOperationException(
- $"The delegate expects {paramsLength} arguments, but received {argc}.");
+ throw new ArgumentNullException(nameof(trampoline),
+ "Cannot dynamically invoke delegate because the trampoline is null.");
}
- for (uint i = 0; i < argc; i++)
- {
- managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
- *args[i], parameterInfos[i].ParameterType);
- }
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
+ var trampolineFn = (delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline;
- object? invokeRet = @delegate.DynamicInvoke(managedArgs);
+ trampolineFn(@delegate, new NativeVariantPtrArgs(args, argc), out godot_variant ret);
- *outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet);
+ *outRet = ret;
}
catch (Exception e)
{
@@ -76,6 +66,11 @@ namespace Godot
internal static bool TrySerializeDelegate(Delegate @delegate, Collections.Array serializedData)
{
+ if (@delegate is null)
+ {
+ return false;
+ }
+
if (@delegate is MulticastDelegate multicastDelegate)
{
bool someDelegatesSerialized = false;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index 93103d0f6b..f8793332a0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -356,35 +356,47 @@ namespace Godot.Collections
IDictionary<TKey, TValue>,
IReadOnlyDictionary<TKey, TValue>
{
+ private static godot_variant ToVariantFunc(in Dictionary<TKey, TValue> godotDictionary) =>
+ VariantUtils.CreateFromDictionary(godotDictionary);
+
+ private static Dictionary<TKey, TValue> FromVariantFunc(in godot_variant variant) =>
+ VariantUtils.ConvertToDictionaryObject<TKey, TValue>(variant);
+
// ReSharper disable StaticMemberInGenericType
// Warning is about unique static fields being created for each generic type combination:
// https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
// In our case this is exactly what we want.
- private static unsafe delegate* managed<in TKey, godot_variant> _convertKeyToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, TKey> _convertKeyToManagedCallback;
- private static unsafe delegate* managed<in TValue, godot_variant> _convertValueToVariantCallback;
- private static unsafe delegate* managed<in godot_variant, TValue> _convertValueToManagedCallback;
+ private static readonly unsafe delegate* managed<in TKey, godot_variant> ConvertKeyToVariantCallback;
+ private static readonly unsafe delegate* managed<in godot_variant, TKey> ConvertKeyToManagedCallback;
+ private static readonly unsafe delegate* managed<in TValue, godot_variant> ConvertValueToVariantCallback;
+ private static readonly unsafe delegate* managed<in godot_variant, TValue> ConvertValueToManagedCallback;
// ReSharper restore StaticMemberInGenericType
static unsafe Dictionary()
{
- _convertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
- _convertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
- _convertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
- _convertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
+ VariantConversionCallbacks.GenericConversionCallbacks[typeof(Dictionary<TKey, TValue>)] =
+ (
+ (IntPtr)(delegate* managed<in Dictionary<TKey, TValue>, godot_variant>)&ToVariantFunc,
+ (IntPtr)(delegate* managed<in godot_variant, Dictionary<TKey, TValue>>)&FromVariantFunc
+ );
+
+ ConvertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
+ ConvertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
+ ConvertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
+ ConvertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
}
private static unsafe void ValidateVariantConversionCallbacks()
{
- if (_convertKeyToVariantCallback == null || _convertKeyToManagedCallback == null)
+ if (ConvertKeyToVariantCallback == null || ConvertKeyToManagedCallback == null)
{
throw new InvalidOperationException(
$"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'.");
}
- if (_convertValueToVariantCallback == null || _convertValueToManagedCallback == null)
+ if (ConvertValueToVariantCallback == null || ConvertValueToManagedCallback == null)
{
throw new InvalidOperationException(
$"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
@@ -473,14 +485,14 @@ namespace Godot.Collections
{
get
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant value).ToBool())
{
using (value)
- return _convertValueToManagedCallback(value);
+ return ConvertValueToManagedCallback(value);
}
else
{
@@ -489,8 +501,8 @@ namespace Godot.Collections
}
set
{
- using var variantKey = _convertKeyToVariantCallback(key);
- using var variantValue = _convertValueToVariantCallback(value);
+ using var variantKey = ConvertKeyToVariantCallback(key);
+ using var variantValue = ConvertValueToVariantCallback(value);
var self = (godot_dictionary)_underlyingDict.NativeValue;
NativeFuncs.godotsharp_dictionary_set_value(ref self,
variantKey, variantValue);
@@ -539,8 +551,8 @@ namespace Godot.Collections
using (value)
{
return new KeyValuePair<TKey, TValue>(
- _convertKeyToManagedCallback(key),
- _convertValueToManagedCallback(value));
+ ConvertKeyToManagedCallback(key),
+ ConvertValueToManagedCallback(value));
}
}
@@ -552,13 +564,13 @@ namespace Godot.Collections
/// <param name="value">The object to add.</param>
public unsafe void Add(TKey key, TValue value)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
throw new ArgumentException("An element with the same key already exists.", nameof(key));
- using var variantValue = _convertValueToVariantCallback(value);
+ using var variantValue = ConvertValueToVariantCallback(value);
NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
}
@@ -569,7 +581,7 @@ namespace Godot.Collections
/// <returns>Whether or not this dictionary contains the given key.</returns>
public unsafe bool ContainsKey(TKey key)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
}
@@ -580,7 +592,7 @@ namespace Godot.Collections
/// <param name="key">The key of the element to remove.</param>
public unsafe bool Remove(TKey key)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
}
@@ -593,13 +605,13 @@ namespace Godot.Collections
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantKey = ConvertKeyToVariantCallback(key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
using (retValue)
- value = found ? _convertValueToManagedCallback(retValue) : default;
+ value = found ? ConvertValueToManagedCallback(retValue) : default;
return found;
}
@@ -625,7 +637,7 @@ namespace Godot.Collections
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = _convertKeyToVariantCallback(item.Key);
+ using var variantKey = ConvertKeyToVariantCallback(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -635,7 +647,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = _convertValueToVariantCallback(item.Value);
+ using var variantValue = ConvertValueToVariantCallback(item.Value);
return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
}
}
@@ -670,7 +682,7 @@ namespace Godot.Collections
unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
- using var variantKey = _convertKeyToVariantCallback(item.Key);
+ using var variantKey = ConvertKeyToVariantCallback(item.Key);
var self = (godot_dictionary)_underlyingDict.NativeValue;
bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
variantKey, out godot_variant retValue).ToBool();
@@ -680,7 +692,7 @@ namespace Godot.Collections
if (!found)
return false;
- using var variantValue = _convertValueToVariantCallback(item.Value);
+ using var variantValue = ConvertValueToVariantCallback(item.Value);
if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
{
return NativeFuncs.godotsharp_dictionary_remove_key(
@@ -717,6 +729,7 @@ namespace Godot.Collections
public static implicit operator Variant(Dictionary<TKey, TValue> from) => Variant.CreateFrom(from);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static explicit operator Dictionary<TKey, TValue>(Variant from) => from.AsGodotDictionary<TKey, TValue>();
+ public static explicit operator Dictionary<TKey, TValue>(Variant from) =>
+ from.AsGodotDictionary<TKey, TValue>();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
index 76b186cd15..649661ee06 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -721,10 +721,19 @@ namespace Godot.NativeInterop
if (p_managed_callable.Delegate != null)
{
var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
- IntPtr objectPtr = p_managed_callable.Target != null ? Object.GetPtr(p_managed_callable.Target) : IntPtr.Zero;
- NativeFuncs.godotsharp_callable_new_with_delegate(
- GCHandle.ToIntPtr(gcHandle), objectPtr, out godot_callable callable);
- return callable;
+
+ IntPtr objectPtr = p_managed_callable.Target != null ?
+ Object.GetPtr(p_managed_callable.Target) :
+ IntPtr.Zero;
+
+ unsafe
+ {
+ NativeFuncs.godotsharp_callable_new_with_delegate(
+ GCHandle.ToIntPtr(gcHandle), (IntPtr)p_managed_callable.Trampoline,
+ objectPtr, out godot_callable callable);
+
+ return callable;
+ }
}
else
{
@@ -748,19 +757,22 @@ namespace Godot.NativeInterop
public static Callable ConvertCallableToManaged(in godot_callable p_callable)
{
if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable,
- out IntPtr delegateGCHandle, out IntPtr godotObject,
- out godot_string_name name).ToBool())
+ out IntPtr delegateGCHandle, out IntPtr trampoline,
+ out IntPtr godotObject, out godot_string_name name).ToBool())
{
if (delegateGCHandle != IntPtr.Zero)
{
- return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target);
- }
- else
- {
- return new Callable(
- InteropUtils.UnmanagedGetManaged(godotObject),
- StringName.CreateTakingOwnershipOfDisposableValue(name));
+ unsafe
+ {
+ return Callable.CreateWithUnsafeTrampoline(
+ (Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target,
+ (delegate* managed<object, NativeVariantPtrArgs, out godot_variant, void>)trampoline);
+ }
}
+
+ return new Callable(
+ InteropUtils.UnmanagedGetManaged(godotObject),
+ StringName.CreateTakingOwnershipOfDisposableValue(name));
}
// Some other unsupported callable
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
index 20ede9f0dd..088f4e7ecf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -141,11 +141,11 @@ namespace Godot.NativeInterop
public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
in godot_string p_element);
- public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_object,
- out godot_callable r_callable);
+ public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle, IntPtr p_trampoline,
+ IntPtr p_object, out godot_callable r_callable);
internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,
- out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name);
+ out IntPtr r_delegate_handle, out IntPtr r_trampoline, out IntPtr r_object, out godot_string_name r_name);
internal static partial godot_variant godotsharp_callable_call(in godot_callable p_callable,
godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
index 422df74c23..d8c5d99cb8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
@@ -8,8 +8,22 @@ namespace Godot.NativeInterop
public unsafe ref struct NativeVariantPtrArgs
{
private godot_variant** _args;
+ private int _argc;
- internal NativeVariantPtrArgs(godot_variant** args) => _args = args;
+ internal NativeVariantPtrArgs(godot_variant** args, int argc)
+ {
+ _args = args;
+ _argc = argc;
+ }
+
+ /// <summary>
+ /// Returns the number of arguments.
+ /// </summary>
+ public int Count
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _argc;
+ }
public ref godot_variant this[int index]
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
index 9cde62c7c5..4b3db0c01a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
@@ -1,10 +1,15 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
namespace Godot.NativeInterop;
+// TODO: Change VariantConversionCallbacks<T>. Store the callback in a static field for quick repeated access, instead of checking every time.
internal static unsafe class VariantConversionCallbacks
{
+ internal static System.Collections.Generic.Dictionary<Type, (IntPtr ToVariant, IntPtr FromVariant)>
+ GenericConversionCallbacks = new();
+
[SuppressMessage("ReSharper", "RedundantNameQualifier")]
internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
{
@@ -502,6 +507,26 @@ internal static unsafe class VariantConversionCallbacks
&FromVariant;
}
+ // TODO:
+ // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
+ // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
+ // Or we could just skip the check and always look for a conversion callback for the type.
+ if (typeOfT.IsGenericType)
+ {
+ var genericTypeDef = typeOfT.GetGenericTypeDefinition();
+
+ if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
+ genericTypeDef == typeof(Godot.Collections.Array<>))
+ {
+ RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
+
+ if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
+ {
+ return (delegate*<in T, godot_variant>)genericConversion.ToVariant;
+ }
+ }
+ }
+
return null;
}
@@ -1005,6 +1030,26 @@ internal static unsafe class VariantConversionCallbacks
&ToVariant;
}
+ // TODO:
+ // IsGenericType and GetGenericTypeDefinition don't work in NativeAOT's reflection-free mode.
+ // We could make the Godot collections implement an interface and use IsAssignableFrom instead.
+ // Or we could just skip the check and always look for a conversion callback for the type.
+ if (typeOfT.IsGenericType)
+ {
+ var genericTypeDef = typeOfT.GetGenericTypeDefinition();
+
+ if (genericTypeDef == typeof(Godot.Collections.Dictionary<,>) ||
+ genericTypeDef == typeof(Godot.Collections.Array<>))
+ {
+ RuntimeHelpers.RunClassConstructor(typeOfT.TypeHandle);
+
+ if (GenericConversionCallbacks.TryGetValue(typeOfT, out var genericConversion))
+ {
+ return (delegate*<in godot_variant, T>)genericConversion.FromVariant;
+ }
+ }
+ }
+
// ReSharper restore RedundantCast
return null;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 5cb678c280..60ee6eb6f4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -202,7 +202,7 @@ namespace Godot
// ReSharper disable once VirtualMemberNeverOverridden.Global
protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
- NativeVariantPtrArgs args, int argCount)
+ NativeVariantPtrArgs args)
{
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 13070c8033..664b2e0f34 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -292,6 +292,18 @@ namespace Godot
}
/// <summary>
+ /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
+ /// a <paramref name="point"/> on the plane.
+ /// </summary>
+ /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="point">The point on the plane.</param>
+ public Plane(Vector3 normal, Vector3 point)
+ {
+ _normal = normal;
+ D = _normal.Dot(point);
+ }
+
+ /// <summary>
/// Constructs a <see cref="Plane"/> from the three points, given in clockwise order.
/// </summary>
/// <param name="v1">The first point.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index d459fe8c96..5dd629aeb0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -507,35 +507,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a <see cref="Quaternion"/> that will perform a rotation specified by
- /// Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last),
- /// given in the vector format as (X angle, Y angle, Z angle).
- /// </summary>
- /// <param name="eulerYXZ">Euler angles that the quaternion will be rotated by.</param>
- public Quaternion(Vector3 eulerYXZ)
- {
- real_t halfA1 = eulerYXZ.y * 0.5f;
- real_t halfA2 = eulerYXZ.x * 0.5f;
- real_t halfA3 = eulerYXZ.z * 0.5f;
-
- // R = Y(a1).X(a2).Z(a3) convention for Euler angles.
- // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
- // a3 is the angle of the first rotation, following the notation in this reference.
-
- real_t cosA1 = Mathf.Cos(halfA1);
- real_t sinA1 = Mathf.Sin(halfA1);
- real_t cosA2 = Mathf.Cos(halfA2);
- real_t sinA2 = Mathf.Sin(halfA2);
- real_t cosA3 = Mathf.Cos(halfA3);
- real_t sinA3 = Mathf.Sin(halfA3);
-
- x = (sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3);
- y = (sinA1 * cosA2 * cosA3) - (cosA1 * sinA2 * sinA3);
- z = (cosA1 * cosA2 * sinA3) - (sinA1 * sinA2 * cosA3);
- w = (sinA1 * sinA2 * sinA3) + (cosA1 * cosA2 * cosA3);
- }
-
- /// <summary>
/// Constructs a <see cref="Quaternion"/> that will rotate around the given axis
/// by the specified angle. The axis must be a normalized vector.
/// </summary>
@@ -572,6 +543,61 @@ namespace Godot
}
}
+ public Quaternion(Vector3 arcFrom, Vector3 arcTo)
+ {
+ Vector3 c = arcFrom.Cross(arcTo);
+ real_t d = arcFrom.Dot(arcTo);
+
+ if (d < -1.0f + Mathf.Epsilon)
+ {
+ x = 0f;
+ y = 1f;
+ z = 0f;
+ w = 0f;
+ }
+ else
+ {
+ real_t s = Mathf.Sqrt((1.0f + d) * 2.0f);
+ real_t rs = 1.0f / s;
+
+ x = c.x * rs;
+ y = c.y * rs;
+ z = c.z * rs;
+ w = s * 0.5f;
+ }
+ }
+
+ /// <summary>
+ /// Constructs a <see cref="Quaternion"/> that will perform a rotation specified by
+ /// Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last),
+ /// given in the vector format as (X angle, Y angle, Z angle).
+ /// </summary>
+ /// <param name="eulerYXZ">Euler angles that the quaternion will be rotated by.</param>
+ public static Quaternion FromEuler(Vector3 eulerYXZ)
+ {
+ real_t halfA1 = eulerYXZ.y * 0.5f;
+ real_t halfA2 = eulerYXZ.x * 0.5f;
+ real_t halfA3 = eulerYXZ.z * 0.5f;
+
+ // R = Y(a1).X(a2).Z(a3) convention for Euler angles.
+ // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
+ // a3 is the angle of the first rotation, following the notation in this reference.
+
+ real_t cosA1 = Mathf.Cos(halfA1);
+ real_t sinA1 = Mathf.Sin(halfA1);
+ real_t cosA2 = Mathf.Cos(halfA2);
+ real_t sinA2 = Mathf.Sin(halfA2);
+ real_t cosA3 = Mathf.Cos(halfA3);
+ real_t sinA3 = Mathf.Sin(halfA3);
+
+ return new Quaternion(
+ (sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3),
+ (sinA1 * cosA2 * cosA3) - (cosA1 * sinA2 * sinA3),
+ (cosA1 * cosA2 * sinA3) - (sinA1 * sinA2 * cosA3),
+ (sinA1 * sinA2 * sinA3) + (cosA1 * cosA2 * cosA3)
+ );
+ }
+
/// <summary>
/// Composes these two quaternions by multiplying them together.
/// This has the effect of rotating the second quaternion
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 5827d3e591..e3fb254f49 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -27,6 +27,8 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+ <IncludeSymbols>true</IncludeSymbols>
+ <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<ItemGroup>
<!-- SdkPackageVersions.props for easy access -->
@@ -50,6 +52,7 @@
<Compile Include="Core\AABB.cs" />
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
<Compile Include="Core\Bridge\MethodInfo.cs" />
+ <Compile Include="Core\Callable.generics.cs" />
<Compile Include="Core\CustomGCHandle.cs" />
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index 5d69ad8ec6..8f623625fc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -22,6 +22,8 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+ <IncludeSymbols>true</IncludeSymbols>
+ <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
index 2717b945f6..e20a88076a 100644
--- a/modules/mono/glue/runtime_interop.cpp
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -447,15 +447,16 @@ void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String
r_dest->append(*p_element);
}
-void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, const Object *p_object, Callable *r_callable) {
+void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, void *p_trampoline,
+ const Object *p_object, Callable *r_callable) {
// TODO: Use pooling for ManagedCallable instances.
ObjectID objid = p_object ? p_object->get_instance_id() : ObjectID();
- CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, objid));
+ CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle, p_trampoline, objid));
memnew_placement(r_callable, Callable(managed_callable));
}
bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
- GCHandleIntPtr *r_delegate_handle, Object **r_object, StringName *r_name) {
+ GCHandleIntPtr *r_delegate_handle, void **r_trampoline, Object **r_object, StringName *r_name) {
if (p_callable->is_custom()) {
CallableCustom *custom = p_callable->get_custom();
CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
@@ -463,18 +464,21 @@ bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
*r_delegate_handle = managed_callable->get_delegate();
+ *r_trampoline = managed_callable->get_trampoline();
*r_object = nullptr;
memnew_placement(r_name, StringName());
return true;
} else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
*r_delegate_handle = { nullptr };
+ *r_trampoline = nullptr;
*r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
memnew_placement(r_name, StringName(signal_awaiter_callable->get_signal()));
return true;
} else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
*r_delegate_handle = { nullptr };
+ *r_trampoline = nullptr;
*r_object = ObjectDB::get_instance(event_signal_callable->get_object());
memnew_placement(r_name, StringName(event_signal_callable->get_signal()));
return true;
@@ -482,11 +486,13 @@ bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
// Some other CallableCustom. We only support ManagedCallable.
*r_delegate_handle = { nullptr };
+ *r_trampoline = nullptr;
*r_object = nullptr;
memnew_placement(r_name, StringName());
return false;
} else {
*r_delegate_handle = { nullptr };
+ *r_trampoline = nullptr;
*r_object = ObjectDB::get_instance(p_callable->get_object_id());
memnew_placement(r_name, StringName(p_callable->get_method()));
return true;
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index c7e47d2718..d45bf4025f 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -94,138 +94,63 @@ String _get_mono_user_dir() {
class _GodotSharpDirs {
public:
- String res_data_dir;
String res_metadata_dir;
- String res_config_dir;
- String res_temp_dir;
- String res_temp_assemblies_base_dir;
String res_temp_assemblies_dir;
String mono_user_dir;
- String mono_logs_dir;
-
- String api_assemblies_base_dir;
String api_assemblies_dir;
#ifdef TOOLS_ENABLED
- String mono_solutions_dir;
String build_logs_dir;
-
String data_editor_tools_dir;
-#else
- // Equivalent of res_assemblies_dir, but in the data directory rather than in 'res://'.
- // Only defined on export templates. Used when exporting assemblies outside of PCKs.
- String data_game_assemblies_dir;
-#endif
-
- String data_mono_etc_dir;
- String data_mono_lib_dir;
-
-#ifdef WINDOWS_ENABLED
- String data_mono_bin_dir;
#endif
private:
_GodotSharpDirs() {
- res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
+ String res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
res_metadata_dir = res_data_dir.path_join("metadata");
- res_config_dir = res_data_dir.path_join("etc").path_join("mono");
// TODO use paths from csproj
- res_temp_dir = res_data_dir.path_join("temp");
- res_temp_assemblies_base_dir = res_temp_dir.path_join("bin");
- res_temp_assemblies_dir = res_temp_assemblies_base_dir.path_join(_get_expected_build_config());
-
- api_assemblies_base_dir = res_data_dir.path_join("assemblies");
+ res_temp_assemblies_dir = res_data_dir.path_join("temp").path_join("bin").path_join(_get_expected_build_config());
#ifdef WEB_ENABLED
mono_user_dir = "user://";
#else
mono_user_dir = _get_mono_user_dir();
#endif
- mono_logs_dir = mono_user_dir.path_join("mono_logs");
-
-#ifdef TOOLS_ENABLED
- mono_solutions_dir = mono_user_dir.path_join("solutions");
- build_logs_dir = mono_user_dir.path_join("build_logs");
-
- String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
-#endif
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
+ String res_dir = OS::get_singleton()->get_bundle_resource_dir();
#ifdef TOOLS_ENABLED
-
String data_dir_root = exe_dir.path_join("GodotSharp");
data_editor_tools_dir = data_dir_root.path_join("Tools");
- api_assemblies_base_dir = data_dir_root.path_join("Api");
-
- String data_mono_root_dir = data_dir_root.path_join("Mono");
- data_mono_etc_dir = data_mono_root_dir.path_join("etc");
-
-#ifdef ANDROID_ENABLED
- data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
-#else
- data_mono_lib_dir = data_mono_root_dir.path_join("lib");
-#endif
-
-#ifdef WINDOWS_ENABLED
- data_mono_bin_dir = data_mono_root_dir.path_join("bin");
-#endif
-
+ String api_assemblies_base_dir = data_dir_root.path_join("Api");
+ build_logs_dir = mono_user_dir.path_join("build_logs");
#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
- data_editor_tools_dir = exe_dir.path_join("../Resources/GodotSharp/Tools");
+ data_editor_tools_dir = res_dir.path_join("GodotSharp").path_join("Tools");
}
-
if (!DirAccess::exists(api_assemblies_base_dir)) {
- api_assemblies_base_dir = exe_dir.path_join("../Resources/GodotSharp/Api");
- }
-
- if (!DirAccess::exists(data_mono_root_dir)) {
- data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
+ api_assemblies_base_dir = res_dir.path_join("GodotSharp").path_join("Api");
}
#endif
-
-#else
-
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
+#else // TOOLS_ENABLED
+ String arch = Engine::get_singleton()->get_architecture_name();
+ String appname = GLOBAL_GET("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- String data_dir_root = exe_dir.path_join("data_" + appname_safe);
+ String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
if (!DirAccess::exists(data_dir_root)) {
- data_dir_root = exe_dir.path_join("data_Godot");
+ data_dir_root = exe_dir.path_join("data_Godot_" + arch);
}
-
- String data_mono_root_dir = data_dir_root.path_join("Mono");
- data_mono_etc_dir = data_mono_root_dir.path_join("etc");
-
-#ifdef ANDROID_ENABLED
- data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
-#else
- data_mono_lib_dir = data_mono_root_dir.path_join("lib");
- data_game_assemblies_dir = data_dir_root.path_join("Assemblies");
-#endif
-
-#ifdef WINDOWS_ENABLED
- data_mono_bin_dir = data_mono_root_dir.path_join("bin");
-#endif
-
#ifdef MACOS_ENABLED
- if (!DirAccess::exists(data_mono_root_dir)) {
- data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
+ if (!DirAccess::exists(data_dir_root)) {
+ data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
}
-
- if (!DirAccess::exists(data_game_assemblies_dir)) {
- data_game_assemblies_dir = exe_dir.path_join("../Resources/GodotSharp/Assemblies");
+ if (!DirAccess::exists(data_dir_root)) {
+ data_dir_root = res_dir.path_join("data_Godot_" + arch);
}
#endif
-
-#endif
-
-#ifdef TOOLS_ENABLED
- api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
-#else
api_assemblies_dir = data_dir_root;
#endif
}
@@ -237,26 +162,10 @@ public:
}
};
-String get_res_data_dir() {
- return _GodotSharpDirs::get_singleton().res_data_dir;
-}
-
String get_res_metadata_dir() {
return _GodotSharpDirs::get_singleton().res_metadata_dir;
}
-String get_res_config_dir() {
- return _GodotSharpDirs::get_singleton().res_config_dir;
-}
-
-String get_res_temp_dir() {
- return _GodotSharpDirs::get_singleton().res_temp_dir;
-}
-
-String get_res_temp_assemblies_base_dir() {
- return _GodotSharpDirs::get_singleton().res_temp_assemblies_base_dir;
-}
-
String get_res_temp_assemblies_dir() {
return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
}
@@ -265,23 +174,11 @@ String get_api_assemblies_dir() {
return _GodotSharpDirs::get_singleton().api_assemblies_dir;
}
-String get_api_assemblies_base_dir() {
- return _GodotSharpDirs::get_singleton().api_assemblies_base_dir;
-}
-
String get_mono_user_dir() {
return _GodotSharpDirs::get_singleton().mono_user_dir;
}
-String get_mono_logs_dir() {
- return _GodotSharpDirs::get_singleton().mono_logs_dir;
-}
-
#ifdef TOOLS_ENABLED
-String get_mono_solutions_dir() {
- return _GodotSharpDirs::get_singleton().mono_solutions_dir;
-}
-
String get_build_logs_dir() {
return _GodotSharpDirs::get_singleton().build_logs_dir;
}
@@ -289,23 +186,6 @@ String get_build_logs_dir() {
String get_data_editor_tools_dir() {
return _GodotSharpDirs::get_singleton().data_editor_tools_dir;
}
-#else
-String get_data_game_assemblies_dir() {
- return _GodotSharpDirs::get_singleton().data_game_assemblies_dir;
-}
#endif
-String get_data_mono_etc_dir() {
- return _GodotSharpDirs::get_singleton().data_mono_etc_dir;
-}
-
-String get_data_mono_lib_dir() {
- return _GodotSharpDirs::get_singleton().data_mono_lib_dir;
-}
-
-#ifdef WINDOWS_ENABLED
-String get_data_mono_bin_dir() {
- return _GodotSharpDirs::get_singleton().data_mono_bin_dir;
-}
-#endif
} // namespace GodotSharpDirs
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
index 03e62ffd82..cdfb8e4787 100644
--- a/modules/mono/godotsharp_dirs.h
+++ b/modules/mono/godotsharp_dirs.h
@@ -35,34 +35,18 @@
namespace GodotSharpDirs {
-String get_res_data_dir();
String get_res_metadata_dir();
-String get_res_config_dir();
-String get_res_temp_dir();
-String get_res_temp_assemblies_base_dir();
String get_res_temp_assemblies_dir();
String get_api_assemblies_dir();
-String get_api_assemblies_base_dir();
String get_mono_user_dir();
-String get_mono_logs_dir();
#ifdef TOOLS_ENABLED
-String get_mono_solutions_dir();
String get_build_logs_dir();
-
String get_data_editor_tools_dir();
-#else
-String get_data_game_assemblies_dir();
#endif
-String get_data_mono_etc_dir();
-String get_data_mono_lib_dir();
-
-#ifdef WINDOWS_ENABLED
-String get_data_mono_bin_dir();
-#endif
} // namespace GodotSharpDirs
#endif // GODOTSHARP_DIRS_H
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index 0c2c533090..28edc41d98 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -92,7 +92,7 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
ERR_FAIL_COND(delegate_handle.value == nullptr);
GDMonoCache::managed_callbacks.DelegateUtils_InvokeWithVariantArgs(
- delegate_handle, p_arguments, p_argcount, &r_return_value);
+ delegate_handle, trampoline, p_arguments, p_argcount, &r_return_value);
r_call_error.error = Callable::CallError::CALL_OK;
}
@@ -106,7 +106,8 @@ void ManagedCallable::release_delegate_handle() {
// Why you do this clang-format...
/* clang-format off */
-ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id) : delegate_handle(p_delegate_handle), object_id(p_object_id) {
+ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle, void *p_trampoline, ObjectID p_object_id) :
+ delegate_handle(p_delegate_handle), trampoline(p_trampoline), object_id(p_object_id) {
#ifdef GD_MONO_HOT_RELOAD
{
MutexLock lock(instances_mutex);
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 26cd164fb6..b3a137dedf 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -40,6 +40,7 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
GCHandleIntPtr delegate_handle;
+ void *trampoline = nullptr;
ObjectID object_id;
#ifdef GD_MONO_HOT_RELOAD
@@ -58,6 +59,7 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
_FORCE_INLINE_ GCHandleIntPtr get_delegate() const { return delegate_handle; }
+ _FORCE_INLINE_ void *get_trampoline() const { return trampoline; }
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -67,7 +69,7 @@ public:
void release_delegate_handle();
- ManagedCallable(GCHandleIntPtr p_delegate_handle, ObjectID p_object_id);
+ ManagedCallable(GCHandleIntPtr p_delegate_handle, void *p_trampoline, ObjectID p_object_id);
~ManagedCallable();
};
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 13b599fe55..9c26fa2b0a 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -74,7 +74,7 @@ struct ManagedCallbacks {
using Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, void *p_def_vals, int32_t p_count);
using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *);
- using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, uint32_t, const Variant *);
+ using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, void *, const Variant **, int32_t, const Variant *);
using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr);
using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *);
using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *);
diff --git a/modules/multiplayer/doc_classes/SceneMultiplayer.xml b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
index 62bb396d15..a7b89f58ac 100644
--- a/modules/multiplayer/doc_classes/SceneMultiplayer.xml
+++ b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
@@ -42,6 +42,10 @@
The root path to use for RPCs and replication. Instead of an absolute path, a relative path will be used to find the node upon which the RPC should be executed.
This effectively allows to have different branches of the scene tree to be managed by different MultiplayerAPI, allowing for example to run both client and server in the same scene.
</member>
+ <member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true">
+ Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server.
+ [b]Note:[/b] Support for this feature may depend on the current [MultiplayerPeer] configuration. See [method MultiplayerPeer.is_server_relay_supported].
+ </member>
</members>
<signals>
<signal name="peer_packet">
diff --git a/modules/multiplayer/multiplayer_synchronizer.cpp b/modules/multiplayer/multiplayer_synchronizer.cpp
index 9755f426d5..95857392c7 100644
--- a/modules/multiplayer/multiplayer_synchronizer.cpp
+++ b/modules/multiplayer/multiplayer_synchronizer.cpp
@@ -118,6 +118,10 @@ void MultiplayerSynchronizer::set_net_id(uint32_t p_net_id) {
}
bool MultiplayerSynchronizer::update_outbound_sync_time(uint64_t p_msec) {
+ if (last_sync_msec == p_msec) {
+ // last_sync_msec has been updated on this frame.
+ return true;
+ }
if (p_msec >= last_sync_msec + interval_msec) {
last_sync_msec = p_msec;
return true;
diff --git a/modules/multiplayer/scene_cache_interface.cpp b/modules/multiplayer/scene_cache_interface.cpp
index b3b642f815..7df9b95b30 100644
--- a/modules/multiplayer/scene_cache_interface.cpp
+++ b/modules/multiplayer/scene_cache_interface.cpp
@@ -105,8 +105,7 @@ void SceneCacheInterface::process_simplify_path(int p_from, const uint8_t *p_pac
multiplayer_peer->set_transfer_channel(0);
multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
- multiplayer_peer->set_target_peer(p_from);
- multiplayer_peer->put_packet(packet.ptr(), packet.size());
+ multiplayer->send_command(p_from, packet.ptr(), packet.size());
}
void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) {
@@ -162,10 +161,9 @@ Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, Pat
Error err = OK;
for (int peer_id : p_peers) {
- multiplayer_peer->set_target_peer(peer_id);
multiplayer_peer->set_transfer_channel(0);
multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
- err = multiplayer_peer->put_packet(packet.ptr(), packet.size());
+ err = multiplayer->send_command(peer_id, packet.ptr(), packet.size());
ERR_FAIL_COND_V(err != OK, err);
// Insert into confirmed, but as false since it was not confirmed.
psc->confirmed_peers.insert(peer_id, false);
diff --git a/modules/multiplayer/scene_multiplayer.cpp b/modules/multiplayer/scene_multiplayer.cpp
index 3fc1eef366..f94f8ef658 100644
--- a/modules/multiplayer/scene_multiplayer.cpp
+++ b/modules/multiplayer/scene_multiplayer.cpp
@@ -67,12 +67,20 @@ Error SceneMultiplayer::poll() {
const uint8_t *packet;
int len;
+ int channel = multiplayer_peer->get_packet_channel();
+ MultiplayerPeer::TransferMode mode = multiplayer_peer->get_packet_mode();
+
Error err = multiplayer_peer->get_packet(&packet, len);
ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error getting packet! %d", err));
- remote_sender_id = sender;
- _process_packet(sender, packet, len);
- remote_sender_id = 0;
+ if (len && (packet[0] & CMD_MASK) == NETWORK_COMMAND_SYS) {
+ // Sys messages are processed separately since they might call _process_packet themselves.
+ _process_sys(sender, packet, len, mode, channel);
+ } else {
+ remote_sender_id = sender;
+ _process_packet(sender, packet, len);
+ remote_sender_id = 0;
+ }
if (!multiplayer_peer.is_valid()) {
return OK; // It's also possible that a packet or RPC caused a disconnection, so also check here.
@@ -86,6 +94,7 @@ void SceneMultiplayer::clear() {
connected_peers.clear();
packet_cache.clear();
cache->clear();
+ relay_buffer->clear();
}
void SceneMultiplayer::set_root_path(const NodePath &p_path) {
@@ -166,10 +175,123 @@ void SceneMultiplayer::_process_packet(int p_from, const uint8_t *p_packet, int
case NETWORK_COMMAND_SYNC: {
replicator->on_sync_receive(p_from, p_packet, p_packet_len);
} break;
+ default: {
+ ERR_FAIL_MSG("Invalid network command from " + itos(p_from));
+ } break;
+ }
+}
+
+Error SceneMultiplayer::send_command(int p_to, const uint8_t *p_packet, int p_packet_len) {
+ if (server_relay && get_unique_id() != 1 && p_to != 1 && multiplayer_peer->is_server_relay_supported()) {
+ // Send relay packet.
+ relay_buffer->seek(0);
+ relay_buffer->put_u8(NETWORK_COMMAND_SYS);
+ relay_buffer->put_u8(SYS_COMMAND_RELAY);
+ relay_buffer->put_32(p_to); // Set the destination.
+ relay_buffer->put_data(p_packet, p_packet_len);
+ multiplayer_peer->set_target_peer(1);
+ const Vector<uint8_t> data = relay_buffer->get_data_array();
+ return multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
+ }
+ if (p_to < 0) {
+ for (const int &pid : connected_peers) {
+ if (pid == -p_to) {
+ continue;
+ }
+ multiplayer_peer->set_target_peer(pid);
+ multiplayer_peer->put_packet(p_packet, p_packet_len);
+ }
+ return OK;
+ } else {
+ multiplayer_peer->set_target_peer(p_to);
+ return multiplayer_peer->put_packet(p_packet, p_packet_len);
+ }
+}
+
+void SceneMultiplayer::_process_sys(int p_from, const uint8_t *p_packet, int p_packet_len, MultiplayerPeer::TransferMode p_mode, int p_channel) {
+ ERR_FAIL_COND_MSG(p_packet_len < SYS_CMD_SIZE, "Invalid packet received. Size too small.");
+ uint8_t sys_cmd_type = p_packet[1];
+ int32_t peer = int32_t(decode_uint32(&p_packet[2]));
+ switch (sys_cmd_type) {
+ case SYS_COMMAND_ADD_PEER: {
+ ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported() || get_unique_id() == 1 || p_from != 1);
+ _add_peer(peer);
+ } break;
+ case SYS_COMMAND_DEL_PEER: {
+ ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported() || get_unique_id() == 1 || p_from != 1);
+ _del_peer(peer);
+ } break;
+ case SYS_COMMAND_RELAY: {
+ ERR_FAIL_COND(!server_relay || !multiplayer_peer->is_server_relay_supported());
+ ERR_FAIL_COND(p_packet_len < SYS_CMD_SIZE + 1);
+ const uint8_t *packet = p_packet + SYS_CMD_SIZE;
+ int len = p_packet_len - SYS_CMD_SIZE;
+ bool should_process = false;
+ if (get_unique_id() == 1) { // I am the server.
+ // Direct messages to server should not go through relay.
+ ERR_FAIL_COND(peer > 0 && !connected_peers.has(peer));
+ // Send relay packet.
+ relay_buffer->seek(0);
+ relay_buffer->put_u8(NETWORK_COMMAND_SYS);
+ relay_buffer->put_u8(SYS_COMMAND_RELAY);
+ relay_buffer->put_32(p_from); // Set the source.
+ relay_buffer->put_data(packet, len);
+ const Vector<uint8_t> data = relay_buffer->get_data_array();
+ multiplayer_peer->set_transfer_mode(p_mode);
+ multiplayer_peer->set_transfer_channel(p_channel);
+ if (peer > 0) {
+ multiplayer_peer->set_target_peer(peer);
+ multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
+ } else {
+ for (const int &P : connected_peers) {
+ // Not to sender, nor excluded.
+ if (P == p_from || (peer < 0 && P != -peer)) {
+ continue;
+ }
+ multiplayer_peer->set_target_peer(P);
+ multiplayer_peer->put_packet(data.ptr(), relay_buffer->get_position());
+ }
+ }
+ if (peer == 0 || peer == -1) {
+ should_process = true;
+ peer = p_from; // Process as the source.
+ }
+ } else {
+ ERR_FAIL_COND(p_from != 1); // Bug.
+ should_process = true;
+ }
+ if (should_process) {
+ remote_sender_id = peer;
+ _process_packet(peer, packet, len);
+ remote_sender_id = 0;
+ }
+ } break;
+ default: {
+ ERR_FAIL();
+ }
}
}
void SceneMultiplayer::_add_peer(int p_id) {
+ if (server_relay && get_unique_id() == 1 && multiplayer_peer->is_server_relay_supported()) {
+ // Notify others of connection, and send connected peers to newly connected one.
+ uint8_t buf[SYS_CMD_SIZE];
+ buf[0] = NETWORK_COMMAND_SYS;
+ buf[1] = SYS_COMMAND_ADD_PEER;
+ multiplayer_peer->set_transfer_channel(0);
+ multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ for (const int &P : connected_peers) {
+ // Send new peer to already connected.
+ encode_uint32(p_id, &buf[2]);
+ multiplayer_peer->set_target_peer(P);
+ multiplayer_peer->put_packet(buf, sizeof(buf));
+ // Send already connected to new peer.
+ encode_uint32(P, &buf[2]);
+ multiplayer_peer->set_target_peer(p_id);
+ multiplayer_peer->put_packet(buf, sizeof(buf));
+ }
+ }
+
connected_peers.insert(p_id);
cache->on_peer_change(p_id, true);
replicator->on_peer_change(p_id, true);
@@ -177,6 +299,23 @@ void SceneMultiplayer::_add_peer(int p_id) {
}
void SceneMultiplayer::_del_peer(int p_id) {
+ if (server_relay && get_unique_id() == 1 && multiplayer_peer->is_server_relay_supported()) {
+ // Notify others of disconnection.
+ uint8_t buf[SYS_CMD_SIZE];
+ buf[0] = NETWORK_COMMAND_SYS;
+ buf[1] = SYS_COMMAND_DEL_PEER;
+ multiplayer_peer->set_transfer_channel(0);
+ multiplayer_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE);
+ encode_uint32(p_id, &buf[2]);
+ for (const int &P : connected_peers) {
+ if (P == p_id) {
+ continue;
+ }
+ multiplayer_peer->set_target_peer(P);
+ multiplayer_peer->put_packet(buf, sizeof(buf));
+ }
+ }
+
replicator->on_peer_change(p_id, false);
cache->on_peer_change(p_id, false);
connected_peers.erase(p_id);
@@ -209,11 +348,9 @@ Error SceneMultiplayer::send_bytes(Vector<uint8_t> p_data, int p_to, Multiplayer
packet_cache.write[0] = NETWORK_COMMAND_RAW;
memcpy(&packet_cache.write[1], &r[0], p_data.size());
- multiplayer_peer->set_target_peer(p_to);
multiplayer_peer->set_transfer_channel(p_channel);
multiplayer_peer->set_transfer_mode(p_mode);
-
- return multiplayer_peer->put_packet(packet_cache.ptr(), p_data.size() + 1);
+ return send_command(p_to, packet_cache.ptr(), p_data.size() + 1);
}
void SceneMultiplayer::_process_raw(int p_from, const uint8_t *p_packet, int p_packet_len) {
@@ -303,6 +440,15 @@ Error SceneMultiplayer::object_configuration_remove(Object *p_obj, Variant p_con
return ERR_INVALID_PARAMETER;
}
+void SceneMultiplayer::set_server_relay_enabled(bool p_enabled) {
+ ERR_FAIL_COND_MSG(multiplayer_peer.is_valid() && multiplayer_peer->get_connection_status() != MultiplayerPeer::CONNECTION_DISCONNECTED, "Cannot change the server relay option while the multiplayer peer is active.");
+ server_relay = p_enabled;
+}
+
+bool SceneMultiplayer::is_server_relay_enabled() const {
+ return server_relay;
+}
+
void SceneMultiplayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_path", "path"), &SceneMultiplayer::set_root_path);
ClassDB::bind_method(D_METHOD("get_root_path"), &SceneMultiplayer::get_root_path);
@@ -311,17 +457,22 @@ void SceneMultiplayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &SceneMultiplayer::is_refusing_new_connections);
ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &SceneMultiplayer::set_allow_object_decoding);
ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &SceneMultiplayer::is_object_decoding_allowed);
+ ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &SceneMultiplayer::set_server_relay_enabled);
+ ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &SceneMultiplayer::is_server_relay_enabled);
ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode", "channel"), &SceneMultiplayer::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0));
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_path"), "set_root_path", "get_root_path");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled");
+
ADD_PROPERTY_DEFAULT("refuse_new_connections", false);
ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "packet")));
}
SceneMultiplayer::SceneMultiplayer() {
+ relay_buffer.instantiate();
replicator = Ref<SceneReplicationInterface>(memnew(SceneReplicationInterface(this)));
rpc = Ref<SceneRPCInterface>(memnew(SceneRPCInterface(this)));
cache = Ref<SceneCacheInterface>(memnew(SceneCacheInterface(this)));
diff --git a/modules/multiplayer/scene_multiplayer.h b/modules/multiplayer/scene_multiplayer.h
index a99cca7b21..06d7b2c7a7 100644
--- a/modules/multiplayer/scene_multiplayer.h
+++ b/modules/multiplayer/scene_multiplayer.h
@@ -49,6 +49,17 @@ public:
NETWORK_COMMAND_SPAWN,
NETWORK_COMMAND_DESPAWN,
NETWORK_COMMAND_SYNC,
+ NETWORK_COMMAND_SYS,
+ };
+
+ enum SysCommands {
+ SYS_COMMAND_ADD_PEER,
+ SYS_COMMAND_DEL_PEER,
+ SYS_COMMAND_RELAY,
+ };
+
+ enum {
+ SYS_CMD_SIZE = 6, // Command + sys command + peer_id (+ optional payload).
};
// For each command, the 4 MSB can contain custom flags, as defined by subsystems.
@@ -74,6 +85,8 @@ private:
NodePath root_path;
bool allow_object_decoding = false;
+ bool server_relay = true;
+ Ref<StreamPeerBuffer> relay_buffer;
Ref<SceneCacheInterface> cache;
Ref<SceneReplicationInterface> replicator;
@@ -84,6 +97,7 @@ protected:
void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len);
+ void _process_sys(int p_from, const uint8_t *p_packet, int p_packet_len, MultiplayerPeer::TransferMode p_mode, int p_channel);
void _add_peer(int p_id);
void _del_peer(int p_id);
@@ -111,6 +125,7 @@ public:
void set_root_path(const NodePath &p_path);
NodePath get_root_path() const;
+ Error send_command(int p_to, const uint8_t *p_packet, int p_packet_len); // Used internally to relay packets when needed.
Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE, int p_channel = 0);
String get_rpc_md5(const Object *p_obj);
@@ -123,6 +138,9 @@ public:
void set_allow_object_decoding(bool p_enable);
bool is_object_decoding_allowed() const;
+ void set_server_relay_enabled(bool p_enabled);
+ bool is_server_relay_enabled() const;
+
Ref<SceneCacheInterface> get_path_cache() { return cache; }
#ifdef DEBUG_ENABLED
diff --git a/modules/multiplayer/scene_replication_config.cpp b/modules/multiplayer/scene_replication_config.cpp
index ae06516b7b..61fe51b6c9 100644
--- a/modules/multiplayer/scene_replication_config.cpp
+++ b/modules/multiplayer/scene_replication_config.cpp
@@ -34,11 +34,11 @@
#include "scene/main/node.h"
bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
+ String prop_name = p_name;
- if (name.begins_with("properties/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ if (prop_name.begins_with("properties/")) {
+ int idx = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (properties.size() == idx && what == "path") {
ERR_FAIL_COND_V(p_value.get_type() != Variant::NODE_PATH, false);
@@ -72,11 +72,11 @@ bool SceneReplicationConfig::_set(const StringName &p_name, const Variant &p_val
}
bool SceneReplicationConfig::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
+ String prop_name = p_name;
- if (name.begins_with("properties/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ if (prop_name.begins_with("properties/")) {
+ int idx = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
ERR_FAIL_INDEX_V(idx, properties.size(), false);
const ReplicationProperty &prop = properties[idx];
if (what == "path") {
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index df9985916b..659ce7316a 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -72,7 +72,7 @@ void SceneReplicationInterface::_free_remotes(const PeerInfo &p_info) {
for (const KeyValue<uint32_t, ObjectID> &E : p_info.recv_nodes) {
Node *node = tracked_nodes.has(E.value) ? get_id_as<Node>(E.value) : nullptr;
ERR_CONTINUE(!node);
- node->queue_delete();
+ node->queue_free();
}
}
@@ -261,11 +261,11 @@ Error SceneReplicationInterface::_update_sync_visibility(int p_peer, Multiplayer
if (p_peer == 0) {
for (KeyValue<int, PeerInfo> &E : peers_info) {
// Might be visible to this specific peer.
- is_visible = is_visible || p_sync->is_visible_to(E.key);
- if (is_visible == E.value.sync_nodes.has(sid)) {
+ bool is_visible_to_peer = is_visible || p_sync->is_visible_to(E.key);
+ if (is_visible_to_peer == E.value.sync_nodes.has(sid)) {
continue;
}
- if (is_visible) {
+ if (is_visible_to_peer) {
E.value.sync_nodes.insert(sid);
} else {
E.value.sync_nodes.erase(sid);
@@ -370,10 +370,9 @@ Error SceneReplicationInterface::_send_raw(const uint8_t *p_buffer, int p_size,
#endif
Ref<MultiplayerPeer> peer = multiplayer->get_multiplayer_peer();
- peer->set_target_peer(p_peer);
peer->set_transfer_channel(0);
peer->set_transfer_mode(p_reliable ? MultiplayerPeer::TRANSFER_MODE_RELIABLE : MultiplayerPeer::TRANSFER_MODE_UNRELIABLE);
- return peer->put_packet(p_buffer, p_size);
+ return multiplayer->send_command(p_peer, p_buffer, p_size);
}
Error SceneReplicationInterface::_make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len) {
@@ -582,7 +581,7 @@ Error SceneReplicationInterface::on_despawn_receive(int p_from, const uint8_t *p
if (node->get_parent() != nullptr) {
node->get_parent()->remove_child(node);
}
- node->queue_delete();
+ node->queue_free();
spawner->emit_signal(SNAME("despawned"), node);
return OK;
diff --git a/modules/multiplayer/scene_rpc_interface.cpp b/modules/multiplayer/scene_rpc_interface.cpp
index 65090b9316..acc113c901 100644
--- a/modules/multiplayer/scene_rpc_interface.cpp
+++ b/modules/multiplayer/scene_rpc_interface.cpp
@@ -412,8 +412,7 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
if (has_all_peers) {
// They all have verified paths, so send fast.
- peer->set_target_peer(p_to); // To all of you.
- peer->put_packet(packet_cache.ptr(), ofs); // A message with love.
+ multiplayer->send_command(p_to, packet_cache.ptr(), ofs);
} else {
// Unreachable because the node ID is never compressed if the peers doesn't know it.
CRASH_COND(node_id_compression != NETWORK_NODE_ID_COMPRESSION_32);
@@ -438,16 +437,14 @@ void SceneRPCInterface::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, con
bool confirmed = multiplayer->get_path_cache()->is_cache_confirmed(from_path, P);
- peer->set_target_peer(P); // To this one specifically.
-
if (confirmed) {
// This one confirmed path, so use id.
encode_uint32(psc_id, &(packet_cache.write[1]));
- peer->put_packet(packet_cache.ptr(), ofs);
+ multiplayer->send_command(P, packet_cache.ptr(), ofs);
} else {
// This one did not confirm path yet, so use entire path (sorry!).
encode_uint32(0x80000000 | ofs, &(packet_cache.write[1])); // Offset to path and flag.
- peer->put_packet(packet_cache.ptr(), ofs + path_len);
+ multiplayer->send_command(P, packet_cache.ptr(), ofs + path_len);
}
}
}
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index f989fc45a5..f0d3e329ce 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -266,10 +266,10 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
if (err == OK) {
PackedVector3Array faces;
- for (int j = 0; j < md.faces.size(); ++j) {
- Geometry3D::MeshData::Face face = md.faces[j];
+ for (uint32_t j = 0; j < md.faces.size(); ++j) {
+ const Geometry3D::MeshData::Face &face = md.faces[j];
- for (int k = 2; k < face.indices.size(); ++k) {
+ for (uint32_t k = 2; k < face.indices.size(); ++k) {
faces.push_back(md.vertices[face.indices[0]]);
faces.push_back(md.vertices[face.indices[k - 1]]);
faces.push_back(md.vertices[face.indices[k]]);
@@ -392,10 +392,10 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
if (err == OK) {
PackedVector3Array faces;
- for (int j = 0; j < md.faces.size(); ++j) {
- Geometry3D::MeshData::Face face = md.faces[j];
+ for (uint32_t j = 0; j < md.faces.size(); ++j) {
+ const Geometry3D::MeshData::Face &face = md.faces[j];
- for (int k = 2; k < face.indices.size(); ++k) {
+ for (uint32_t k = 2; k < face.indices.size(); ++k) {
faces.push_back(md.vertices[face.indices[0]]);
faces.push_back(md.vertices[face.indices[k - 1]]);
faces.push_back(md.vertices[face.indices[k]]);
diff --git a/modules/noise/noise_texture_2d.cpp b/modules/noise/noise_texture_2d.cpp
index 101a66371b..8c785d7591 100644
--- a/modules/noise/noise_texture_2d.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -152,33 +152,31 @@ Ref<Image> NoiseTexture2D::_generate_texture() {
return Ref<Image>();
}
- Ref<Image> image;
+ Ref<Image> new_image;
if (seamless) {
- image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
+ new_image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
} else {
- image = ref_noise->get_image(size.x, size.y, invert, in_3d_space);
+ new_image = ref_noise->get_image(size.x, size.y, invert, in_3d_space);
}
if (color_ramp.is_valid()) {
- image = _modulate_with_gradient(image, color_ramp);
+ new_image = _modulate_with_gradient(new_image, color_ramp);
}
if (as_normal_map) {
- image->bump_map_to_normal_map(bump_strength);
+ new_image->bump_map_to_normal_map(bump_strength);
}
if (generate_mipmaps) {
- image->generate_mipmaps();
+ new_image->generate_mipmaps();
}
- return image;
+ return new_image;
}
Ref<Image> NoiseTexture2D::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
int width = p_image->get_width();
int height = p_image->get_height();
- Ref<Image> new_image;
- new_image.instantiate();
- new_image->create(width, height, false, Image::FORMAT_RGBA8);
+ Ref<Image> new_image = Image::create_empty(width, height, false, Image::FORMAT_RGBA8);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
@@ -206,8 +204,8 @@ void NoiseTexture2D::_update_texture() {
}
} else {
- Ref<Image> image = _generate_texture();
- _set_texture_image(image);
+ Ref<Image> new_image = _generate_texture();
+ _set_texture_image(new_image);
}
update_queued = false;
}
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index d4469b110b..b5978ab134 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -92,9 +92,11 @@ if env["vulkan"]:
env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_palm_pose_extension.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_composition_layer_depth_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_htc_vive_tracker_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_hand_tracking_extension.cpp")
env_openxr.add_source_files(module_obj, "extensions/openxr_fb_passthrough_extension_wrapper.cpp")
+env_openxr.add_source_files(module_obj, "extensions/openxr_fb_display_refresh_rate_extension.cpp")
env.modules_sources += module_obj
diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp
index 359975a480..0fb4f0773f 100644
--- a/modules/openxr/action_map/openxr_action.cpp
+++ b/modules/openxr/action_map/openxr_action.cpp
@@ -64,13 +64,13 @@ Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_loc
}
String OpenXRAction::get_name_with_set() const {
- String name = get_name();
+ String action_name = get_name();
if (action_set != nullptr) {
- name = action_set->get_name() + "/" + name;
+ action_name = action_set->get_name() + "/" + action_name;
}
- return name;
+ return action_name;
}
void OpenXRAction::set_localized_name(const String p_localized_name) {
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 185e44c29d..123f860ce9 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -224,7 +224,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our interaction profiles
Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -236,7 +236,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Vive controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -257,7 +257,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our WMR controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -280,7 +280,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Meta touch controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -305,7 +305,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Valve index controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -333,7 +333,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our HP MR controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -356,7 +356,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Samsung Odyssey controller profile,
// Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller.
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -379,7 +379,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Vive Cosmos controller
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -403,7 +403,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Note, Vive Focus 3 currently is not yet supported as a stand alone device
// however HTC currently has a beta OpenXR runtime in testing we may support in the near future
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
@@ -427,7 +427,7 @@ void OpenXRActionMap::create_default_action_sets() {
// Create our Huawei controller
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose");
diff --git a/modules/openxr/doc_classes/OpenXRInterface.xml b/modules/openxr/doc_classes/OpenXRInterface.xml
index 25bf496de9..f089fd066e 100644
--- a/modules/openxr/doc_classes/OpenXRInterface.xml
+++ b/modules/openxr/doc_classes/OpenXRInterface.xml
@@ -10,6 +10,19 @@
<tutorials>
<link title="Setting up XR">$DOCS_URL/tutorials/xr/setting_up_xr.html</link>
</tutorials>
+ <methods>
+ <method name="get_available_display_refresh_rates" qualifiers="const">
+ <return type="Array" />
+ <description>
+ Returns display refresh rates supported by the current HMD. Only returned if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="display_refresh_rate" type="float" setter="set_display_refresh_rate" getter="get_display_refresh_rate" default="0.0">
+ The display refresh rate for the current HMD. Only functional if this feature is supported by the OpenXR runtime and after the interface has been initialized.
+ </member>
+ </members>
<signals>
<signal name="pose_recentered">
<description>
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 51c402d746..b5223e5903 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -128,7 +128,7 @@ void OpenXRActionMapEditor::_update_interaction_profiles() {
interaction_profiles.remove_at(0);
tabs->remove_child(interaction_profile);
- interaction_profile->queue_delete();
+ interaction_profile->queue_free();
}
// in with the new...
@@ -205,7 +205,7 @@ void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
action_map->remove_action_set(action_set);
actionsets_vb->remove_child(action_set_editor);
- action_set_editor->queue_delete();
+ action_set_editor->queue_free();
}
void OpenXRActionMapEditor::_on_action_removed() {
@@ -290,7 +290,7 @@ void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
action_map->remove_interaction_profile(interaction_profile);
tabs->remove_child(profile_editor);
- profile_editor->queue_delete();
+ profile_editor->queue_free();
}
void OpenXRActionMapEditor::open_action_map(String p_path) {
@@ -364,7 +364,7 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() {
select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
add_child(select_interaction_profile_dialog);
- _load_action_map(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map"));
+ _load_action_map(GLOBAL_GET("xr/openxr/default_action_map"));
}
OpenXRActionMapEditor::~OpenXRActionMapEditor() {
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 804808a6b9..3869146e8e 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -140,7 +140,7 @@ void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) {
// And remove it....
action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to
actions_vb->remove_child(action_editor);
- action_editor->queue_delete();
+ action_editor->queue_free();
// Let action map editor know so we can update our interaction profiles
emit_signal("action_removed");
diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp
new file mode 100644
index 0000000000..0f6aaf8afb
--- /dev/null
+++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* openxr_composition_layer_depth_extension.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 "openxr_composition_layer_depth_extension.h"
+
+OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::singleton = nullptr;
+
+OpenXRCompositionLayerDepthExtension *OpenXRCompositionLayerDepthExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRCompositionLayerDepthExtension::OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api) :
+ OpenXRExtensionWrapper(p_openxr_api) {
+ singleton = this;
+
+ request_extensions[XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME] = &available;
+}
+
+OpenXRCompositionLayerDepthExtension::~OpenXRCompositionLayerDepthExtension() {
+ singleton = nullptr;
+}
+
+bool OpenXRCompositionLayerDepthExtension::is_available() {
+ return available;
+}
+
+XrCompositionLayerBaseHeader *OpenXRCompositionLayerDepthExtension::get_composition_layer() {
+ // Seems this is all done in our base layer... Just in case this changes...
+
+ return nullptr;
+}
diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h
new file mode 100644
index 0000000000..9533783d83
--- /dev/null
+++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* openxr_composition_layer_depth_extension.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 OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H
+#define OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H
+
+#include "openxr_composition_layer_provider.h"
+#include "openxr_extension_wrapper.h"
+
+class OpenXRCompositionLayerDepthExtension : public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {
+public:
+ static OpenXRCompositionLayerDepthExtension *get_singleton();
+
+ OpenXRCompositionLayerDepthExtension(OpenXRAPI *p_openxr_api);
+ virtual ~OpenXRCompositionLayerDepthExtension() override;
+
+ bool is_available();
+ virtual XrCompositionLayerBaseHeader *get_composition_layer() override;
+
+private:
+ static OpenXRCompositionLayerDepthExtension *singleton;
+
+ bool available = false;
+};
+
+#endif // OPENXR_COMPOSITION_LAYER_DEPTH_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h
index ba51389f7d..a4c4cbe0c6 100644
--- a/modules/openxr/extensions/openxr_composition_layer_provider.h
+++ b/modules/openxr/extensions/openxr_composition_layer_provider.h
@@ -31,6 +31,7 @@
#ifndef OPENXR_COMPOSITION_LAYER_PROVIDER_H
#define OPENXR_COMPOSITION_LAYER_PROVIDER_H
+#include "openxr_extension_wrapper.h"
#include <openxr/openxr.h>
// Interface for OpenXR extensions that provide a composition layer.
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 623c264e6e..c417c90d11 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -100,11 +100,12 @@ public:
class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper {
public:
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0;
+ virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) = 0;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0;
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0;
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0;
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) = 0;
- virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) = 0;
+ virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) = 0;
OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) :
OpenXRExtensionWrapper(p_openxr_api){};
diff --git a/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
new file mode 100644
index 0000000000..c0bbaea5b4
--- /dev/null
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* openxr_fb_display_refresh_rate_extension.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 "openxr_fb_display_refresh_rate_extension.h"
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::singleton = nullptr;
+
+OpenXRDisplayRefreshRateExtension *OpenXRDisplayRefreshRateExtension::get_singleton() {
+ return singleton;
+}
+
+OpenXRDisplayRefreshRateExtension::OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api) :
+ OpenXRExtensionWrapper(p_openxr_api) {
+ singleton = this;
+
+ // Extensions we use for our hand tracking.
+ request_extensions[XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME] = &display_refresh_rate_ext;
+}
+
+OpenXRDisplayRefreshRateExtension::~OpenXRDisplayRefreshRateExtension() {
+ display_refresh_rate_ext = false;
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_created(const XrInstance p_instance) {
+ if (display_refresh_rate_ext) {
+ EXT_INIT_XR_FUNC(xrEnumerateDisplayRefreshRatesFB);
+ EXT_INIT_XR_FUNC(xrGetDisplayRefreshRateFB);
+ EXT_INIT_XR_FUNC(xrRequestDisplayRefreshRateFB);
+ }
+}
+
+void OpenXRDisplayRefreshRateExtension::on_instance_destroyed() {
+ display_refresh_rate_ext = false;
+}
+
+float OpenXRDisplayRefreshRateExtension::get_refresh_rate() const {
+ float refresh_rate = 0.0;
+
+ if (display_refresh_rate_ext) {
+ float rate;
+ XrResult result = xrGetDisplayRefreshRateFB(openxr_api->get_session(), &rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rate [", openxr_api->get_error_string(result), "]");
+ } else {
+ refresh_rate = rate;
+ }
+ }
+
+ return refresh_rate;
+}
+
+void OpenXRDisplayRefreshRateExtension::set_refresh_rate(float p_refresh_rate) {
+ if (display_refresh_rate_ext) {
+ XrResult result = xrRequestDisplayRefreshRateFB(openxr_api->get_session(), p_refresh_rate);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to set refresh rate [", openxr_api->get_error_string(result), "]");
+ }
+ }
+}
+
+Array OpenXRDisplayRefreshRateExtension::get_available_refresh_rates() const {
+ Array arr;
+ XrResult result;
+
+ if (display_refresh_rate_ext) {
+ uint32_t display_refresh_rate_count = 0;
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), 0, &display_refresh_rate_count, nullptr);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ }
+
+ if (display_refresh_rate_count > 0) {
+ float *display_refresh_rates = (float *)memalloc(sizeof(float) * display_refresh_rate_count);
+ if (display_refresh_rates == nullptr) {
+ print_line("OpenXR: Failed to obtain refresh rates memory buffer [", openxr_api->get_error_string(result), "]");
+ return arr;
+ }
+
+ result = xrEnumerateDisplayRefreshRatesFB(openxr_api->get_session(), display_refresh_rate_count, &display_refresh_rate_count, display_refresh_rates);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to obtain refresh rates count [", openxr_api->get_error_string(result), "]");
+ memfree(display_refresh_rates);
+ return arr;
+ }
+
+ for (uint32_t i = 0; i < display_refresh_rate_count; i++) {
+ float refresh_rate = display_refresh_rates[i];
+ arr.push_back(Variant(refresh_rate));
+ }
+
+ memfree(display_refresh_rates);
+ }
+ }
+
+ return arr;
+}
diff --git a/modules/websocket/wsl_client.h b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
index dfb989fdd3..dcd52fe4d1 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/openxr/extensions/openxr_fb_display_refresh_rate_extension.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* wsl_client.h */
+/* openxr_fb_display_refresh_rate_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,64 +28,43 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WSL_CLIENT_H
-#define WSL_CLIENT_H
+#ifndef OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
+#define OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
-#ifndef WEB_ENABLED
+// This extension gives us access to the possible display refresh rates
+// supported by the HMD.
+// While this is an FB extension it has been adopted by most runtimes and
+// will likely become core in the near future.
-#include "core/error/error_list.h"
-#include "core/io/stream_peer_tcp.h"
-#include "core/io/stream_peer_tls.h"
-#include "websocket_client.h"
-#include "wsl_peer.h"
-#include "wslay/wslay.h"
+#include "../openxr_api.h"
+#include "../util.h"
-class WSLClient : public WebSocketClient {
- GDCIIMPL(WSLClient, WebSocketClient);
+#include "openxr_extension_wrapper.h"
-private:
- int _in_buf_size = DEF_BUF_SHIFT;
- int _in_pkt_size = DEF_PKT_SHIFT;
- int _out_buf_size = DEF_BUF_SHIFT;
- int _out_pkt_size = DEF_PKT_SHIFT;
+class OpenXRDisplayRefreshRateExtension : public OpenXRExtensionWrapper {
+public:
+ static OpenXRDisplayRefreshRateExtension *get_singleton();
- Ref<WSLPeer> _peer;
- Ref<StreamPeerTCP> _tcp;
- Ref<StreamPeer> _connection;
- ConnectionStatus _status = CONNECTION_DISCONNECTED;
+ OpenXRDisplayRefreshRateExtension(OpenXRAPI *p_openxr_api);
+ virtual ~OpenXRDisplayRefreshRateExtension() override;
- CharString _request;
- int _requested = 0;
+ virtual void on_instance_created(const XrInstance p_instance) override;
+ virtual void on_instance_destroyed() override;
- uint8_t _resp_buf[WSL_MAX_HEADER_SIZE];
- int _resp_pos = 0;
+ float get_refresh_rate() const;
+ void set_refresh_rate(float p_refresh_rate);
- String _key;
- String _host;
- uint16_t _port = 0;
- Array _ip_candidates;
- Vector<String> _protocols;
- bool _use_tls = false;
- IP::ResolverID _resolver_id = IP::RESOLVER_INVALID_ID;
+ Array get_available_refresh_rates() const;
- void _do_handshake();
- bool _verify_headers(String &r_protocol);
+private:
+ static OpenXRDisplayRefreshRateExtension *singleton;
-public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_tls, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
- int get_max_packet_size() const override;
- Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
- void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
- IPAddress get_connected_host() const override;
- uint16_t get_connected_port() const override;
- virtual ConnectionStatus get_connection_status() const override;
- virtual void poll() override;
+ bool display_refresh_rate_ext = false;
- WSLClient();
- ~WSLClient();
+ // OpenXR API call wrappers
+ EXT_PROTO_XRRESULT_FUNC4(xrEnumerateDisplayRefreshRatesFB, (XrSession), session, (uint32_t), displayRefreshRateCapacityInput, (uint32_t *), displayRefreshRateCountOutput, (float *), displayRefreshRates);
+ EXT_PROTO_XRRESULT_FUNC2(xrGetDisplayRefreshRateFB, (XrSession), session, (float *), display_refresh_rate);
+ EXT_PROTO_XRRESULT_FUNC2(xrRequestDisplayRefreshRateFB, (XrSession), session, (float), display_refresh_rate);
};
-#endif // WEB_ENABLED
-
-#endif // WSL_CLIENT_H
+#endif // OPENXR_FB_DISPLAY_REFRESH_RATE_EXTENSION_H
diff --git a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
index 88cc7c061c..4d996e6283 100644
--- a/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
+++ b/modules/openxr/extensions/openxr_htc_vive_tracker_extension.cpp
@@ -69,6 +69,34 @@ bool OpenXRHTCViveTrackerExtension::on_event_polled(const XrEventDataBuffer &eve
bool OpenXRHTCViveTrackerExtension::is_path_supported(const String &p_path) {
if (p_path == "/interaction_profiles/htc/vive_tracker_htcx") {
return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/handheld_object") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_foot") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_shoulder") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_elbow") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/left_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/right_knee") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/waist") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/chest") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/camera") {
+ return available;
+ } else if (p_path == "/user/vive_tracker_htcx/role/keyboard") {
+ return available;
}
// Not a path under this extensions control, so we return true;
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index f9e771c934..ee5bda2881 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -228,6 +228,12 @@ void OpenXRVulkanExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usab
p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_UINT);
}
+void OpenXRVulkanExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) {
+ p_usable_swap_chains.push_back(VK_FORMAT_R32_SFLOAT);
+ p_usable_swap_chains.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
+ p_usable_swap_chains.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
+}
+
bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
XrSwapchainImageVulkanKHR *images = nullptr;
@@ -271,7 +277,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1;
- uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT;
switch (p_swapchain_format) {
case VK_FORMAT_R8G8B8A8_SRGB:
@@ -283,16 +289,32 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
// will thus do an sRGB -> Linear conversion as expected.
// format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case VK_FORMAT_B8G8R8A8_SRGB:
// format = RenderingDevice::DATA_FORMAT_B8G8R8A8_SRGB;
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case VK_FORMAT_R8G8B8A8_UINT:
format = RenderingDevice::DATA_FORMAT_R8G8B8A8_UINT;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
break;
case VK_FORMAT_B8G8R8A8_UINT:
format = RenderingDevice::DATA_FORMAT_B8G8R8A8_UINT;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+ break;
+ case VK_FORMAT_R32_SFLOAT:
+ format = RenderingDevice::DATA_FORMAT_R32_SFLOAT;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ break;
+ case VK_FORMAT_D24_UNORM_S8_UINT:
+ format = RenderingDevice::DATA_FORMAT_D24_UNORM_S8_UINT;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ break;
+ case VK_FORMAT_D32_SFLOAT_S8_UINT:
+ format = RenderingDevice::DATA_FORMAT_D32_SFLOAT_S8_UINT;
+ usage_flags |= RenderingDevice::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
break;
default:
// continue with our default value
@@ -328,8 +350,7 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
break;
}
- Vector<RID> image_rids;
- Vector<RID> framebuffers;
+ Vector<RID> texture_rids;
// create Godot texture objects for each entry in our swapchain
for (uint64_t i = 0; i < swapchain_length; i++) {
@@ -344,19 +365,10 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in
1,
p_array_size);
- image_rids.push_back(image_rid);
-
- {
- Vector<RID> fb;
- fb.push_back(image_rid);
-
- RID fb_rid = rendering_device->framebuffer_create(fb, RenderingDevice::INVALID_ID, p_array_size);
- framebuffers.push_back(fb_rid);
- }
+ texture_rids.push_back(image_rid);
}
- data->image_rids = image_rids;
- data->framebuffers = framebuffers;
+ data->texture_rids = texture_rids;
memfree(images);
@@ -370,33 +382,19 @@ bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
- r_camera_matrix.matrix[j][i] = matrix.m[j * 4 + i];
+ r_camera_matrix.columns[j][i] = matrix.m[j * 4 + i];
}
}
return true;
}
-bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) {
+RID OpenXRVulkanExtension::get_texture(void *p_swapchain_graphics_data, int p_image_index) {
SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
- ERR_FAIL_NULL_V(data, false);
- ERR_FAIL_COND_V(p_from_render_target.is_null(), false);
+ ERR_FAIL_NULL_V(data, RID());
- RID source_image = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(p_from_render_target);
- ERR_FAIL_COND_V(source_image.is_null(), false);
-
- RID depth_image; // TODO implement
-
- ERR_FAIL_INDEX_V(p_image_index, data->framebuffers.size(), false);
- RID fb = data->framebuffers[p_image_index];
- ERR_FAIL_COND_V(fb.is_null(), false);
-
- // Our vulkan extension can only be used in conjunction with our vulkan renderer.
- RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
- ERR_FAIL_NULL_V(copy_effects, false);
- copy_effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview);
-
- return true;
+ ERR_FAIL_INDEX_V(p_image_index, data->texture_rids.size(), RID());
+ return data->texture_rids[p_image_index];
}
void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
@@ -411,17 +409,11 @@ void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_g
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
ERR_FAIL_NULL(rendering_device);
- for (int i = 0; i < data->image_rids.size(); i++) {
- // This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain
- rendering_device->free(data->image_rids[i]);
- }
- data->image_rids.clear();
-
- for (int i = 0; i < data->framebuffers.size(); i++) {
+ for (int i = 0; i < data->texture_rids.size(); i++) {
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain
- rendering_device->free(data->framebuffers[i]);
+ rendering_device->free(data->texture_rids[i]);
}
- data->framebuffers.clear();
+ data->texture_rids.clear();
memdelete(data);
*p_swapchain_graphics_data = nullptr;
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index d6e9917900..71abe3b166 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -69,11 +69,12 @@ public:
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) override;
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
+ virtual void get_usable_depth_formats(Vector<int64_t> &p_usable_swap_chains) override;
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) override;
- virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) override;
+ virtual RID get_texture(void *p_swapchain_graphics_data, int p_image_index) override;
private:
static OpenXRVulkanExtension *singleton;
@@ -81,8 +82,7 @@ private:
struct SwapchainGraphicsData {
bool is_multiview;
- Vector<RID> image_rids;
- Vector<RID> framebuffers;
+ Vector<RID> texture_rids;
};
bool check_graphics_api_support(XrVersion p_desired_version);
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 16879ac4e5..1ff1dac512 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -49,6 +49,8 @@
#include "extensions/openxr_vulkan_extension.h"
#endif
+#include "extensions/openxr_composition_layer_depth_extension.h"
+#include "extensions/openxr_fb_display_refresh_rate_extension.h"
#include "extensions/openxr_fb_passthrough_extension_wrapper.h"
#include "extensions/openxr_hand_tracking_extension.h"
#include "extensions/openxr_htc_vive_tracker_extension.h"
@@ -130,11 +132,9 @@ bool OpenXRAPI::load_layer_properties() {
result = xrEnumerateApiLayerProperties(num_layer_properties, &num_layer_properties, layer_properties);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate api layer properties");
-#ifdef DEBUG
for (uint32_t i = 0; i < num_layer_properties; i++) {
- print_line("OpenXR: Found OpenXR layer ", layer_properties[i].layerName);
+ print_verbose(String("OpenXR: Found OpenXR layer ") + layer_properties[i].layerName);
}
-#endif
return true;
}
@@ -162,11 +162,9 @@ bool OpenXRAPI::load_supported_extensions() {
result = xrEnumerateInstanceExtensionProperties(nullptr, num_supported_extensions, &num_supported_extensions, supported_extensions);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate extension properties");
-#ifdef DEBUG
for (uint32_t i = 0; i < num_supported_extensions; i++) {
- print_line("OpenXR: Found OpenXR extension ", supported_extensions[i].extensionName);
+ print_verbose(String("OpenXR: Found OpenXR extension ") + supported_extensions[i].extensionName);
}
-#endif
return true;
}
@@ -174,17 +172,10 @@ bool OpenXRAPI::load_supported_extensions() {
bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
for (uint32_t i = 0; i < num_supported_extensions; i++) {
if (supported_extensions[i].extensionName == p_extension) {
-#ifdef DEBUG
- print_line("OpenXR: requested extension", p_extension, "is supported");
-#endif
return true;
}
}
-#ifdef DEBUG
- print_line("OpenXR: requested extension", p_extension, "is not supported");
-#endif
-
return false;
}
@@ -244,7 +235,7 @@ bool OpenXRAPI::create_instance() {
if (!is_extension_supported(requested_extension.key)) {
if (requested_extension.value == nullptr) {
// nullptr means this is a manditory extension so we fail
- ERR_FAIL_V_MSG(false, "OpenXR: OpenXR Runtime does not support OpenGL extension!");
+ ERR_FAIL_V_MSG(false, String("OpenXR: OpenXR Runtime does not support ") + requested_extension.key + String(" extension!"));
} else {
// set this extension as not supported
*requested_extension.value = false;
@@ -400,11 +391,9 @@ bool OpenXRAPI::load_supported_view_configuration_types() {
result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations");
-#ifdef DEBUG
for (uint32_t i = 0; i < num_view_configuration_types; i++) {
- print_line("OpenXR: Found supported view configuration ", OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i]));
+ print_verbose(String("OpenXR: Found supported view configuration ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i]));
}
-#endif
return true;
}
@@ -453,17 +442,15 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType
result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate view configurations");
-#ifdef DEBUG
for (uint32_t i = 0; i < view_count; i++) {
- print_line("OpenXR: Found supported view configuration view");
- print_line(" - width: ", view_configuration_views[i].maxImageRectWidth);
- print_line(" - height: ", view_configuration_views[i].maxImageRectHeight);
- print_line(" - sample count: ", view_configuration_views[i].maxSwapchainSampleCount);
- print_line(" - recommended render width: ", view_configuration_views[i].recommendedImageRectWidth);
- print_line(" - recommended render height: ", view_configuration_views[i].recommendedImageRectHeight);
- print_line(" - recommended render sample count: ", view_configuration_views[i].recommendedSwapchainSampleCount);
+ print_verbose("OpenXR: Found supported view configuration view");
+ print_verbose(String(" - width: ") + itos(view_configuration_views[i].maxImageRectWidth));
+ print_verbose(String(" - height: ") + itos(view_configuration_views[i].maxImageRectHeight));
+ print_verbose(String(" - sample count: ") + itos(view_configuration_views[i].maxSwapchainSampleCount));
+ print_verbose(String(" - recommended render width: ") + itos(view_configuration_views[i].recommendedImageRectWidth));
+ print_verbose(String(" - recommended render height: ") + itos(view_configuration_views[i].recommendedImageRectHeight));
+ print_verbose(String(" - recommended render sample count: ") + itos(view_configuration_views[i].recommendedSwapchainSampleCount));
}
-#endif
return true;
}
@@ -545,11 +532,9 @@ bool OpenXRAPI::load_supported_reference_spaces() {
result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces");
- // #ifdef DEBUG
for (uint32_t i = 0; i < num_reference_spaces; i++) {
- print_line("OpenXR: Found supported reference space ", OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
+ print_verbose(String("OpenXR: Found supported reference space ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
}
- // #endif
return true;
}
@@ -642,11 +627,9 @@ bool OpenXRAPI::load_supported_swapchain_formats() {
result = xrEnumerateSwapchainFormats(session, num_swapchain_formats, &num_swapchain_formats, supported_swapchain_formats);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate swapchain formats");
- // #ifdef DEBUG
for (uint32_t i = 0; i < num_swapchain_formats; i++) {
- print_line("OpenXR: Found supported swapchain format ", get_swapchain_format_name(supported_swapchain_formats[i]));
+ print_verbose(String("OpenXR: Found supported swapchain format ") + get_swapchain_format_name(supported_swapchain_formats[i]));
}
- // #endif
return true;
}
@@ -663,7 +646,7 @@ bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) {
return false;
}
-bool OpenXRAPI::create_main_swapchain() {
+bool OpenXRAPI::create_swapchains() {
ERR_FAIL_NULL_V(graphics_extension, false);
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
@@ -681,34 +664,36 @@ bool OpenXRAPI::create_main_swapchain() {
already rendering the next frame.
Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create,
- as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains
- until such time as we implement VRS.
+ as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support
*/
- // Build a vector with swapchain formats we want to use, from best fit to worst
- Vector<int64_t> usable_swapchain_formats;
- int64_t swapchain_format_to_use = 0;
+ Size2 recommended_size = get_recommended_target_size();
- graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats);
+ // We start with our color swapchain...
+ {
+ // Build a vector with swapchain formats we want to use, from best fit to worst
+ Vector<int64_t> usable_swapchain_formats;
+ int64_t swapchain_format_to_use = 0;
- // now find out which one is supported
- for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
- if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
- swapchain_format_to_use = usable_swapchain_formats[i];
- }
- }
+ graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats);
- if (swapchain_format_to_use == 0) {
- swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best...
- print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead.");
- } else {
- print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use));
- }
+ // now find out which one is supported
+ for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
+ if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
+ swapchain_format_to_use = usable_swapchain_formats[i];
+ }
+ }
- Size2 recommended_size = get_recommended_target_size();
+ if (swapchain_format_to_use == 0) {
+ swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best...
+ print_line("Couldn't find usable color swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead.");
+ } else {
+ print_verbose(String("Using color swap chain format:") + get_swapchain_format_name(swapchain_format_to_use));
+ }
- if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) {
- return false;
+ if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) {
+ return false;
+ }
}
views = (XrView *)memalloc(sizeof(XrView) * view_count);
@@ -717,18 +702,73 @@ bool OpenXRAPI::create_main_swapchain() {
projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count);
ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views");
+ // We create our depth swapchain if:
+ // - we support our depth layer extension
+ // - we have our spacewarp extension (not yet implemented)
+ if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) {
+ // Build a vector with swapchain formats we want to use, from best fit to worst
+ Vector<int64_t> usable_swapchain_formats;
+ int64_t swapchain_format_to_use = 0;
+
+ graphics_extension->get_usable_depth_formats(usable_swapchain_formats);
+
+ // now find out which one is supported
+ for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) {
+ if (is_swapchain_format_supported(usable_swapchain_formats[i])) {
+ swapchain_format_to_use = usable_swapchain_formats[i];
+ }
+ }
+
+ if (swapchain_format_to_use == 0) {
+ swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best...
+ print_line("Couldn't find usable depth swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead.");
+ } else {
+ print_verbose(String("Using depth swap chain format:") + get_swapchain_format_name(swapchain_format_to_use));
+ }
+
+ if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) {
+ return false;
+ }
+
+ depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * view_count);
+ ERR_FAIL_NULL_V_MSG(depth_views, false, "OpenXR Couldn't allocate memory for depth views");
+ }
+
+ // We create our velocity swapchain if:
+ // - we have our spacewarp extension (not yet implemented)
+ {
+ // TBD
+ }
+
for (uint32_t i = 0; i < view_count; i++) {
views[i].type = XR_TYPE_VIEW;
views[i].next = nullptr;
projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
projection_views[i].next = nullptr;
- projection_views[i].subImage.swapchain = swapchain;
+ projection_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain;
projection_views[i].subImage.imageArrayIndex = i;
projection_views[i].subImage.imageRect.offset.x = 0;
projection_views[i].subImage.imageRect.offset.y = 0;
projection_views[i].subImage.imageRect.extent.width = recommended_size.width;
projection_views[i].subImage.imageRect.extent.height = recommended_size.height;
+
+ if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) {
+ projection_views[i].next = &depth_views[i];
+
+ depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
+ depth_views[i].next = nullptr;
+ depth_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain;
+ depth_views[i].subImage.imageArrayIndex = 0;
+ depth_views[i].subImage.imageRect.offset.x = 0;
+ depth_views[i].subImage.imageRect.offset.y = 0;
+ depth_views[i].subImage.imageRect.extent.width = recommended_size.width;
+ depth_views[i].subImage.imageRect.extent.height = recommended_size.height;
+ depth_views[i].minDepth = 0.0;
+ depth_views[i].maxDepth = 1.0;
+ depth_views[i].nearZ = 0.01; // Near and far Z will be set to the correct values in fill_projection_matrix
+ depth_views[i].farZ = 100.0;
+ }
};
return true;
@@ -740,7 +780,7 @@ void OpenXRAPI::destroy_session() {
}
if (graphics_extension) {
- graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data);
+ graphics_extension->cleanup_swapchain_graphics_data(&swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data);
}
if (views != nullptr) {
@@ -753,9 +793,16 @@ void OpenXRAPI::destroy_session() {
projection_views = nullptr;
}
- if (swapchain != XR_NULL_HANDLE) {
- xrDestroySwapchain(swapchain);
- swapchain = XR_NULL_HANDLE;
+ if (depth_views != nullptr) {
+ memfree(depth_views);
+ depth_views = nullptr;
+ }
+
+ for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
+ if (swapchains[i].swapchain != XR_NULL_HANDLE) {
+ xrDestroySwapchain(swapchains[i].swapchain);
+ swapchains[i].swapchain = XR_NULL_HANDLE;
+ }
}
if (supported_swapchain_formats != nullptr) {
@@ -789,7 +836,7 @@ void OpenXRAPI::destroy_session() {
}
}
-bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) {
+bool OpenXRAPI::create_swapchain(XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false);
ERR_FAIL_NULL_V(graphics_extension, false);
@@ -807,7 +854,7 @@ bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, u
XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
next_pointer, // next
0, // createFlags
- XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags
+ p_usage_flags, // usageFlags
p_swapchain_format, // format
p_sample_count, // sampleCount
p_width, // width
@@ -835,9 +882,7 @@ bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, u
}
bool OpenXRAPI::on_state_idle() {
-#ifdef DEBUG
- print_line("On state idle");
-#endif
+ print_verbose("On state idle");
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_idle();
@@ -847,9 +892,7 @@ bool OpenXRAPI::on_state_idle() {
}
bool OpenXRAPI::on_state_ready() {
-#ifdef DEBUG
- print_line("On state ready");
-#endif
+ print_verbose("On state ready");
// begin session
XrSessionBeginInfo session_begin_info = {
@@ -871,7 +914,7 @@ bool OpenXRAPI::on_state_ready() {
// That will be very very ugly
// The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module
- if (!create_main_swapchain()) {
+ if (!create_swapchains()) {
return false;
}
@@ -892,9 +935,7 @@ bool OpenXRAPI::on_state_ready() {
}
bool OpenXRAPI::on_state_synchronized() {
-#ifdef DEBUG
- print_line("On state synchronized");
-#endif
+ print_verbose("On state synchronized");
// Just in case, see if we already have active trackers...
List<RID> trackers;
@@ -911,9 +952,7 @@ bool OpenXRAPI::on_state_synchronized() {
}
bool OpenXRAPI::on_state_visible() {
-#ifdef DEBUG
- print_line("On state visible");
-#endif
+ print_verbose("On state visible");
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_visible();
@@ -927,9 +966,7 @@ bool OpenXRAPI::on_state_visible() {
}
bool OpenXRAPI::on_state_focused() {
-#ifdef DEBUG
- print_line("On state focused");
-#endif
+ print_verbose("On state focused");
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_focused();
@@ -943,9 +980,7 @@ bool OpenXRAPI::on_state_focused() {
}
bool OpenXRAPI::on_state_stopping() {
-#ifdef DEBUG
- print_line("On state stopping");
-#endif
+ print_verbose("On state stopping");
if (xr_interface) {
xr_interface->on_state_stopping();
@@ -971,9 +1006,7 @@ bool OpenXRAPI::on_state_stopping() {
}
bool OpenXRAPI::on_state_loss_pending() {
-#ifdef DEBUG
- print_line("On state loss pending");
-#endif
+ print_verbose("On state loss pending");
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_loss_pending();
@@ -985,9 +1018,7 @@ bool OpenXRAPI::on_state_loss_pending() {
}
bool OpenXRAPI::on_state_exiting() {
-#ifdef DEBUG
- print_line("On state existing");
-#endif
+ print_verbose("On state existing");
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->on_state_exiting();
@@ -1259,12 +1290,10 @@ XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform,
head_pose_confidence = confidence;
if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {
print_line("OpenXR head space location not valid (check tracking?)");
-#ifdef DEBUG
} else if (head_pose_confidence == XRPose::XR_TRACKING_CONFIDENCE_LOW) {
- print_line("OpenVR Head pose now tracking with low confidence");
+ print_verbose("OpenVR Head pose now tracking with low confidence");
} else {
- print_line("OpenVR Head pose now tracking with high confidence");
-#endif
+ print_verbose("OpenVR Head pose now tracking with high confidence");
}
}
@@ -1304,6 +1333,15 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z
return false;
}
+ // if we're using depth views, make sure we update our near and far there...
+ if (depth_views != nullptr) {
+ for (uint32_t i = 0; i < view_count; i++) {
+ depth_views[i].nearZ = p_z_near;
+ depth_views[i].farZ = p_z_far;
+ }
+ }
+
+ // now update our projection
return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix);
}
@@ -1343,7 +1381,7 @@ bool OpenXRAPI::poll_events() {
// TODO We get this event if we're about to loose our OpenXR instance.
// We should queue exiting Godot at this point.
- print_verbose("OpenXR EVENT: instance loss pending at " + itos(event->lossTime));
+ print_verbose(String("OpenXR EVENT: instance loss pending at ") + itos(event->lossTime));
return false;
} break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
@@ -1351,9 +1389,9 @@ bool OpenXRAPI::poll_events() {
session_state = event->state;
if (session_state >= XR_SESSION_STATE_MAX_ENUM) {
- print_verbose("OpenXR EVENT: session state changed to UNKNOWN - " + itos(session_state));
+ print_verbose(String("OpenXR EVENT: session state changed to UNKNOWN - ") + itos(session_state));
} else {
- print_verbose("OpenXR EVENT: session state changed to " + OpenXRUtil::get_session_state_name(session_state));
+ print_verbose(String("OpenXR EVENT: session state changed to ") + OpenXRUtil::get_session_state_name(session_state));
switch (session_state) {
case XR_SESSION_STATE_IDLE:
@@ -1388,7 +1426,7 @@ bool OpenXRAPI::poll_events() {
case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING: {
XrEventDataReferenceSpaceChangePending *event = (XrEventDataReferenceSpaceChangePending *)&runtimeEvent;
- print_verbose("OpenXR EVENT: reference space type " + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
+ print_verbose(String("OpenXR EVENT: reference space type ") + OpenXRUtil::get_reference_space_name(event->referenceSpaceType) + " change pending!");
if (event->poseValid && xr_interface) {
xr_interface->on_pose_recentered();
}
@@ -1407,7 +1445,7 @@ bool OpenXRAPI::poll_events() {
} break;
default:
if (!handled) {
- print_verbose("OpenXR Unhandled event type " + OpenXRUtil::get_structure_type_name(runtimeEvent.type));
+ print_verbose(String("OpenXR Unhandled event type ") + OpenXRUtil::get_structure_type_name(runtimeEvent.type));
}
break;
}
@@ -1442,15 +1480,15 @@ bool OpenXRAPI::process() {
return true;
}
-bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) {
- ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use...
+bool OpenXRAPI::acquire_image(OpenXRSwapChainInfo &p_swapchain) {
+ ERR_FAIL_COND_V(p_swapchain.image_acquired, true); // this was not released when it should be, error out and re-use...
XrResult result;
XrSwapchainImageAcquireInfo swapchain_image_acquire_info = {
XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type
nullptr // next
};
- result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index);
+ result = xrAcquireSwapchainImage(p_swapchain.swapchain, &swapchain_image_acquire_info, &p_swapchain.image_index);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]");
return false;
@@ -1462,7 +1500,7 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index)
17000000 // timeout in nanoseconds
};
- result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info);
+ result = xrWaitSwapchainImage(p_swapchain.swapchain, &swapchain_image_wait_info);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]");
return false;
@@ -1471,12 +1509,12 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index)
return true;
}
-bool OpenXRAPI::release_image(XrSwapchain p_swapchain) {
+bool OpenXRAPI::release_image(OpenXRSwapChainInfo &p_swapchain) {
XrSwapchainImageReleaseInfo swapchain_image_release_info = {
XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type
nullptr // next
};
- XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info);
+ XrResult result = xrReleaseSwapchainImage(p_swapchain.swapchain, &swapchain_image_release_info);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]");
return false;
@@ -1515,7 +1553,7 @@ void OpenXRAPI::pre_render() {
if (frame_state.predictedDisplayPeriod > 500000000) {
// display period more then 0.5 seconds? must be wrong data
- print_verbose("OpenXR resetting invalid display period " + rtos(frame_state.predictedDisplayPeriod));
+ print_verbose(String("OpenXR resetting invalid display period ") + rtos(frame_state.predictedDisplayPeriod));
frame_state.predictedDisplayPeriod = 0;
}
@@ -1562,13 +1600,11 @@ void OpenXRAPI::pre_render() {
}
if (view_pose_valid != pose_valid) {
view_pose_valid = pose_valid;
-#ifdef DEBUG
if (!view_pose_valid) {
- print_line("OpenXR View pose became invalid");
+ print_verbose("OpenXR View pose became invalid");
} else {
- print_line("OpenXR View pose became valid");
+ print_verbose("OpenXR View pose became valid");
}
-#endif
}
// let's start our frame..
@@ -1590,28 +1626,41 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) {
// TODO: at some point in time we may support multiple viewports in which case we need to handle that...
+ // Acquire our images
+ for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
+ if (!swapchains[i].image_acquired && swapchains[i].swapchain != XR_NULL_HANDLE) {
+ if (!acquire_image(swapchains[i])) {
+ return false;
+ }
+ swapchains[i].image_acquired = true;
+ }
+ }
+
return true;
}
+RID OpenXRAPI::get_color_texture() {
+ if (swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
+ return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_COLOR].image_index);
+ } else {
+ return RID();
+ }
+}
+
+RID OpenXRAPI::get_depth_texture() {
+ if (swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) {
+ return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_DEPTH].image_index);
+ } else {
+ return RID();
+ }
+}
+
void OpenXRAPI::post_draw_viewport(RID p_render_target) {
if (!can_render()) {
return;
}
- // TODO: at some point in time we may support multiple viewports in which case we need to handle that...
-
- // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something
- if (!image_acquired) {
- if (!acquire_image(swapchain, image_index)) {
- return;
- }
- image_acquired = true;
-
- // print_line("OpenXR: acquired image " + itos(image_index) + ", copying...");
-
- // Copy our buffer into our swap chain (remove once PR 51179 is done)
- graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index);
- }
+ // Nothing to do here at this point in time...
};
void OpenXRAPI::end_frame() {
@@ -1623,7 +1672,7 @@ void OpenXRAPI::end_frame() {
return;
}
- if (frame_state.shouldRender && view_pose_valid && !image_acquired) {
+ if (frame_state.shouldRender && view_pose_valid && !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!");
}
@@ -1631,7 +1680,7 @@ void OpenXRAPI::end_frame() {
// - shouldRender set to true
// - a valid view pose for projection_views[eye].pose to submit layer
// - an image to render
- if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) {
+ if (!frame_state.shouldRender || !view_pose_valid || !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) {
// submit 0 layers when we shouldn't render
XrFrameEndInfo frame_end_info = {
XR_TYPE_FRAME_END_INFO, // type
@@ -1652,10 +1701,12 @@ void OpenXRAPI::end_frame() {
}
// release our swapchain image if we acquired it
- if (image_acquired) {
- image_acquired = false; // whether we succeed or not, consider this released.
+ for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) {
+ if (swapchains[i].image_acquired) {
+ swapchains[i].image_acquired = false; // whether we succeed or not, consider this released.
- release_image(swapchain);
+ release_image(swapchains[i]);
+ }
}
for (uint32_t eye = 0; eye < view_count; eye++) {
@@ -1698,6 +1749,31 @@ void OpenXRAPI::end_frame() {
}
}
+float OpenXRAPI::get_display_refresh_rate() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext) {
+ return drrext->get_refresh_rate();
+ }
+
+ return 0.0;
+}
+
+void OpenXRAPI::set_display_refresh_rate(float p_refresh_rate) {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ drrext->set_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRAPI::get_available_display_refresh_rates() const {
+ OpenXRDisplayRefreshRateExtension *drrext = OpenXRDisplayRefreshRateExtension::get_singleton();
+ if (drrext != nullptr) {
+ return drrext->get_available_refresh_rates();
+ }
+
+ return Array();
+}
+
OpenXRAPI::OpenXRAPI() {
// OpenXRAPI is only constructed if OpenXR is enabled.
singleton = this;
@@ -1763,9 +1839,11 @@ OpenXRAPI::OpenXRAPI() {
// register our other extensions
register_extension_wrapper(memnew(OpenXRPalmPoseExtension(this)));
+ register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension(this)));
register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this)));
register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this)));
register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this)));
+ register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension(this)));
}
OpenXRAPI::~OpenXRAPI() {
@@ -1991,8 +2069,6 @@ RID OpenXRAPI::action_set_create(const String p_name, const String p_localized_n
copy_string_to_char_buffer(p_name, action_set_info.actionSetName, XR_MAX_ACTION_SET_NAME_SIZE);
copy_string_to_char_buffer(p_localized_name, action_set_info.localizedActionSetName, XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE);
- // print_line("Creating action set ", action_set_info.actionSetName, " - ", action_set_info.localizedActionSetName, " (", itos(action_set_info.priority), ")");
-
XrResult result = xrCreateActionSet(instance, &action_set_info, &action_set.handle);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to create action set ", p_name, "! [", get_error_string(result), "]");
@@ -2146,8 +2222,6 @@ RID OpenXRAPI::action_create(RID p_action_set, const String p_name, const String
copy_string_to_char_buffer(p_name, action_info.actionName, XR_MAX_ACTION_NAME_SIZE);
copy_string_to_char_buffer(p_localized_name, action_info.localizedActionName, XR_MAX_LOCALIZED_ACTION_NAME_SIZE);
- // print_line("Creating action ", action_info.actionName, action_info.localizedActionName, action_info.countSubactionPaths);
-
XrResult result = xrCreateAction(action_set->handle, &action_info, &action.handle);
if (XR_FAILED(result)) {
print_line("OpenXR: failed to create action ", p_name, "! [", get_error_string(result), "]");
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 316886239e..5dce749351 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -84,8 +84,6 @@ private:
bool ext_vive_focus3_available = false;
bool ext_huawei_controller_available = false;
- bool is_path_supported(const String &p_path);
-
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
@@ -120,15 +118,28 @@ private:
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
XrSystemGraphicsProperties graphics_properties;
- void *swapchain_graphics_data = nullptr;
- uint32_t image_index = 0;
- bool image_acquired = false;
uint32_t view_count = 0;
XrViewConfigurationView *view_configuration_views = nullptr;
XrView *views = nullptr;
XrCompositionLayerProjectionView *projection_views = nullptr;
- XrSwapchain swapchain = XR_NULL_HANDLE;
+ XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available
+
+ enum OpenXRSwapChainTypes {
+ OPENXR_SWAPCHAIN_COLOR,
+ OPENXR_SWAPCHAIN_DEPTH,
+ // OPENXR_SWAPCHAIN_VELOCITY,
+ OPENXR_SWAPCHAIN_MAX
+ };
+
+ struct OpenXRSwapChainInfo {
+ XrSwapchain swapchain = XR_NULL_HANDLE;
+ void *swapchain_graphics_data = nullptr;
+ uint32_t image_index = 0;
+ bool image_acquired = false;
+ };
+
+ OpenXRSwapChainInfo swapchains[OPENXR_SWAPCHAIN_MAX];
XrSpace play_space = XR_NULL_HANDLE;
XrSpace view_space = XR_NULL_HANDLE;
@@ -212,13 +223,13 @@ private:
bool setup_spaces();
bool load_supported_swapchain_formats();
bool is_swapchain_format_supported(int64_t p_swapchain_format);
- bool create_main_swapchain();
+ bool create_swapchains();
void destroy_session();
// swapchains
- bool create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data);
- bool acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index);
- bool release_image(XrSwapchain p_swapchain);
+ bool create_swapchain(XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data);
+ bool acquire_image(OpenXRSwapChainInfo &p_swapchain);
+ bool release_image(OpenXRSwapChainInfo &p_swapchain);
// action map
struct Tracker { // Trackers represent tracked physical objects such as controllers, pucks, etc.
@@ -289,6 +300,7 @@ public:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
+ bool is_path_supported(const String &p_path);
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
@@ -318,9 +330,16 @@ public:
void pre_render();
bool pre_draw_viewport(RID p_render_target);
+ RID get_color_texture();
+ RID get_depth_texture();
void post_draw_viewport(RID p_render_target);
void end_frame();
+ // Display refresh rate
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
// action map
String get_default_action_map_resource_name();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 01e148e00f..bdf437b0b7 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -41,6 +41,13 @@ void OpenXRInterface::_bind_methods() {
ADD_SIGNAL(MethodInfo("session_focussed"));
ADD_SIGNAL(MethodInfo("session_visible"));
ADD_SIGNAL(MethodInfo("pose_recentered"));
+
+ // Display refresh rate
+ ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
+ ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "display_refresh_rate"), "set_display_refresh_rate", "get_display_refresh_rate");
+
+ ClassDB::bind_method(D_METHOD("get_available_display_refresh_rates"), &OpenXRInterface::get_available_display_refresh_rates);
}
StringName OpenXRInterface::get_name() const {
@@ -132,10 +139,10 @@ void OpenXRInterface::_load_action_map() {
if (action_map.is_valid()) {
HashMap<Ref<OpenXRAction>, Action *> xr_actions;
- Array action_sets = action_map->get_action_sets();
- for (int i = 0; i < action_sets.size(); i++) {
+ Array action_set_array = action_map->get_action_sets();
+ for (int i = 0; i < action_set_array.size(); i++) {
// Create our action set
- Ref<OpenXRActionSet> xr_action_set = action_sets[i];
+ Ref<OpenXRActionSet> xr_action_set = action_set_array[i];
ActionSet *action_set = create_action_set(xr_action_set->get_name(), xr_action_set->get_localized_name(), xr_action_set->get_priority());
if (!action_set) {
continue;
@@ -147,32 +154,33 @@ void OpenXRInterface::_load_action_map() {
Ref<OpenXRAction> xr_action = actions[j];
PackedStringArray toplevel_paths = xr_action->get_toplevel_paths();
- Vector<Tracker *> trackers;
+ Vector<Tracker *> trackers_for_action;
for (int k = 0; k < toplevel_paths.size(); k++) {
- Tracker *tracker = find_tracker(toplevel_paths[k], true);
- if (tracker) {
- trackers.push_back(tracker);
+ // Only check for our tracker if our path is supported.
+ if (openxr_api->is_path_supported(toplevel_paths[k])) {
+ Tracker *tracker = find_tracker(toplevel_paths[k], true);
+ if (tracker) {
+ trackers_for_action.push_back(tracker);
+ }
}
}
- Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers);
- if (action) {
- // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
- for (int t = 0; t < trackers.size(); t++) {
- link_action_to_tracker(trackers[t], action);
+ // Only add our action if we have atleast one valid toplevel path
+ if (trackers_for_action.size() > 0) {
+ Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), trackers_for_action);
+ if (action) {
+ // add this to our map for creating our interaction profiles
+ xr_actions[xr_action] = action;
}
-
- // add this to our map for creating our interaction profiles
- xr_actions[xr_action] = action;
}
}
}
// now do our suggestions
- Array interaction_profiles = action_map->get_interaction_profiles();
- for (int i = 0; i < interaction_profiles.size(); i++) {
- Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profiles[i];
+ Array interaction_profile_array = action_map->get_interaction_profiles();
+ for (int i = 0; i < interaction_profile_array.size(); i++) {
+ Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profile_array[i];
// Note, we can only have one entry per interaction profile so if it already exists we clear it out
RID ip = openxr_api->interaction_profile_create(xr_interaction_profile->get_interaction_profile_path());
@@ -202,8 +210,8 @@ void OpenXRInterface::_load_action_map() {
openxr_api->interaction_profile_suggest_bindings(ip);
// And record it in our array so we can clean it up later on
- if (interaction_profiles.has(ip)) {
- interaction_profiles.push_back(ip);
+ if (interaction_profile_array.has(ip)) {
+ interaction_profile_array.push_back(ip);
}
}
}
@@ -282,6 +290,13 @@ OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set,
action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, tracker_rids);
p_action_set->actions.push_back(action);
+ // we link our actions back to our trackers so we know which actions to check when we're processing our trackers
+ for (int i = 0; i < p_trackers.size(); i++) {
+ if (p_trackers[i]->actions.find(action) == -1) {
+ p_trackers[i]->actions.push_back(action);
+ }
+ }
+
return action;
}
@@ -330,6 +345,8 @@ OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_tracker_
return nullptr;
}
+ ERR_FAIL_COND_V(!openxr_api->is_path_supported(p_tracker_name), nullptr);
+
// Create our RID
RID tracker_rid = openxr_api->tracker_create(p_tracker_name);
ERR_FAIL_COND_V(tracker_rid.is_null(), nullptr);
@@ -389,12 +406,6 @@ void OpenXRInterface::tracker_profile_changed(RID p_tracker, RID p_interaction_p
}
}
-void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) {
- if (p_tracker->actions.find(p_action) == -1) {
- p_tracker->actions.push_back(p_action);
- }
-}
-
void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
ERR_FAIL_NULL(openxr_api);
ERR_FAIL_COND(p_tracker->positional_tracker.is_null());
@@ -447,9 +458,18 @@ void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
ERR_FAIL_NULL(openxr_api);
+
Action *action = find_action(p_action_name);
ERR_FAIL_NULL(action);
- Tracker *tracker = find_tracker(p_tracker_name);
+
+ // We need to map our tracker name to our OpenXR name for our inbuild names.
+ String tracker_name = p_tracker_name;
+ if (tracker_name == "left_hand") {
+ tracker_name = "/user/hand/left";
+ } else if (tracker_name == "right_hand") {
+ tracker_name = "/user/hand/right";
+ }
+ Tracker *tracker = find_tracker(tracker_name);
ERR_FAIL_NULL(tracker);
// TODO OpenXR does not support delay, so we may need to add support for that somehow...
@@ -571,6 +591,36 @@ bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
return false;
}
+float OpenXRInterface::get_display_refresh_rate() const {
+ if (openxr_api == nullptr) {
+ return 0.0;
+ } else if (!openxr_api->is_initialized()) {
+ return 0.0;
+ } else {
+ return openxr_api->get_display_refresh_rate();
+ }
+}
+
+void OpenXRInterface::set_display_refresh_rate(float p_refresh_rate) {
+ if (openxr_api == nullptr) {
+ return;
+ } else if (!openxr_api->is_initialized()) {
+ return;
+ } else {
+ openxr_api->set_display_refresh_rate(p_refresh_rate);
+ }
+}
+
+Array OpenXRInterface::get_available_display_refresh_rates() const {
+ if (openxr_api == nullptr) {
+ return Array();
+ } else if (!openxr_api->is_initialized()) {
+ return Array();
+ } else {
+ return openxr_api->get_available_display_refresh_rates();
+ }
+}
+
Size2 OpenXRInterface::get_render_target_size() {
if (openxr_api == nullptr) {
return Size2();
@@ -648,6 +698,22 @@ Projection OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_as
return cm;
}
+RID OpenXRInterface::get_color_texture() {
+ if (openxr_api) {
+ return openxr_api->get_color_texture();
+ } else {
+ return RID();
+ }
+}
+
+RID OpenXRInterface::get_depth_texture() {
+ if (openxr_api) {
+ return openxr_api->get_depth_texture();
+ } else {
+ return RID();
+ }
+}
+
void OpenXRInterface::process() {
if (openxr_api) {
// do our normal process
@@ -707,6 +773,7 @@ bool OpenXRInterface::pre_draw_viewport(RID p_render_target) {
Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) {
Vector<BlitToScreen> blit_to_screen;
+#ifndef ANDROID_ENABLED
// If separate HMD we should output one eye to screen
if (p_screen_rect != Rect2()) {
BlitToScreen blit;
@@ -732,6 +799,7 @@ Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, co
blit.dst_rect = dst_rect;
blit_to_screen.push_back(blit);
}
+#endif
if (openxr_api) {
openxr_api->post_draw_viewport(p_render_target);
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 3765f18637..454612346f 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -91,7 +91,6 @@ private:
void free_actions(ActionSet *p_action_set);
Tracker *find_tracker(const String &p_tracker_name, bool p_create = false);
- void link_action_to_tracker(Tracker *p_tracker, Action *p_action);
void handle_tracker(Tracker *p_tracker);
void free_trackers();
@@ -120,12 +119,19 @@ public:
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
+ float get_display_refresh_rate() const;
+ void set_display_refresh_rate(float p_refresh_rate);
+ Array get_available_display_refresh_rates() const;
+
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
+ virtual RID get_color_texture() override;
+ virtual RID get_depth_texture() override;
+
virtual void process() override;
virtual void pre_render() override;
bool pre_draw_viewport(RID p_render_target) override;
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
index 5c79890830..1b5e0451dc 100644
--- a/modules/openxr/util.h
+++ b/modules/openxr/util.h
@@ -53,58 +53,58 @@
#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(openxr_api, name)
#define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name)
-#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1); \
+#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1); \
}
-#define EXT_PROTO_XRRESULT_FUNC2(func_name, arg1_type, arg1, arg2_type, arg2) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1, arg2); \
+#define EXT_PROTO_XRRESULT_FUNC2(func_name, arg1_type, arg1, arg2_type, arg2) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1, UNPACK arg2_type p_##arg2) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1, p_##arg2); \
}
-#define EXT_PROTO_XRRESULT_FUNC3(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1, arg2, arg3); \
+#define EXT_PROTO_XRRESULT_FUNC3(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1, UNPACK arg2_type p_##arg2, UNPACK arg3_type p_##arg3) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1, p_##arg2, p_##arg3); \
}
-#define EXT_PROTO_XRRESULT_FUNC4(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1, arg2, arg3, arg4); \
+#define EXT_PROTO_XRRESULT_FUNC4(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1, UNPACK arg2_type p_##arg2, UNPACK arg3_type p_##arg3, UNPACK arg4_type p_##arg4) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1, p_##arg2, p_##arg3, p_##arg4); \
}
-#define EXT_PROTO_XRRESULT_FUNC5(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5); \
+#define EXT_PROTO_XRRESULT_FUNC5(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1, UNPACK arg2_type p_##arg2, UNPACK arg3_type p_##arg3, UNPACK arg4_type p_##arg4, UNPACK arg5_type p_##arg5) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1, p_##arg2, p_##arg3, p_##arg4, p_##arg5); \
}
-#define EXT_PROTO_XRRESULT_FUNC6(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5, arg6_type, arg6) \
- PFN_##func_name func_name##_ptr = nullptr; \
- XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type arg1, UNPACK arg2_type arg2, UNPACK arg3_type arg3, UNPACK arg4_type arg4, UNPACK arg5_type arg5, UNPACK arg6_type arg6) const { \
- if (!func_name##_ptr) { \
- return XR_ERROR_HANDLE_INVALID; \
- } \
- return (*func_name##_ptr)(arg1, arg2, arg3, arg4, arg5, arg6); \
+#define EXT_PROTO_XRRESULT_FUNC6(func_name, arg1_type, arg1, arg2_type, arg2, arg3_type, arg3, arg4_type, arg4, arg5_type, arg5, arg6_type, arg6) \
+ PFN_##func_name func_name##_ptr = nullptr; \
+ XRAPI_ATTR XrResult XRAPI_CALL func_name(UNPACK arg1_type p_##arg1, UNPACK arg2_type p_##arg2, UNPACK arg3_type p_##arg3, UNPACK arg4_type p_##arg4, UNPACK arg5_type p_##arg5, UNPACK arg6_type p_##arg6) const { \
+ if (!func_name##_ptr) { \
+ return XR_ERROR_HANDLE_INVALID; \
+ } \
+ return (*func_name##_ptr)(p_##arg1, p_##arg2, p_##arg3, p_##arg4, p_##arg5, p_##arg6); \
}
#endif // UTIL_H
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 56404f796c..43dc3a65df 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -4,7 +4,7 @@
Class for searching text for patterns using regular expressions.
</brief_description>
<description>
- A regular expression (or regex) is a compact language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For instance, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet.
+ A regular expression (or regex) is a compact language that can be used to recognise strings that follow a specific pattern, such as URLs, email addresses, complete sentences, etc. For example, a regex of [code]ab[0-9][/code] would find any string that is [code]ab[/code] followed by any number from [code]0[/code] to [code]9[/code]. For a more in-depth look, you can easily find various tutorials and detailed explanations on the Internet.
To begin, the RegEx object needs to be compiled with the search pattern using [method compile] before it can be used.
[codeblock]
var regex = RegEx.new()
@@ -99,7 +99,8 @@
<param index="1" name="offset" type="int" default="0" />
<param index="2" name="end" type="int" default="-1" />
<description>
- Searches the text for the compiled pattern. Returns a [RegExMatch] container of the first matching result if found, otherwise [code]null[/code]. The region to search within can be specified without modifying where the start and end anchor would be.
+ Searches the text for the compiled pattern. Returns a [RegExMatch] container of the first matching result if found, otherwise [code]null[/code].
+ The region to search within can be specified with [param offset] and [param end]. This is useful when searching for another match in the same [param subject] by calling this method again after a previous success. Note that setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [param offset], and the character before [param offset] will be checked for the word boundary [code]\b[/code].
</description>
</method>
<method name="search_all" qualifiers="const">
@@ -108,7 +109,8 @@
<param index="1" name="offset" type="int" default="0" />
<param index="2" name="end" type="int" default="-1" />
<description>
- Searches the text for the compiled pattern. Returns an array of [RegExMatch] containers for each non-overlapping result. If no results were found, an empty array is returned instead. The region to search within can be specified without modifying where the start and end anchor would be.
+ Searches the text for the compiled pattern. Returns an array of [RegExMatch] containers for each non-overlapping result. If no results were found, an empty array is returned instead.
+ The region to search within can be specified with [param offset] and [param end]. This is useful when searching for another match in the same [param subject] by calling this method again after a previous success. Note that setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [param offset], and the character before [param offset] will be checked for the word boundary [code]\b[/code].
</description>
</method>
<method name="sub" qualifiers="const">
@@ -119,7 +121,8 @@
<param index="3" name="offset" type="int" default="0" />
<param index="4" name="end" type="int" default="-1" />
<description>
- Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default, only the first instance is replaced, but it can be changed for all instances (global replacement). The region to search within can be specified without modifying where the start and end anchor would be.
+ Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default, only the first instance is replaced, but it can be changed for all instances (global replacement).
+ The region to search within can be specified with [param offset] and [param end]. This is useful when searching for another match in the same [param subject] by calling this method again after a previous success. Note that setting these parameters differs from passing over a shortened string. For example, the start anchor [code]^[/code] is not affected by [param offset], and the character before [param offset] will be checked for the word boundary [code]\b[/code].
</description>
</method>
</methods>
diff --git a/modules/squish/image_decompress_squish.cpp b/modules/squish/image_decompress_squish.cpp
index 3a810e5259..2abd9a0c69 100644
--- a/modules/squish/image_decompress_squish.cpp
+++ b/modules/squish/image_decompress_squish.cpp
@@ -70,7 +70,7 @@ void image_decompress_squish(Image *p_image) {
h >>= 1;
}
- p_image->create(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
+ p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
if (p_image->get_format() == Image::FORMAT_DXT5_RA_AS_RG) {
p_image->convert_ra_rgba8_to_rg();
diff --git a/modules/svg/SCsub b/modules/svg/SCsub
index 93262f4f87..ae3e1bdedb 100644
--- a/modules/svg/SCsub
+++ b/modules/svg/SCsub
@@ -11,6 +11,16 @@ thirdparty_obj = []
thirdparty_dir = "#thirdparty/thorvg/"
thirdparty_sources = [
+ "src/lib/sw_engine/tvgSwFill.cpp",
+ "src/lib/sw_engine/tvgSwImage.cpp",
+ "src/lib/sw_engine/tvgSwMath.cpp",
+ "src/lib/sw_engine/tvgSwMemPool.cpp",
+ "src/lib/sw_engine/tvgSwRaster.cpp",
+ "src/lib/sw_engine/tvgSwRenderer.cpp",
+ "src/lib/sw_engine/tvgSwRle.cpp",
+ "src/lib/sw_engine/tvgSwShape.cpp",
+ "src/lib/sw_engine/tvgSwStroke.cpp",
+ "src/lib/tvgAccessor.cpp",
"src/lib/tvgBezier.cpp",
"src/lib/tvgCanvas.cpp",
"src/lib/tvgFill.cpp",
@@ -28,27 +38,18 @@ thirdparty_sources = [
"src/lib/tvgShape.cpp",
"src/lib/tvgSwCanvas.cpp",
"src/lib/tvgTaskScheduler.cpp",
+ "src/loaders/external_png/tvgPngLoader.cpp",
+ "src/loaders/jpg/tvgJpgd.cpp",
+ "src/loaders/jpg/tvgJpgLoader.cpp",
"src/loaders/raw/tvgRawLoader.cpp",
- "src/loaders/svg/tvgXmlParser.cpp",
- "src/loaders/svg/tvgSvgUtil.cpp",
- "src/loaders/svg/tvgSvgSceneBuilder.cpp",
- "src/loaders/svg/tvgSvgPath.cpp",
- "src/loaders/svg/tvgSvgLoader.cpp",
"src/loaders/svg/tvgSvgCssStyle.cpp",
+ "src/loaders/svg/tvgSvgLoader.cpp",
+ "src/loaders/svg/tvgSvgPath.cpp",
+ "src/loaders/svg/tvgSvgSceneBuilder.cpp",
+ "src/loaders/svg/tvgSvgUtil.cpp",
+ "src/loaders/svg/tvgXmlParser.cpp",
"src/loaders/tvg/tvgTvgBinInterpreter.cpp",
"src/loaders/tvg/tvgTvgLoader.cpp",
- "src/loaders/jpg/tvgJpgLoader.cpp",
- "src/loaders/jpg/tvgJpgd.cpp",
- "src/loaders/external_png/tvgPngLoader.cpp",
- "src/lib/sw_engine/tvgSwFill.cpp",
- "src/lib/sw_engine/tvgSwImage.cpp",
- "src/lib/sw_engine/tvgSwMath.cpp",
- "src/lib/sw_engine/tvgSwMemPool.cpp",
- "src/lib/sw_engine/tvgSwRaster.cpp",
- "src/lib/sw_engine/tvgSwRenderer.cpp",
- "src/lib/sw_engine/tvgSwRle.cpp",
- "src/lib/sw_engine/tvgSwShape.cpp",
- "src/lib/sw_engine/tvgSwStroke.cpp",
"src/savers/tvg/tvgTvgSaver.cpp",
]
@@ -62,14 +63,18 @@ env_thirdparty.Prepend(
CPPPATH=[
thirdparty_dir + "src/lib",
thirdparty_dir + "src/lib/sw_engine",
+ thirdparty_dir + "src/loaders/external_png",
+ thirdparty_dir + "src/loaders/jpg",
thirdparty_dir + "src/loaders/raw",
thirdparty_dir + "src/loaders/svg",
- thirdparty_dir + "src/loaders/jpg",
- thirdparty_dir + "src/loaders/png",
thirdparty_dir + "src/loaders/tvg",
thirdparty_dir + "src/savers/tvg",
]
)
+# Also requires libpng headers
+if env["builtin_libpng"]:
+ env_thirdparty.Prepend(CPPPATH=["#thirdparty/libpng"])
+
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.modules_sources += thirdparty_obj
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index f43f2784c7..b8c412a201 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -135,7 +135,7 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin
res = sw_canvas->clear(true);
memfree(buffer);
- p_image->create(width, height, false, Image::FORMAT_RGBA8, image);
+ p_image->set_data(width, height, false, Image::FORMAT_RGBA8, image);
}
void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 2261342467..bd208a8429 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -131,9 +131,14 @@ if env["builtin_harfbuzz"]:
env_harfbuzz.Append(
CCFLAGS=[
"-DHAVE_FREETYPE",
- "-DHAVE_GRAPHITE2",
]
)
+ if env["graphite"]:
+ env_harfbuzz.Append(
+ CCFLAGS=[
+ "-DHAVE_GRAPHITE2",
+ ]
+ )
if env["builtin_freetype"]:
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/freetype/include"])
if env["builtin_graphite"] and env["graphite"]:
@@ -446,7 +451,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt71l.dat"
+ icu_data_name = "icudt72l.dat"
if env.editor_build:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 7ca8859ee6..65b41e46ce 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -68,7 +68,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
lib = env_msdfgen.Library(
- f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_msdfgen_sources,
)
env.Append(LIBS=[lib])
@@ -199,7 +199,7 @@ if env["freetype_enabled"]:
env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"])
lib = env_freetype.Library(
- f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_freetype_sources,
)
env.Append(LIBS=[lib])
@@ -321,7 +321,7 @@ if env["freetype_enabled"]:
env.Append(CPPPATH=["../../../thirdparty/harfbuzz/src"])
lib = env_harfbuzz.Library(
- f'harfbuzz_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'harfbuzz_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_harfbuzz_sources,
)
env.Prepend(LIBS=[lib])
@@ -381,7 +381,7 @@ if env["graphite_enabled"] and env["freetype_enabled"]:
)
lib = env_graphite.Library(
- f'graphite_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'graphite_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_graphite_sources,
)
env.Append(LIBS=[lib])
@@ -597,7 +597,7 @@ thirdparty_icu_sources = [
]
thirdparty_icu_sources = [thirdparty_icu_dir + file for file in thirdparty_icu_sources]
-icu_data_name = "icudt71l.dat"
+icu_data_name = "icudt72l.dat"
if env["static_icu_data"]:
env_icu.Depends("../../../thirdparty/icu4c/icudata.gen.h", "../../../thirdparty/icu4c/" + icu_data_name)
@@ -640,9 +640,7 @@ env.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/ic
if env["platform"] == "windows":
env.Append(LIBS=["advapi32"])
-lib = env_icu.Library(
- f'icu_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources
-)
+lib = env_icu.Library(f'icu_builtin{env["suffix"]}{env["LIBSUFFIX"]}', thirdparty_icu_sources)
env.Append(LIBS=[lib])
env.Append(CPPDEFINES=["GDEXTENSION"])
@@ -662,7 +660,7 @@ if env["platform"] == "macos":
)
else:
library = env.SharedLibrary(
- f'./bin/libtextserver_advanced.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}',
+ f'./bin/libtextserver_advanced{env["suffix"]}{env["SHLIBSUFFIX"]}',
source=sources,
)
diff --git a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension
index 11ed271ae9..c12fcfdfdf 100644
--- a/modules/text_server_adv/gdextension_build/text_server_adv.gdextension
+++ b/modules/text_server_adv/gdextension_build/text_server_adv.gdextension
@@ -4,9 +4,21 @@ entry_symbol = "textserver_advanced_init"
[libraries]
-linux.64.debug = "bin/libtextserver_advanced.linux.debug.64.so"
-linux.64.release = "bin/libtextserver_advanced.linux.release.64.so"
-windows.64.debug = "bin/libtextserver_advanced.windows.debug.64.dll"
-windows.64.release = "bin/libtextserver_advanced.windows.release.64.dll"
-macos.debug = "bin/libtextserver_advanced.macos.debug.framework"
-macos.release = "bin/libtextserver_advanced.macos.release.framework"
+linux.x86_64.debug = "bin/libtextserver_advanced.linux.template_debug.x86_64.so"
+linux.x86_64.release = "bin/libtextserver_advanced.linux.template_release.x86_64.so"
+linux.x86_32.debug = "bin/libtextserver_advanced.linux.template_debug.x86_32.so"
+linux.x86_32.release = "bin/libtextserver_advanced.linux.template_release.x86_32.so"
+linux.arm64.debug = "bin/libtextserver_advanced.linux.template_debug.arm64.so"
+linux.arm64.release = "bin/libtextserver_advanced.linux.template_release.arm64.so"
+linux.rv64.debug = "bin/libtextserver_advanced.linux.template_debug.rv64.so"
+linux.rv64.release = "bin/libtextserver_advanced.linux.template_release.rv64.so"
+
+windows.x86_64.debug = "bin/libtextserver_advanced.windows.template_debug.x86_64.dll"
+windows.x86_64.release = "bin/libtextserver_advanced.windows.template_release.x86_64.dll"
+windows.x86_32.debug = "bin/libtextserver_advanced.windows.template_debug.x86_32.dll"
+windows.x86_32.release = "bin/libtextserver_advanced.windows.template_release.x86_32.dll"
+windows.arm64.debug = "bin/libtextserver_advanced.windows.template_debug.arm64.dll"
+windows.arm64.release = "bin/libtextserver_advanced.windows.template_release.arm64.dll"
+
+macos.debug = "bin/libtextserver_advanced.macos.template_debug.framework"
+macos.release = "bin/libtextserver_advanced.macos.template_release.framework"
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index d0301eeae3..155da3c67b 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -788,58 +788,27 @@ String TextServerAdvanced::_tag_to_name(int64_t p_tag) const {
_FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_texture_pos_for_glyph(FontForSizeAdvanced *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
FontTexturePosition ret;
- ret.index = -1;
int mw = p_width;
int mh = p_height;
- for (int i = 0; i < p_data->textures.size(); i++) {
- const FontTexture &ct = p_data->textures[i];
-
- if (p_image_format != ct.format) {
+ ShelfPackTexture *ct = p_data->textures.ptrw();
+ for (int32_t i = 0; i < p_data->textures.size(); i++) {
+ if (p_image_format != ct[i].format) {
continue;
}
-
- if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
+ if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
continue;
}
- if (ct.offsets.size() < ct.texture_w) {
- continue;
- }
-
- ret.y = 0x7fffffff;
- ret.x = 0;
-
- for (int j = 0; j < ct.texture_w - mw; j++) {
- int max_y = 0;
-
- for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
- if (y > max_y) {
- max_y = y;
- }
- }
-
- if (max_y < ret.y) {
- ret.y = max_y;
- ret.x = j;
- }
- }
-
- if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
- continue; // Fail, could not fit it here.
+ ret = ct[i].pack_rect(i, mh, mw);
+ if (ret.index != -1) {
+ break;
}
-
- ret.index = i;
- break;
}
if (ret.index == -1) {
// Could not find texture to fit, create one.
- ret.x = 0;
- ret.y = 0;
-
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
#ifdef GDEXTENSION
@@ -867,12 +836,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
#endif
}
- FontTexture tex;
- tex.texture_w = texsize;
- tex.texture_h = texsize;
+ ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
tex.format = p_image_format;
tex.imgdata.resize(texsize * texsize * p_color_size);
-
{
// Zero texture.
uint8_t *w = tex.imgdata.ptrw();
@@ -895,14 +861,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ERR_FAIL_V(ret);
}
}
- tex.offsets.resize(texsize);
- int32_t *offw = tex.offsets.ptrw();
- for (int i = 0; i < texsize; i++) { // Zero offsets.
- offw[i] = 0;
- }
-
p_data->textures.push_back(tex);
- ret.index = p_data->textures.size() - 1;
+
+ int32_t idx = p_data->textures.size() - 1;
+ ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
}
return ret;
@@ -1036,7 +998,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
- FontTexture &tex = p_data->textures.write[tex_pos.index];
+ ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
edgeColoringSimple(shape, 3.0); // Max. angle.
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
@@ -1079,12 +1041,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
tex.dirty = true;
- // Update height array.
- int32_t *offw = tex.offsets.ptrw();
- for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- offw[k] = tex_pos.y + mh;
- }
-
chr.texture_idx = tex_pos.index;
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
@@ -1132,8 +1088,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
// Fit character in char texture.
-
- FontTexture &tex = p_data->textures.write[tex_pos.index];
+ ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
{
uint8_t *wr = tex.imgdata.ptrw();
@@ -1198,12 +1153,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
tex.dirty = true;
- // Update height array.
- int32_t *offw = tex.offsets.ptrw();
- for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- offw[k] = tex_pos.y + mh;
- }
-
FontGlyph chr;
chr.advance = advance * p_data->scale / p_data->oversampling;
chr.texture_idx = tex_pos.index;
@@ -1393,7 +1342,10 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -1422,6 +1374,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -1835,6 +1788,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
} else {
@@ -2487,16 +2441,14 @@ void TextServerAdvanced::_font_set_texture_image(const RID &p_font_rid, const Ve
fd->cache[size]->textures.resize(p_texture_index + 1);
}
- FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
tex.imgdata = p_image->get_data();
tex.texture_w = p_image->get_width();
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -2514,15 +2466,12 @@ Ref<Image> TextServerAdvanced::_font_get_texture_image(const RID &p_font_rid, co
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
- const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
-
- return img;
+ const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
+ return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
}
-void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
+void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
+ ERR_FAIL_COND(p_offsets.size() % 4 != 0);
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -2534,8 +2483,11 @@ void TextServerAdvanced::_font_set_texture_offsets(const RID &p_font_rid, const
fd->cache[size]->textures.resize(p_texture_index + 1);
}
- FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
- tex.offsets = p_offset;
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ tex.shelves.clear();
+ for (int32_t i = 0; i < p_offsets.size(); i += 4) {
+ tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
+ }
}
PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
@@ -2547,8 +2499,20 @@ PackedInt32Array TextServerAdvanced::_font_get_texture_offsets(const RID &p_font
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
- const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
- return tex.offsets;
+ const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
+ PackedInt32Array ret;
+ ret.resize(tex.shelves.size() * 4);
+
+ int32_t *wr = ret.ptrw();
+ int32_t i = 0;
+ for (const Shelf &E : tex.shelves) {
+ wr[i * 4] = E.x;
+ wr[i * 4 + 1] = E.y;
+ wr[i * 4 + 2] = E.w;
+ wr[i * 4 + 3] = E.h;
+ i++;
+ }
+ return ret;
}
PackedInt32Array TextServerAdvanced::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
@@ -2614,7 +2578,7 @@ Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2631,9 +2595,10 @@ Vector2 TextServerAdvanced::_font_get_glyph_advance(const RID &p_font_rid, int64
ea.x = fd->embolden * double(size.x) / 64.0;
}
+ double scale = _font_get_scale(p_font_rid, p_size);
if (fd->msdf) {
return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ } else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE))) {
return (gl[p_glyph | mod].advance + ea).round();
} else {
return gl[p_glyph | mod].advance + ea;
@@ -2666,7 +2631,7 @@ Vector2 TextServerAdvanced::_font_get_glyph_offset(const RID &p_font_rid, const
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2711,7 +2676,7 @@ Vector2 TextServerAdvanced::_font_get_glyph_size(const RID &p_font_rid, const Ve
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2756,7 +2721,7 @@ Rect2 TextServerAdvanced::_font_get_glyph_uv_rect(const RID &p_font_rid, const V
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2796,7 +2761,7 @@ int64_t TextServerAdvanced::_font_get_glyph_texture_idx(const RID &p_font_rid, c
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2836,7 +2801,7 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2852,10 +2817,8 @@ RID TextServerAdvanced::_font_get_glyph_texture_rid(const RID &p_font_rid, const
if (RenderingServer::get_singleton() != nullptr) {
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -2884,7 +2847,7 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -2900,10 +2863,8 @@ Size2 TextServerAdvanced::_font_get_glyph_texture_size(const RID &p_font_rid, co
if (RenderingServer::get_singleton() != nullptr) {
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -3213,7 +3174,7 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
if (!fd->msdf && fd->cache[size]->face) {
// LCD layout, bits 24, 25, 26
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
lcd_aa = true;
index = index | (layout << 24);
@@ -3247,10 +3208,8 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -3268,13 +3227,15 @@ void TextServerAdvanced::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
Size2 csize = gl.rect.size * (double)p_size / (double)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
+ double scale = _font_get_scale(p_font_rid, p_size);
Point2 cpos = p_pos;
- cpos.y = Math::floor(cpos.y);
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.125));
+ cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.25));
- } else {
+ cpos.x = cpos.x + 0.25;
+ }
+ if (scale == 1.0) {
+ cpos.y = Math::floor(cpos.y);
cpos.x = Math::floor(cpos.x);
}
cpos += gl.rect.position;
@@ -3305,7 +3266,7 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
if (!fd->msdf && fd->cache[size]->face) {
// LCD layout, bits 24, 25, 26
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
lcd_aa = true;
index = index | (layout << 24);
@@ -3339,10 +3300,8 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -3361,12 +3320,14 @@ void TextServerAdvanced::_font_draw_glyph_outline(const RID &p_font_rid, const R
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2 cpos = p_pos;
- cpos.y = Math::floor(cpos.y);
+ double scale = _font_get_scale(p_font_rid, p_size);
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.125));
+ cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.25));
- } else {
+ cpos.x = cpos.x + 0.25;
+ }
+ if (scale == 1.0) {
+ cpos.y = Math::floor(cpos.y);
cpos.x = Math::floor(cpos.x);
}
cpos += gl.rect.position;
@@ -4630,6 +4591,7 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
if (!sd->break_ops_valid) {
sd->breaks.clear();
+ sd->break_inserts = 0;
UErrorCode err = U_ZERO_ERROR;
int i = 0;
while (i < sd->spans.size()) {
@@ -4658,6 +4620,12 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
sd->breaks[pos] = true;
} else if ((ubrk_getRuleStatus(bi) >= UBRK_LINE_SOFT) && (ubrk_getRuleStatus(bi) < UBRK_LINE_SOFT_LIMIT)) {
sd->breaks[pos] = false;
+
+ int pos_p = pos - 1 - sd->start;
+ char32_t c = sd->text[pos_p];
+ if (pos - sd->start != sd->end && !is_whitespace(c) && (c != 0xfffc)) {
+ sd->break_inserts++;
+ }
}
}
}
@@ -4667,60 +4635,83 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
sd->break_ops_valid = true;
}
+ Vector<Glyph> glyphs_new;
+
+ bool rewrite = false;
+ int sd_shift = 0;
+ int sd_size = sd->glyphs.size();
+ Glyph *sd_glyphs = sd->glyphs.ptrw();
+ Glyph *sd_glyphs_new = nullptr;
+
+ if (sd->break_inserts > 0) {
+ glyphs_new.resize(sd->glyphs.size() + sd->break_inserts);
+ sd_glyphs_new = glyphs_new.ptrw();
+ rewrite = true;
+ } else {
+ sd_glyphs_new = sd_glyphs;
+ }
+
sd->sort_valid = false;
sd->glyphs_logical.clear();
- int sd_size = sd->glyphs.size();
const char32_t *ch = sd->text.ptr();
- Glyph *sd_glyphs = sd->glyphs.ptrw();
int c_punct_size = sd->custom_punct.length();
const char32_t *c_punct = sd->custom_punct.ptr();
for (int i = 0; i < sd_size; i++) {
+ if (rewrite) {
+ for (int j = 0; j < sd_glyphs[i].count; j++) {
+ sd_glyphs_new[sd_shift + i + j] = sd_glyphs[i + j];
+ }
+ }
if (sd_glyphs[i].count > 0) {
char32_t c = ch[sd_glyphs[i].start - sd->start];
if (c == 0xfffc) {
+ i += (sd_glyphs[i].count - 1);
continue;
}
if (c == 0x0009 || c == 0x000b) {
- sd_glyphs[i].flags |= GRAPHEME_IS_TAB;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_TAB;
}
if (is_whitespace(c)) {
- sd_glyphs[i].flags |= GRAPHEME_IS_SPACE;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_SPACE;
}
if (c_punct_size == 0) {
if (u_ispunct(c) && c != 0x005f) {
- sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;
}
} else {
for (int j = 0; j < c_punct_size; j++) {
if (c_punct[j] == c) {
- sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_PUNCTUATION;
break;
}
}
}
if (is_underscore(c)) {
- sd_glyphs[i].flags |= GRAPHEME_IS_UNDERSCORE;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_UNDERSCORE;
}
if (sd->breaks.has(sd_glyphs[i].end)) {
if (sd->breaks[sd_glyphs[i].end] && (is_linebreak(c))) {
- sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_HARD;
} else if (is_whitespace(c)) {
- sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
+ sd_glyphs_new[sd_shift + i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
int count = sd_glyphs[i].count;
// Do not add extra space at the end of the line.
if (sd_glyphs[i].end == sd->end) {
+ i += (sd_glyphs[i].count - 1);
continue;
}
// Do not add extra space after existing space.
if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
if ((i + count < sd_size - 1) && ((sd_glyphs[i + count].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {
+ i += (sd_glyphs[i].count - 1);
continue;
}
} else {
- if ((i > 0) && ((sd_glyphs[i - 1].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT))) {
+ if ((sd_glyphs[i].flags & (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) == (GRAPHEME_IS_SPACE | GRAPHEME_IS_BREAK_SOFT)) {
+ i += (sd_glyphs[i].count - 1);
continue;
}
}
@@ -4733,22 +4724,25 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) {
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL | GRAPHEME_IS_SPACE;
if (sd_glyphs[i].flags & GRAPHEME_IS_RTL) {
gl.flags |= GRAPHEME_IS_RTL;
- sd->glyphs.insert(i, gl); // Insert before.
+ for (int j = sd_glyphs[i].count - 1; j >= 0; j--) {
+ sd_glyphs_new[sd_shift + i + j + 1] = sd_glyphs_new[sd_shift + i + j];
+ }
+ sd_glyphs_new[sd_shift + i] = gl;
} else {
- sd->glyphs.insert(i + count, gl); // Insert after.
+ sd_glyphs_new[sd_shift + i + count] = gl;
}
- i += count;
-
- // Update write pointer and size.
- sd_size = sd->glyphs.size();
- sd_glyphs = sd->glyphs.ptrw();
- continue;
+ sd_shift++;
+ ERR_FAIL_COND_V_MSG(sd_shift > sd->break_inserts, false, "Invalid break insert count!");
}
}
-
i += (sd_glyphs[i].count - 1);
}
}
+ ERR_FAIL_COND_V_MSG(sd_shift != sd->break_inserts, false, "Invalid break insert count!");
+
+ if (sd->break_inserts > 0) {
+ sd->glyphs = glyphs_new;
+ }
sd->line_breaks_valid = true;
@@ -4984,7 +4978,8 @@ bool TextServerAdvanced::_shaped_text_update_justification_ops(const RID &p_shap
Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size) {
hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
- bool subpos = (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
+ double scale = _font_get_scale(p_font, p_font_size);
+ bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(p_font) == SUBPIXEL_POSITIONING_AUTO && p_font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -5010,25 +5005,24 @@ Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char
gl.font_size = p_font_size;
if (glyph_count > 0) {
- double scale = _font_get_scale(p_font, p_font_size);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
- gl.advance = glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);
+ gl.advance = (double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size);
} else {
- gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));
+ gl.advance = Math::round((double)glyph_pos[0].x_advance / (64.0 / scale) + _get_extra_advance(p_font, p_font_size));
}
} else {
- gl.advance = -Math::round(glyph_pos[0].y_advance / (64.0 / scale));
+ gl.advance = -Math::round((double)glyph_pos[0].y_advance / (64.0 / scale));
}
gl.count = 1;
gl.index = glyph_info[0].codepoint;
if (subpos) {
- gl.x_off = glyph_pos[0].x_offset / (64.0 / scale);
+ gl.x_off = (double)glyph_pos[0].x_offset / (64.0 / scale);
} else {
- gl.x_off = Math::round(glyph_pos[0].x_offset / (64.0 / scale));
+ gl.x_off = Math::round((double)glyph_pos[0].x_offset / (64.0 / scale));
}
- gl.y_off = -Math::round(glyph_pos[0].y_offset / (64.0 / scale));
+ gl.y_off = -Math::round((double)glyph_pos[0].y_offset / (64.0 / scale));
if ((glyph_info[0].codepoint != 0) || !u_isgraph(p_char)) {
gl.flags |= GRAPHEME_IS_VALID;
@@ -5078,6 +5072,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
} else {
gl.advance = get_hex_code_box_size(fs, gl.index).y;
+ gl.y_off = get_hex_code_box_size(fs, gl.index).y;
+ gl.x_off = -Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5);
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5));
}
@@ -5101,7 +5097,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
double sp_gl = p_sd->extra_spacing[SPACING_GLYPH];
bool last_run = (p_sd->end == p_end);
double ea = _get_extra_advance(f, fs);
- bool subpos = (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
+ bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(f) == SUBPIXEL_POSITIONING_AUTO && fs <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
ERR_FAIL_COND(hb_font == nullptr);
hb_buffer_clear_contents(p_sd->hb_buffer);
@@ -5140,7 +5136,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -5202,19 +5198,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
_ensure_glyph(fd, fss, gl.index | mod);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
- gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea;
+ gl.advance = (double)glyph_pos[i].x_advance / (64.0 / scale) + ea;
} else {
- gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale) + ea);
+ gl.advance = Math::round((double)glyph_pos[i].x_advance / (64.0 / scale) + ea);
}
} else {
- gl.advance = -Math::round(glyph_pos[i].y_advance / (64.0 / scale));
+ gl.advance = -Math::round((double)glyph_pos[i].y_advance / (64.0 / scale));
}
if (subpos) {
- gl.x_off = glyph_pos[i].x_offset / (64.0 / scale);
+ gl.x_off = (double)glyph_pos[i].x_offset / (64.0 / scale);
} else {
- gl.x_off = Math::round(glyph_pos[i].x_offset / (64.0 / scale));
+ gl.x_off = Math::round((double)glyph_pos[i].x_offset / (64.0 / scale));
}
- gl.y_off = -Math::round(glyph_pos[i].y_offset / (64.0 / scale));
+ gl.y_off = -Math::round((double)glyph_pos[i].y_offset / (64.0 / scale));
}
if (!last_run || i < glyph_count - 1) {
// Do not add extra spacing to the last glyph of the string.
@@ -5401,7 +5397,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
int32_t script_run_end = MIN(sd->script_iter->script_ranges[j].end, bidi_run_end);
char scr_buffer[5] = { 0, 0, 0, 0, 0 };
hb_tag_to_string(hb_script_to_iso15924_tag(sd->script_iter->script_ranges[j].script), scr_buffer);
- String script = String(scr_buffer);
+ String script_code = String(scr_buffer);
int spn_from = (is_rtl) ? 0 : sd->spans.size() - 1;
int spn_to = (is_rtl) ? sd->spans.size() : -1;
@@ -5441,7 +5437,7 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
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_script_supported(span.fonts[l], script_code)) {
if (_font_is_language_supported(span.fonts[l], span.language)) {
fonts.push_back(sd->spans[k].fonts[l]);
} else {
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index fb5075e835..33fa1e117e 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -168,20 +168,86 @@ class TextServerAdvanced : public TextServerExtension {
const int rect_range = 1;
- struct FontTexture {
+ struct FontTexturePosition {
+ int32_t index = -1;
+ int32_t x = 0;
+ int32_t y = 0;
+
+ FontTexturePosition() {}
+ FontTexturePosition(int32_t p_id, int32_t p_x, int32_t p_y) :
+ index(p_id), x(p_x), y(p_y) {}
+ };
+
+ struct Shelf {
+ int32_t x = 0;
+ int32_t y = 0;
+ int32_t w = 0;
+ int32_t h = 0;
+
+ FontTexturePosition alloc_shelf(int32_t p_id, int32_t p_w, int32_t p_h) {
+ if (p_w > w || p_h > h) {
+ return FontTexturePosition(-1, 0, 0);
+ }
+ int32_t xx = x;
+ x += p_w;
+ w -= p_w;
+ return FontTexturePosition(p_id, xx, y);
+ }
+
+ Shelf() {}
+ Shelf(int32_t p_x, int32_t p_y, int32_t p_w, int32_t p_h) :
+ x(p_x), y(p_y), w(p_w), h(p_h) {}
+ };
+
+ struct ShelfPackTexture {
+ int32_t texture_w = 1024;
+ int32_t texture_h = 1024;
+
Image::Format format;
PackedByteArray imgdata;
- int texture_w = 0;
- int texture_h = 0;
- PackedInt32Array offsets;
Ref<ImageTexture> texture;
bool dirty = true;
- };
- struct FontTexturePosition {
- int index = 0;
- int x = 0;
- int y = 0;
+ List<Shelf> shelves;
+
+ FontTexturePosition pack_rect(int32_t p_id, int32_t p_h, int32_t p_w) {
+ int32_t y = 0;
+ int32_t waste = 0;
+ Shelf *best_shelf = nullptr;
+ int32_t best_waste = std::numeric_limits<std::int32_t>::max();
+
+ for (Shelf &E : shelves) {
+ y += E.h;
+ if (p_w > E.w) {
+ continue;
+ }
+ if (p_h == E.h) {
+ return E.alloc_shelf(p_id, p_w, p_h);
+ }
+ if (p_h > E.h) {
+ continue;
+ }
+ if (p_h < E.h) {
+ waste = (E.h - p_h) * p_w;
+ if (waste < best_waste) {
+ best_waste = waste;
+ best_shelf = &E;
+ }
+ }
+ }
+ if (best_shelf) {
+ return best_shelf->alloc_shelf(p_id, p_w, p_h);
+ }
+ if (p_h <= (texture_h - y) && p_w <= texture_w) {
+ List<Shelf>::Element *E = shelves.push_back(Shelf(0, y, texture_w, p_h));
+ return E->get().alloc_shelf(p_id, p_w, p_h);
+ }
+ return FontTexturePosition(-1, 0, 0);
+ }
+
+ ShelfPackTexture() {}
+ ShelfPackTexture(int32_t p_w, int32_t p_h) :
+ texture_w(p_w), texture_h(p_h) {}
};
struct FontGlyph {
@@ -202,7 +268,7 @@ class TextServerAdvanced : public TextServerExtension {
Vector2i size;
- Vector<FontTexture> textures;
+ Vector<ShelfPackTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
HashMap<Vector2i, Vector2> kerning_map;
hb_font_t *hb_handle = nullptr;
@@ -384,6 +450,7 @@ class TextServerAdvanced : public TextServerExtension {
HashMap<int, bool> jstops;
HashMap<int, bool> breaks;
+ int break_inserts = 0;
bool break_ops_valid = false;
bool js_ops_valid = false;
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index eae8e031bf..8ed8f61a43 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -63,7 +63,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
env.Append(CPPDEFINES=["MODULE_MSDFGEN_ENABLED"])
lib = env_msdfgen.Library(
- f'msdfgen_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'msdfgen_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_msdfgen_sources,
)
env.Append(LIBS=[lib])
@@ -194,7 +194,7 @@ if env["freetype_enabled"]:
env.Append(CPPDEFINES=["MODULE_FREETYPE_ENABLED"])
lib = env_freetype.Library(
- f'freetype_builtin.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["LIBSUFFIX"]}',
+ f'freetype_builtin{env["suffix"]}{env["LIBSUFFIX"]}',
thirdparty_freetype_sources,
)
env.Append(LIBS=[lib])
@@ -217,7 +217,7 @@ if env["platform"] == "macos":
)
else:
library = env.SharedLibrary(
- f'./bin/libtextserver_fallback.{env["platform"]}.{env["target"]}.{env["arch_suffix"]}{env["SHLIBSUFFIX"]}',
+ f'./bin/libtextserver_fallback{env["suffix"]}{env["SHLIBSUFFIX"]}',
source=sources,
)
diff --git a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
index 9236555d63..58a92e403b 100644
--- a/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
+++ b/modules/text_server_fb/gdextension_build/text_server_fb.gdextension
@@ -4,9 +4,21 @@ entry_symbol = "textserver_fallback_init"
[libraries]
-linux.64.debug = "bin/libtextserver_fallback.linux.debug.64.so"
-linux.64.release = "bin/libtextserver_fallback.linux.release.64.so"
-windows.64.debug = "bin/libtextserver_fallback.windows.debug.64.dll"
-windows.64.release = "bin/libtextserver_fallback.windows.release.64.dll"
-macos.debug = "bin/libtextserver_fallback.macos.debug.framework"
-macos.release = "bin/libtextserver_fallback.macos.release.framework"
+linux.x86_64.debug = "bin/libtextserver_fallback.linux.template_debug.x86_64.so"
+linux.x86_64.release = "bin/libtextserver_fallback.linux.template_release.x86_64.so"
+linux.x86_32.debug = "bin/libtextserver_fallback.linux.template_debug.x86_32.so"
+linux.x86_32.release = "bin/libtextserver_fallback.linux.template_release.x86_32.so"
+linux.arm64.debug = "bin/libtextserver_fallback.linux.template_debug.arm64.so"
+linux.arm64.release = "bin/libtextserver_fallback.linux.template_release.arm64.so"
+linux.rv64.debug = "bin/libtextserver_fallback.linux.template_debug.rv64.so"
+linux.rv64.release = "bin/libtextserver_fallback.linux.template_release.rv64.so"
+
+windows.x86_64.debug = "bin/libtextserver_fallback.windows.template_debug.x86_64.dll"
+windows.x86_64.release = "bin/libtextserver_fallback.windows.template_release.x86_64.dll"
+windows.x86_32.debug = "bin/libtextserver_fallback.windows.template_debug.x86_32.dll"
+windows.x86_32.release = "bin/libtextserver_fallback.windows.template_release.x86_32.dll"
+windows.arm64.debug = "bin/libtextserver_fallback.windows.template_debug.arm64.dll"
+windows.arm64.release = "bin/libtextserver_fallback.windows.template_release.arm64.dll"
+
+macos.debug = "bin/libtextserver_fallback.macos.template_debug.framework"
+macos.release = "bin/libtextserver_fallback.macos.template_release.framework"
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 518c877baa..999870b904 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -211,58 +211,27 @@ String TextServerFallback::_tag_to_name(int64_t p_tag) const {
_FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_texture_pos_for_glyph(FontForSizeFallback *p_data, int p_color_size, Image::Format p_image_format, int p_width, int p_height, bool p_msdf) const {
FontTexturePosition ret;
- ret.index = -1;
int mw = p_width;
int mh = p_height;
- for (int i = 0; i < p_data->textures.size(); i++) {
- const FontTexture &ct = p_data->textures[i];
-
- if (p_image_format != ct.format) {
+ ShelfPackTexture *ct = p_data->textures.ptrw();
+ for (int32_t i = 0; i < p_data->textures.size(); i++) {
+ if (p_image_format != ct[i].format) {
continue;
}
-
- if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
+ if (mw > ct[i].texture_w || mh > ct[i].texture_h) { // Too big for this texture.
continue;
}
- if (ct.offsets.size() < ct.texture_w) {
- continue;
+ ret = ct[i].pack_rect(i, mh, mw);
+ if (ret.index != -1) {
+ break;
}
-
- ret.y = 0x7fffffff;
- ret.x = 0;
-
- for (int j = 0; j < ct.texture_w - mw; j++) {
- int max_y = 0;
-
- for (int k = j; k < j + mw; k++) {
- int y = ct.offsets[k];
- if (y > max_y) {
- max_y = y;
- }
- }
-
- if (max_y < ret.y) {
- ret.y = max_y;
- ret.x = j;
- }
- }
-
- if (ret.y == 0x7fffffff || ret.y + mh > ct.texture_h) {
- continue; // Fail, could not fit it here.
- }
-
- ret.index = i;
- break;
}
if (ret.index == -1) {
// Could not find texture to fit, create one.
- ret.x = 0;
- ret.y = 0;
-
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
#ifdef GDEXTENSION
@@ -291,12 +260,9 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
#endif
}
- FontTexture tex;
- tex.texture_w = texsize;
- tex.texture_h = texsize;
+ ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
tex.format = p_image_format;
tex.imgdata.resize(texsize * texsize * p_color_size);
-
{
// Zero texture.
uint8_t *w = tex.imgdata.ptrw();
@@ -319,14 +285,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
ERR_FAIL_V(ret);
}
}
- tex.offsets.resize(texsize);
- int32_t *offw = tex.offsets.ptrw();
- for (int i = 0; i < texsize; i++) { // Zero offsets.
- offw[i] = 0;
- }
-
p_data->textures.push_back(tex);
- ret.index = p_data->textures.size() - 1;
+
+ int32_t idx = p_data->textures.size() - 1;
+ ret = p_data->textures.write[idx].pack_rect(idx, mh, mw);
}
return ret;
@@ -460,7 +422,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
- FontTexture &tex = p_data->textures.write[tex_pos.index];
+ ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
edgeColoringSimple(shape, 3.0); // Max. angle.
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
@@ -503,12 +465,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
tex.dirty = true;
- // Update height array.
- int32_t *offw = tex.offsets.ptrw();
- for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- offw[k] = tex_pos.y + mh;
- }
-
chr.texture_idx = tex_pos.index;
chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
@@ -555,8 +511,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
// Fit character in char texture.
-
- FontTexture &tex = p_data->textures.write[tex_pos.index];
+ ShelfPackTexture &tex = p_data->textures.write[tex_pos.index];
{
uint8_t *wr = tex.imgdata.ptrw();
@@ -621,12 +576,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
tex.dirty = true;
- // Update height array.
- int32_t *offw = tex.offsets.ptrw();
- for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
- offw[k] = tex_pos.y + mh;
- }
-
FontGlyph chr;
chr.advance = advance * p_data->scale / p_data->oversampling;
chr.texture_idx = tex_pos.index;
@@ -818,7 +767,10 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
int error = 0;
if (!ft_library) {
error = FT_Init_FreeType(&ft_library);
- ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ if (error != 0) {
+ memdelete(fd);
+ ERR_FAIL_V_MSG(false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
+ }
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -847,6 +799,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
@@ -945,6 +898,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
FT_Done_MM_Var(ft_library, amaster);
}
#else
+ memdelete(fd);
ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
}
@@ -1581,16 +1535,14 @@ void TextServerFallback::_font_set_texture_image(const RID &p_font_rid, const Ve
fd->cache[size]->textures.resize(p_texture_index + 1);
}
- FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
tex.imgdata = p_image->get_data();
tex.texture_w = p_image->get_width();
tex.texture_h = p_image->get_height();
tex.format = p_image->get_format();
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -1608,15 +1560,12 @@ Ref<Image> TextServerFallback::_font_get_texture_image(const RID &p_font_rid, co
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Ref<Image>());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), Ref<Image>());
- const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
-
- return img;
+ const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
+ return Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
}
-void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
+void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offsets) {
+ ERR_FAIL_COND(p_offsets.size() % 4 != 0);
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1628,8 +1577,11 @@ void TextServerFallback::_font_set_texture_offsets(const RID &p_font_rid, const
fd->cache[size]->textures.resize(p_texture_index + 1);
}
- FontTexture &tex = fd->cache[size]->textures.write[p_texture_index];
- tex.offsets = p_offset;
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[p_texture_index];
+ tex.shelves.clear();
+ for (int32_t i = 0; i < p_offsets.size(); i += 4) {
+ tex.shelves.push_back(Shelf(p_offsets[i], p_offsets[i + 1], p_offsets[i + 2], p_offsets[i + 3]));
+ }
}
PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
@@ -1641,8 +1593,20 @@ PackedInt32Array TextServerFallback::_font_get_texture_offsets(const RID &p_font
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
ERR_FAIL_INDEX_V(p_texture_index, fd->cache[size]->textures.size(), PackedInt32Array());
- const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
- return tex.offsets;
+ const ShelfPackTexture &tex = fd->cache[size]->textures[p_texture_index];
+ PackedInt32Array ret;
+ ret.resize(tex.shelves.size() * 4);
+
+ int32_t *wr = ret.ptrw();
+ int32_t i = 0;
+ for (const Shelf &E : tex.shelves) {
+ wr[i * 4] = E.x;
+ wr[i * 4 + 1] = E.y;
+ wr[i * 4 + 2] = E.w;
+ wr[i * 4 + 3] = E.h;
+ i++;
+ }
+ return ret;
}
PackedInt32Array TextServerFallback::_font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
@@ -1694,7 +1658,7 @@ Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1711,9 +1675,10 @@ Vector2 TextServerFallback::_font_get_glyph_advance(const RID &p_font_rid, int64
ea.x = fd->embolden * double(size.x) / 64.0;
}
+ double scale = _font_get_scale(p_font_rid, p_size);
if (fd->msdf) {
return (gl[p_glyph | mod].advance + ea) * (double)p_size / (double)fd->msdf_source_size;
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ } else if ((scale == 1.0) && ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_DISABLED) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x > SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE))) {
return (gl[p_glyph | mod].advance + ea).round();
} else {
return gl[p_glyph | mod].advance + ea;
@@ -1746,7 +1711,7 @@ Vector2 TextServerFallback::_font_get_glyph_offset(const RID &p_font_rid, const
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1791,7 +1756,7 @@ Vector2 TextServerFallback::_font_get_glyph_size(const RID &p_font_rid, const Ve
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1836,7 +1801,7 @@ Rect2 TextServerFallback::_font_get_glyph_uv_rect(const RID &p_font_rid, const V
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1876,7 +1841,7 @@ int64_t TextServerFallback::_font_get_glyph_texture_idx(const RID &p_font_rid, c
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1916,7 +1881,7 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1932,10 +1897,8 @@ RID TextServerFallback::_font_get_glyph_texture_rid(const RID &p_font_rid, const
if (RenderingServer::get_singleton() != nullptr) {
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -1964,7 +1927,7 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co
int mod = 0;
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
mod = (layout << 24);
}
@@ -1980,10 +1943,8 @@ Size2 TextServerFallback::_font_get_glyph_texture_size(const RID &p_font_rid, co
if (RenderingServer::get_singleton() != nullptr) {
if (gl[p_glyph | mod].texture_idx != -1) {
if (fd->cache[size]->textures[gl[p_glyph | mod].texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl[p_glyph | mod].texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -2275,7 +2236,7 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
if (!fd->msdf && fd->cache[size]->face) {
// LCD layout, bits 24, 25, 26
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
lcd_aa = true;
index = index | (layout << 24);
@@ -2309,10 +2270,8 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -2331,12 +2290,14 @@ void TextServerFallback::_font_draw_glyph(const RID &p_font_rid, const RID &p_ca
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
Point2 cpos = p_pos;
- cpos.y = Math::floor(cpos.y);
+ double scale = _font_get_scale(p_font_rid, p_size);
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.125));
+ cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.25));
- } else {
+ cpos.x = cpos.x + 0.25;
+ }
+ if (scale == 1.0) {
+ cpos.y = Math::floor(cpos.y);
cpos.x = Math::floor(cpos.x);
}
cpos += gl.rect.position;
@@ -2367,7 +2328,7 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
if (!fd->msdf && fd->cache[size]->face) {
// LCD layout, bits 24, 25, 26
if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
- TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)ProjectSettings::get_singleton()->get("gui/theme/lcd_subpixel_layout");
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
lcd_aa = true;
index = index | (layout << 24);
@@ -2401,10 +2362,8 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
#endif
if (RenderingServer::get_singleton() != nullptr) {
if (fd->cache[size]->textures[gl.texture_idx].dirty) {
- FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ ShelfPackTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img = Image::create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
if (fd->mipmaps) {
img->generate_mipmaps();
}
@@ -2423,12 +2382,14 @@ void TextServerFallback::_font_draw_glyph_outline(const RID &p_font_rid, const R
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2 cpos = p_pos;
- cpos.y = Math::floor(cpos.y);
+ double scale = _font_get_scale(p_font_rid, p_size);
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.125));
+ cpos.x = cpos.x + 0.125;
} else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- cpos.x = ((int)Math::floor(cpos.x + 0.25));
- } else {
+ cpos.x = cpos.x + 0.25;
+ }
+ if (scale == 1.0) {
+ cpos.y = Math::floor(cpos.y);
cpos.x = Math::floor(cpos.x);
}
cpos += gl.rect.position;
@@ -3651,17 +3612,18 @@ bool TextServerFallback::_shaped_text_shape(const RID &p_shaped) {
}
}
+ double scale = _font_get_scale(gl.font_rid, gl.font_size);
if (gl.font_rid.is_valid()) {
- bool subpos = (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
+ bool subpos = (scale != 1.0) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_HALF) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_ONE_QUARTER) || (_font_get_subpixel_positioning(gl.font_rid) == SUBPIXEL_POSITIONING_AUTO && gl.font_size <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE);
if (sd->text[j - sd->start] != 0 && !is_linebreak(sd->text[j - sd->start])) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- gl.advance = Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x);
+ gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x;
gl.x_off = 0;
gl.y_off = 0;
sd->ascent = MAX(sd->ascent, _font_get_ascent(gl.font_rid, gl.font_size));
sd->descent = MAX(sd->descent, _font_get_descent(gl.font_rid, gl.font_size));
} else {
- gl.advance = Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y);
+ gl.advance = _font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).y;
gl.x_off = -Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5);
gl.y_off = _font_get_ascent(gl.font_rid, gl.font_size);
sd->ascent = MAX(sd->ascent, Math::round(_font_get_glyph_advance(gl.font_rid, gl.font_size, gl.index).x * 0.5));
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 4aeec4f452..151ae13904 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -127,20 +127,86 @@ class TextServerFallback : public TextServerExtension {
const int rect_range = 1;
- struct FontTexture {
+ struct FontTexturePosition {
+ int32_t index = -1;
+ int32_t x = 0;
+ int32_t y = 0;
+
+ FontTexturePosition() {}
+ FontTexturePosition(int32_t p_id, int32_t p_x, int32_t p_y) :
+ index(p_id), x(p_x), y(p_y) {}
+ };
+
+ struct Shelf {
+ int32_t x = 0;
+ int32_t y = 0;
+ int32_t w = 0;
+ int32_t h = 0;
+
+ FontTexturePosition alloc_shelf(int32_t p_id, int32_t p_w, int32_t p_h) {
+ if (p_w > w || p_h > h) {
+ return FontTexturePosition(-1, 0, 0);
+ }
+ int32_t xx = x;
+ x += p_w;
+ w -= p_w;
+ return FontTexturePosition(p_id, xx, y);
+ }
+
+ Shelf() {}
+ Shelf(int32_t p_x, int32_t p_y, int32_t p_w, int32_t p_h) :
+ x(p_x), y(p_y), w(p_w), h(p_h) {}
+ };
+
+ struct ShelfPackTexture {
+ int32_t texture_w = 1024;
+ int32_t texture_h = 1024;
+
Image::Format format;
PackedByteArray imgdata;
- int texture_w = 0;
- int texture_h = 0;
- PackedInt32Array offsets;
Ref<ImageTexture> texture;
bool dirty = true;
- };
- struct FontTexturePosition {
- int index = 0;
- int x = 0;
- int y = 0;
+ List<Shelf> shelves;
+
+ FontTexturePosition pack_rect(int32_t p_id, int32_t p_h, int32_t p_w) {
+ int32_t y = 0;
+ int32_t waste = 0;
+ Shelf *best_shelf = nullptr;
+ int32_t best_waste = std::numeric_limits<std::int32_t>::max();
+
+ for (Shelf &E : shelves) {
+ y += E.h;
+ if (p_w > E.w) {
+ continue;
+ }
+ if (p_h == E.h) {
+ return E.alloc_shelf(p_id, p_w, p_h);
+ }
+ if (p_h > E.h) {
+ continue;
+ }
+ if (p_h < E.h) {
+ waste = (E.h - p_h) * p_w;
+ if (waste < best_waste) {
+ best_waste = waste;
+ best_shelf = &E;
+ }
+ }
+ }
+ if (best_shelf) {
+ return best_shelf->alloc_shelf(p_id, p_w, p_h);
+ }
+ if (p_h <= (texture_h - y) && p_w <= texture_w) {
+ List<Shelf>::Element *E = shelves.push_back(Shelf(0, y, texture_w, p_h));
+ return E->get().alloc_shelf(p_id, p_w, p_h);
+ }
+ return FontTexturePosition(-1, 0, 0);
+ }
+
+ ShelfPackTexture() {}
+ ShelfPackTexture(int32_t p_w, int32_t p_h) :
+ texture_w(p_w), texture_h(p_h) {}
};
struct FontGlyph {
@@ -161,7 +227,7 @@ class TextServerFallback : public TextServerExtension {
Vector2i size;
- Vector<FontTexture> textures;
+ Vector<ShelfPackTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
HashMap<Vector2i, Vector2> kerning_map;
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index aed95294e7..8adde3c5d3 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -246,7 +246,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
}
}
- p_image->create(width, height, false, Image::FORMAT_RGBA8, image_data);
+ p_image->initialize_data(width, height, false, Image::FORMAT_RGBA8, image_data);
return OK;
}
@@ -284,14 +284,21 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField
err = FAILED;
}
+ uint64_t color_map_size;
if (has_color_map) {
if (tga_header.color_map_length > 256 || (tga_header.color_map_depth != 24) || tga_header.color_map_type != 1) {
err = FAILED;
}
+ color_map_size = tga_header.color_map_length * (tga_header.color_map_depth >> 3);
} else {
if (tga_header.color_map_type) {
err = FAILED;
}
+ color_map_size = 0;
+ }
+
+ if ((src_image_len - f->get_position()) < (tga_header.id_length + color_map_size)) {
+ err = FAILED; // TGA data appears to be truncated (fewer bytes than expected).
}
if (tga_header.image_width <= 0 || tga_header.image_height <= 0) {
@@ -308,7 +315,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitField
Vector<uint8_t> palette;
if (has_color_map) {
- size_t color_map_size = tga_header.color_map_length * (tga_header.color_map_depth >> 3);
err = palette.resize(color_map_size);
if (err == OK) {
uint8_t *palette_w = palette.ptrw();
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 57f055ca42..83833d8253 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -33,8 +33,17 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
#include "thirdparty/misc/yuv2rgb.h"
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
int VideoStreamPlaybackTheora::buffer_data() {
char *buffer = ogg_sync_buffer(&oy, 4096);
@@ -242,16 +251,9 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
/* we're expecting more header packets. */
while ((theora_p && theora_p < 3) || (vorbis_p && vorbis_p < 3)) {
-#ifdef _MSC_VER
- // Make exception for these assignments in conditional expression.
-#pragma warning(push)
-#pragma warning(disable : 4706)
-#endif
-
- int ret;
-
/* look for further theora headers */
- while (theora_p && (theora_p < 3) && (ret = ogg_stream_packetout(&to, &op))) {
+ int ret = ogg_stream_packetout(&to, &op);
+ while (theora_p && theora_p < 3 && ret) {
if (ret < 0) {
fprintf(stderr, "Error parsing Theora stream headers; corrupt stream?\n");
clear();
@@ -262,11 +264,13 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
clear();
return;
}
+ ret = ogg_stream_packetout(&to, &op);
theora_p++;
}
/* look for more vorbis header packets */
- while (vorbis_p && (vorbis_p < 3) && (ret = ogg_stream_packetout(&vo, &op))) {
+ ret = ogg_stream_packetout(&vo, &op);
+ while (vorbis_p && vorbis_p < 3 && ret) {
if (ret < 0) {
fprintf(stderr, "Error parsing Vorbis stream headers; corrupt stream?\n");
clear();
@@ -282,12 +286,9 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
if (vorbis_p == 3) {
break;
}
+ ret = ogg_stream_packetout(&vo, &op);
}
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
/* The header pages/packets will arrive before anything else we
care about, or the stream is not obeying spec */
@@ -335,9 +336,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
size.x = w;
size.y = h;
- Ref<Image> img;
- img.instantiate();
- img->create(w, h, false, Image::FORMAT_RGBA8);
+ Ref<Image> img = Image::create_empty(w, h, false, Image::FORMAT_RGBA8);
texture->set_image(img);
} else {
@@ -464,12 +463,6 @@ void VideoStreamPlaybackTheora::update(double p_delta) {
while (theora_p && !frame_done) {
/* theora is one in, one out... */
if (ogg_stream_packetout(&to, &op) > 0) {
- if (false && pp_inc) {
- pp_level += pp_inc;
- th_decode_ctl(td, TH_DECCTL_SET_PPLEVEL, &pp_level,
- sizeof(pp_level));
- pp_inc = 0;
- }
/*HACK: This should be set after a seek or a gap, but we might not have
a granulepos for the first packet (we only have them for the last
packet on a page), so we just set it as often as we get it.
@@ -556,7 +549,7 @@ void VideoStreamPlaybackTheora::play() {
}
playing = true;
- delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms");
+ delay_compensation = GLOBAL_GET("audio/video/video_delay_compensation_ms");
delay_compensation /= 1000.0;
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 3efb653651..9e096ec8b7 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -76,7 +76,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
th_info ti;
th_comment tc;
th_dec_ctx *td = nullptr;
- vorbis_info vi;
+ vorbis_info vi = {};
vorbis_dsp_state vd;
vorbis_block vb;
vorbis_comment vc;
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 5c43bfc8b7..c5aa110fe6 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -280,7 +280,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, BitF
}
}
- p_image->create(exr_image.width, exr_image.height, false, format, imgdata);
+ p_image->set_data(exr_image.width, exr_image.height, false, format, imgdata);
FreeEXRHeader(&exr_header);
FreeEXRImage(&exr_image);
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index 4888dca822..d4054948f6 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -41,7 +41,7 @@
func _ready():
thread = Thread.new()
- thread.start(self, "_upnp_setup", SERVER_PORT)
+ thread.start(_upnp_setup.bind(SERVER_PORT))
func _exit_tree():
# Wait for thread finish here to handle game exit while the thread is running.
diff --git a/modules/webp/resource_saver_webp.cpp b/modules/webp/resource_saver_webp.cpp
index bd71c2869a..56ff8097b4 100644
--- a/modules/webp/resource_saver_webp.cpp
+++ b/modules/webp/resource_saver_webp.cpp
@@ -38,8 +38,8 @@
Error ResourceSaverWebP::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
Ref<ImageTexture> texture = p_resource;
- ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as WEBP.");
- ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as WEBP.");
+ ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as WebP.");
+ ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as WebP.");
Ref<Image> img = texture->get_image();
@@ -52,7 +52,7 @@ Error ResourceSaverWebP::save_image(const String &p_path, const Ref<Image> &p_im
Vector<uint8_t> buffer = save_image_to_buffer(p_img, p_lossy, p_quality);
Error err;
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save WEBP at path: '%s'.", p_path));
+ ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save WebP at path: '%s'.", p_path));
const uint8_t *reader = buffer.ptr();
diff --git a/modules/webp/webp_common.cpp b/modules/webp/webp_common.cpp
index 8657a98853..af98788420 100644
--- a/modules/webp/webp_common.cpp
+++ b/modules/webp/webp_common.cpp
@@ -73,7 +73,7 @@ Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quality) {
Vector<uint8_t> _webp_lossless_pack(const Ref<Image> &p_image) {
ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>());
- int compression_level = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/webp_compression_level");
+ int compression_level = GLOBAL_GET("rendering/textures/lossless_compression/webp_compression_level");
compression_level = CLAMP(compression_level, 0, 9);
Ref<Image> img = p_image->duplicate();
@@ -139,7 +139,7 @@ Ref<Image> _webp_unpack(const Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(r[0] != 'R' || r[1] != 'I' || r[2] != 'F' || r[3] != 'F' || r[8] != 'W' || r[9] != 'E' || r[10] != 'B' || r[11] != 'P', Ref<Image>());
WebPBitstreamFeatures features;
if (WebPGetFeatures(r, size, &features) != VP8_STATUS_OK) {
- ERR_FAIL_V_MSG(Ref<Image>(), "Error unpacking WEBP image.");
+ ERR_FAIL_V_MSG(Ref<Image>(), "Error unpacking WebP image.");
}
Vector<uint8_t> dst_image;
@@ -183,7 +183,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
ERR_FAIL_COND_V_MSG(errdec, ERR_FILE_CORRUPT, "Failed decoding WebP image.");
- p_image->create(features.width, features.height, false, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image);
+ p_image->set_data(features.width, features.height, false, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image);
return OK;
}
diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
index 927888fe21..91ee65e9bd 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -6,7 +6,7 @@
<description>
This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.multiplayer_peer].
You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections.
- [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer].
+ [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless the peer is created using [method create_client]. Beside that data transfer works like in a [MultiplayerPeer].
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
@@ -22,10 +22,29 @@
Three channels will be created for reliable, unreliable, and ordered transport. The value of [code]unreliable_lifetime[/code] will be passed to the [code]maxPacketLifetime[/code] option when creating unreliable and ordered channels (see [method WebRTCPeerConnection.create_data_channel]).
</description>
</method>
- <method name="close">
- <return type="void" />
+ <method name="create_client">
+ <return type="int" enum="Error" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="channels_config" type="Array" default="[]" />
+ <description>
+ Initialize the multiplayer peer as a client with the given [code]peer_id[/code] (must be between 2 and 2147483647). In this mode, you should only call [method add_peer] once and with [code]peer_id[/code] of [code]1[/code]. This mode enables [method MultiplayerPeer.is_server_relay_supported], allowing the upper [MultiplayerAPI] layer to perform peer exchange and packet relaying.
+ You can optionally specify a [code]channels_config[/code] array of [enum MultiplayerPeer.TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel).
+ </description>
+ </method>
+ <method name="create_mesh">
+ <return type="int" enum="Error" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="channels_config" type="Array" default="[]" />
+ <description>
+ Initialize the multiplayer peer as a mesh (i.e. all peers connect to each other) with the given [code]peer_id[/code] (must be between 1 and 2147483647).
+ </description>
+ </method>
+ <method name="create_server">
+ <return type="int" enum="Error" />
+ <param index="0" name="channels_config" type="Array" default="[]" />
<description>
- Close all the add peer connections and channels, freeing all resources.
+ Initialize the multiplayer peer as a server (with unique ID of [code]1[/code]). This mode enables [method MultiplayerPeer.is_server_relay_supported], allowing the upper [MultiplayerAPI] layer to perform peer exchange and packet relaying.
+ You can optionally specify a [code]channels_config[/code] array of [enum MultiplayerPeer.TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel).
</description>
</method>
<method name="get_peer">
@@ -48,18 +67,6 @@
Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers map (it might not be connected though).
</description>
</method>
- <method name="initialize">
- <return type="int" enum="Error" />
- <param index="0" name="peer_id" type="int" />
- <param index="1" name="server_compatibility" type="bool" default="false" />
- <param index="2" name="channels_config" type="Array" default="[]" />
- <description>
- Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647).
- If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted.
- If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED].
- You can optionally specify a [code]channels_config[/code] array of [enum MultiplayerPeer.TransferMode] which will be used to create extra channels (WebRTC only supports one transfer mode per channel).
- </description>
- </method>
<method name="remove_peer">
<return type="void" />
<param index="0" name="peer_id" type="int" />
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index e03b6b2473..163b17fa6f 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.cpp
+++ b/modules/webrtc/webrtc_multiplayer_peer.cpp
@@ -34,13 +34,14 @@
#include "core/os/os.h"
void WebRTCMultiplayerPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility", "channels_config"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false), DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_server", "channels_config"), &WebRTCMultiplayerPeer::create_server, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_client", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_client, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("create_mesh", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_mesh, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1));
ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer);
ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer);
ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayerPeer::get_peer);
ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayerPeer::get_peers);
- ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close);
}
void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) {
@@ -52,6 +53,15 @@ int WebRTCMultiplayerPeer::get_packet_peer() const {
return next_packet_peer;
}
+int WebRTCMultiplayerPeer::get_packet_channel() const {
+ return next_packet_channel < CH_RESERVED_MAX ? 0 : next_packet_channel - CH_RESERVED_MAX + 1;
+}
+
+MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_packet_mode() const {
+ ERR_FAIL_INDEX_V(next_packet_channel, channels_modes.size(), TRANSFER_MODE_RELIABLE);
+ return channels_modes[next_packet_channel];
+}
+
bool WebRTCMultiplayerPeer::is_server() const {
return unique_id == TARGET_PEER_SERVER;
}
@@ -113,24 +123,14 @@ void WebRTCMultiplayerPeer::poll() {
// Signal newly connected peers
for (int &E : add) {
// Already connected to server: simply notify new peer.
- // NOTE: Mesh is always connected.
- if (connection_status == CONNECTION_CONNECTED) {
- emit_signal(SNAME("peer_connected"), E);
- }
-
- // Server emulation mode suppresses peer_conencted until server connects.
- if (server_compat && E == TARGET_PEER_SERVER) {
+ if (network_mode == MODE_CLIENT) {
+ ERR_CONTINUE(E != TARGET_PEER_SERVER); // Bug.
// Server connected.
connection_status = CONNECTION_CONNECTED;
emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER);
emit_signal(SNAME("connection_succeeded"));
- // Notify of all previously connected peers
- for (const KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) {
- if (F.key != 1 && F.value->connected) {
- emit_signal(SNAME("peer_connected"), F.key);
- }
- }
- break; // Because we already notified of all newly added peers.
+ } else {
+ emit_signal(SNAME("peer_connected"), E);
}
}
// Fetch next packet
@@ -150,11 +150,14 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
continue;
}
+ int idx = 0;
for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
+ next_packet_channel = idx;
next_packet_peer = E->key;
return;
}
+ idx++;
}
++E;
}
@@ -165,11 +168,14 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
continue;
}
+ int idx = 0;
for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
+ next_packet_channel = idx;
next_packet_peer = E->key;
return;
}
+ idx++;
}
if (E->key == (int)next_packet_peer) {
break;
@@ -177,6 +183,7 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
++E;
}
// No packet found
+ next_packet_channel = 0;
next_packet_peer = 0;
}
@@ -184,11 +191,28 @@ MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status()
return connection_status;
}
-Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Array p_channels_config) {
+Error WebRTCMultiplayerPeer::create_server(Array p_channels_config) {
+ return _initialize(1, MODE_SERVER, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::create_client(int p_self_id, Array p_channels_config) {
+ ERR_FAIL_COND_V_MSG(p_self_id == 1, ERR_INVALID_PARAMETER, "Clients cannot have ID 1.");
+ return _initialize(p_self_id, MODE_CLIENT, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::create_mesh(int p_self_id, Array p_channels_config) {
+ return _initialize(p_self_id, MODE_MESH, p_channels_config);
+}
+
+Error WebRTCMultiplayerPeer::_initialize(int p_self_id, NetworkMode p_mode, Array p_channels_config) {
ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER);
channels_config.clear();
+ channels_modes.clear();
+ channels_modes.push_back(TRANSFER_MODE_RELIABLE);
+ channels_modes.push_back(TRANSFER_MODE_UNRELIABLE_ORDERED);
+ channels_modes.push_back(TRANSFER_MODE_UNRELIABLE);
for (int i = 0; i < p_channels_config.size(); i++) {
- ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'");
+ ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'");
int mode = p_channels_config[i].operator int();
// Initialize data channel configurations.
Dictionary cfg;
@@ -207,16 +231,17 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr
case TRANSFER_MODE_RELIABLE:
break;
default:
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.Multiplayer::TransferMode'. Got: %d", mode));
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'. Got: %d", mode));
}
channels_config.push_back(cfg);
+ channels_modes.push_back((TransferMode)mode);
}
unique_id = p_self_id;
- server_compat = p_server_compat;
+ network_mode = p_mode;
// Mesh and server are always connected
- if (!server_compat || p_self_id == 1) {
+ if (p_mode != MODE_CLIENT) {
connection_status = CONNECTION_CONNECTED;
} else {
connection_status = CONNECTION_CONNECTING;
@@ -224,6 +249,10 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr
return OK;
}
+bool WebRTCMultiplayerPeer::is_server_relay_supported() const {
+ return network_mode == MODE_SERVER || network_mode == MODE_CLIENT;
+}
+
int WebRTCMultiplayerPeer::get_unique_id() const {
ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1);
return unique_id;
@@ -261,7 +290,10 @@ Dictionary WebRTCMultiplayerPeer::get_peers() {
}
Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) {
- ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(network_mode == MODE_NONE, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(network_mode == MODE_CLIENT && p_peer_id != 1, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(network_mode == MODE_SERVER && p_peer_id == 1, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(p_peer_id < 1 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED);
// Peer must be valid, and in new state (to create data channels)
@@ -308,10 +340,26 @@ void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) {
if (peer->connected) {
peer->connected = false;
emit_signal(SNAME("peer_disconnected"), p_peer_id);
- if (server_compat && p_peer_id == TARGET_PEER_SERVER) {
- emit_signal(SNAME("server_disconnected"));
+ if (network_mode == MODE_CLIENT && p_peer_id == TARGET_PEER_SERVER) {
+ if (connection_status == CONNECTION_CONNECTING) {
+ emit_signal(SNAME("connection_failed"));
+ } else {
+ emit_signal(SNAME("server_disconnected"));
+ }
+ connection_status = CONNECTION_DISCONNECTED;
+ }
+ }
+}
+
+void WebRTCMultiplayerPeer::disconnect_peer(int p_peer_id, bool p_force) {
+ ERR_FAIL_COND(!peer_map.has(p_peer_id));
+ if (p_force) {
+ peer_map.erase(p_peer_id);
+ if (network_mode == MODE_CLIENT && p_peer_id == TARGET_PEER_SERVER) {
connection_status = CONNECTION_DISCONNECTED;
}
+ } else {
+ peer_map[p_peer_id]->connection->close(); // Will be removed during next poll.
}
}
@@ -403,7 +451,9 @@ void WebRTCMultiplayerPeer::close() {
channels_config.clear();
unique_id = 0;
next_packet_peer = 0;
+ next_packet_channel = 0;
target_peer = 0;
+ network_mode = MODE_NONE;
connection_status = CONNECTION_DISCONNECTED;
}
diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h
index ea7c60036b..0556ef029c 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.h
+++ b/modules/webrtc/webrtc_multiplayer_peer.h
@@ -48,6 +48,13 @@ private:
CH_RESERVED_MAX = 3
};
+ enum NetworkMode {
+ MODE_NONE,
+ MODE_SERVER,
+ MODE_CLIENT,
+ MODE_MESH,
+ };
+
class ConnectedPeer : public RefCounted {
public:
Ref<WebRTCPeerConnection> connection;
@@ -67,43 +74,53 @@ private:
int client_count = 0;
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
int next_packet_peer = 0;
- bool server_compat = false;
+ int next_packet_channel = 0;
+ NetworkMode network_mode = MODE_NONE;
HashMap<int, Ref<ConnectedPeer>> peer_map;
+ List<TransferMode> channels_modes;
List<Dictionary> channels_config;
void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict);
void _find_next_peer();
+ Ref<ConnectedPeer> _get_next_peer();
+ Error _initialize(int p_self_id, NetworkMode p_mode, Array p_channels_config = Array());
public:
WebRTCMultiplayerPeer() {}
~WebRTCMultiplayerPeer();
- Error initialize(int p_self_id, bool p_server_compat = false, Array p_channels_config = Array());
+ Error create_server(Array p_channels_config = Array());
+ Error create_client(int p_self_id, Array p_channels_config = Array());
+ Error create_mesh(int p_self_id, Array p_channels_config = Array());
Error add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime = 1);
void remove_peer(int p_peer_id);
bool has_peer(int p_peer_id);
Dictionary get_peer(int p_peer_id);
Dictionary get_peers();
- void close();
// PacketPeer
- Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
- Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- int get_available_packet_count() const override;
- int get_max_packet_size() const override;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ virtual int get_available_packet_count() const override;
+ virtual int get_max_packet_size() const override;
// MultiplayerPeer
- void set_target_peer(int p_peer_id) override;
+ virtual void set_target_peer(int p_peer_id) override;
- int get_unique_id() const override;
- int get_packet_peer() const override;
+ virtual int get_unique_id() const override;
+ virtual int get_packet_peer() const override;
+ virtual int get_packet_channel() const override;
+ virtual TransferMode get_packet_mode() const override;
- bool is_server() const override;
+ virtual bool is_server() const override;
+ virtual bool is_server_relay_supported() const override;
- void poll() override;
+ virtual void poll() override;
+ virtual void close() override;
+ virtual void disconnect_peer(int p_peer_id, bool p_force = false) override;
- ConnectionStatus get_connection_status() const override;
+ virtual ConnectionStatus get_connection_status() const override;
};
#endif // WEBRTC_MULTIPLAYER_PEER_H
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
deleted file mode 100644
index 1978d2e7c6..0000000000
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A WebSocket client implementation.
- </brief_description>
- <description>
- This class implements a WebSocket client compatible with any RFC 6455-compliant WebSocket server.
- This client can be optionally used as a multiplayer peer for the [MultiplayerAPI].
- After starting the client ([method connect_to_url]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]).
- You will receive appropriate signals when connecting, disconnecting, or when new data is available.
- [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="connect_to_url">
- <return type="int" enum="Error" />
- <param index="0" name="url" type="String" />
- <param index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
- <param index="2" name="gd_mp_api" type="bool" default="false" />
- <param index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
- <description>
- Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested.
- If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a multiplayer peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
- If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
- You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request.
- [b]Note:[/b] To avoid mixed content warnings or errors in Web, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's TLS certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the TLS certificate.
- [b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in Web exports due to browsers' restrictions.
- </description>
- </method>
- <method name="disconnect_from_host">
- <return type="void" />
- <param index="0" name="code" type="int" default="1000" />
- <param index="1" name="reason" type="String" default="&quot;&quot;" />
- <description>
- Disconnects this client from the connected host. See [method WebSocketPeer.close] for more information.
- </description>
- </method>
- <method name="get_connected_host" qualifiers="const">
- <return type="String" />
- <description>
- Returns the IP address of the currently connected host.
- </description>
- </method>
- <method name="get_connected_port" qualifiers="const">
- <return type="int" />
- <description>
- Returns the IP port of the currently connected host.
- </description>
- </method>
- </methods>
- <members>
- <member name="trusted_tls_certificate" type="X509Certificate" setter="set_trusted_tls_certificate" getter="get_trusted_tls_certificate">
- If specified, this [X509Certificate] will be the only one accepted when connecting to an TLS host. Any other certificate provided by the server will be regarded as invalid.
- [b]Note:[/b] Specifying a custom [code]trusted_tls_certificate[/code] is not supported in Web exports due to browsers' restrictions.
- </member>
- <member name="verify_tls" type="bool" setter="set_verify_tls_enabled" getter="is_verify_tls_enabled">
- If [code]true[/code], TLS certificate verification is enabled.
- [b]Note:[/b] You must specify the certificates to be used in the Project Settings for it to work when exported.
- </member>
- </members>
- <signals>
- <signal name="connection_closed">
- <param index="0" name="was_clean_close" type="bool" />
- <description>
- Emitted when the connection to the server is closed. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly.
- </description>
- </signal>
- <signal name="connection_error">
- <description>
- Emitted when the connection to the server fails.
- </description>
- </signal>
- <signal name="connection_established">
- <param index="0" name="protocol" type="String" />
- <description>
- Emitted when a connection with the server is established, [code]protocol[/code] will contain the sub-protocol agreed with the server.
- </description>
- </signal>
- <signal name="data_received">
- <description>
- Emitted when a WebSocket message is received.
- [b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level multiplayer peer.
- </description>
- </signal>
- <signal name="server_close_request">
- <param index="0" name="code" type="int" />
- <param index="1" name="reason" type="String" />
- <description>
- Emitted when the server requests a clean close. You should keep polling until you get a [signal connection_closed] signal to achieve the clean close. See [method WebSocketPeer.close] for more details.
- </description>
- </signal>
- </signals>
-</class>
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 4cc4d515e7..7e896a0ca3 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -10,6 +10,26 @@
<tutorials>
</tutorials>
<methods>
+ <method name="create_client">
+ <return type="int" enum="Error" />
+ <param index="0" name="url" type="String" />
+ <param index="1" name="verify_tls" type="bool" default="true" />
+ <param index="2" name="tls_certificate" type="X509Certificate" default="null" />
+ <description>
+ Starts a new multiplayer client connecting to the given [param url]. If [param verify_tls] is [code]false[/code] certificate validation will be disabled. If specified, the [param tls_certificate] will be used to verify the TLS host.
+ [b]Note[/b]: It is recommended to specify the scheme part of the URL, i.e. the [param url] should start with either [code]ws://[/code] or [code]wss://[/code].
+ </description>
+ </method>
+ <method name="create_server">
+ <return type="int" enum="Error" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
+ <param index="2" name="tls_key" type="CryptoKey" default="null" />
+ <param index="3" name="tls_certificate" type="X509Certificate" default="null" />
+ <description>
+ Starts a new multiplayer server listening on the given [param port]. You can optionally specify a [param bind_address], and provide a [param tls_key] and [param tls_certificate] to use TLS.
+ </description>
+ </method>
<method name="get_peer" qualifiers="const">
<return type="WebSocketPeer" />
<param index="0" name="peer_id" type="int" />
@@ -17,27 +37,39 @@
Returns the [WebSocketPeer] associated to the given [code]peer_id[/code].
</description>
</method>
- <method name="set_buffers">
- <return type="int" enum="Error" />
- <param index="0" name="input_buffer_size_kb" type="int" />
- <param index="1" name="input_max_packets" type="int" />
- <param index="2" name="output_buffer_size_kb" type="int" />
- <param index="3" name="output_max_packets" type="int" />
+ <method name="get_peer_address" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="id" type="int" />
<description>
- Configures the buffer sizes for this WebSocket peer. Default values can be specified in the Project Settings under [code]network/limits[/code]. For server, values are meant per connected peer.
- The first two parameters define the size and queued packets limits of the input buffer, the last two of the output buffer.
- Buffer sizes are expressed in KiB, so [code]4 = 2^12 = 4096 bytes[/code]. All parameters will be rounded up to the nearest power of two.
- [b]Note:[/b] Web exports only use the input buffer since the output one is managed by browsers.
+ Returns the IP address of the given peer.
</description>
</method>
- </methods>
- <signals>
- <signal name="peer_packet">
- <param index="0" name="peer_source" type="int" />
+ <method name="get_peer_port" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Emitted when a packet is received from a peer.
- [b]Note:[/b] This signal is only emitted when the client or server is configured to use Godot multiplayer API.
+ Returns the remote port of the given peer.
</description>
- </signal>
- </signals>
+ </method>
+ </methods>
+ <members>
+ <member name="handshake_headers" type="PackedStringArray" setter="set_handshake_headers" getter="get_handshake_headers" default="PackedStringArray()">
+ The extra headers to use during handshake. See [member WebSocketPeer.handshake_headers] for more details.
+ </member>
+ <member name="handshake_timeout" type="float" setter="set_handshake_timeout" getter="get_handshake_timeout" default="3.0">
+ The maximum time each peer can stay in a connecting state before being dropped.
+ </member>
+ <member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
+ The inbound buffer size for connected peers. See [member WebSocketPeer.inbound_buffer_size] for more details.
+ </member>
+ <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="2048">
+ The maximum number of queued packets for connected peers. See [member WebSocketPeer.max_queued_packets] for more details.
+ </member>
+ <member name="outbound_buffer_size" type="int" setter="set_outbound_buffer_size" getter="get_outbound_buffer_size" default="65535">
+ The outbound buffer size for connected peers. See [member WebSocketPeer.outbound_buffer_size] for more details.
+ </member>
+ <member name="supported_protocols" type="PackedStringArray" setter="set_supported_protocols" getter="get_supported_protocols" default="PackedStringArray()">
+ The supported WebSocket sub-protocols. See [member WebSocketPeer.supported_protocols] for more details.
+ </member>
+ </members>
</class>
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 627b9c607c..fe0aae412e 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -1,25 +1,82 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="WebSocketPeer" inherits="PacketPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- A class representing a specific WebSocket connection.
+ A WebSocket connection.
</brief_description>
<description>
- This class represents a specific WebSocket connection, allowing you to do lower level operations with it.
- You can choose to write to the socket in binary or text mode, and you can recognize the mode used for writing by the other peer.
+ This class represents WebSocket connection, and can be used as a WebSocket client (RFC 6455-compliant) or as a remote peer of a WebSocket server.
+ You can send WebSocket binary frames using [method PacketPeer.put_packet], and WebSocket text frames using [method send] (prefer text frames when interacting with text-based API). You can check the frame type of the last packet via [method was_string_packet].
+ To start a WebSocket client, first call [method connect_to_url], then regularly call [method poll] (e.g. during [Node] process). You can query the socket state via [method get_ready_state], get the number of pending packets using [method PacketPeer.get_available_packet_count], and retrieve them via [method PacketPeer.get_packet].
+ [codeblocks]
+ [gdscript]
+ extends Node
+
+ var socket = WebSocketPeer.new()
+
+ func _ready():
+ socket.connect_to_url("wss://example.com")
+
+ func _process(delta):
+ socket.poll()
+ var state = socket.get_ready_state()
+ if state == WebSocketPeer.STATE_OPEN:
+ while socket.get_available_packet_count():
+ print("Packet: ", socket.get_packet())
+ elif state == WebSocketPeer.STATE_CLOSING:
+ # Keep polling to achieve proper close.
+ pass
+ elif state == WebSocketPeer.STATE_CLOSED:
+ var code = socket.get_close_code()
+ var reason = socket.get_close_reason()
+ print("WebSocket closed with code: %d, reason %s. Clean: %s" % [code, reason, code != -1])
+ set_process(false) # Stop processing.
+ [/gdscript]
+ [/codeblocks]
+ To use the peer as part of a WebSocket server refer to [method accept_stream] and the online tutorial.
</description>
<tutorials>
</tutorials>
<methods>
+ <method name="accept_stream">
+ <return type="int" enum="Error" />
+ <param index="0" name="stream" type="StreamPeer" />
+ <description>
+ Accepts a peer connection performing the HTTP handshake as a WebSocket server. The [param stream] must be a valid TCP stream retrieved via [method TCPServer.take_connection], or a TLS stream accepted via [method StreamPeerTLS.accept_stream].
+ [b]Note:[/b] Not supported in Web exports due to browsers' restrictions.
+ </description>
+ </method>
<method name="close">
<return type="void" />
<param index="0" name="code" type="int" default="1000" />
<param index="1" name="reason" type="String" default="&quot;&quot;" />
<description>
- Closes this WebSocket connection. [code]code[/code] is the status code for the closure (see RFC 6455 section 7.4 for a list of valid status codes). [code]reason[/code] is the human readable reason for closing the connection (can be any UTF-8 string that's smaller than 123 bytes).
- [b]Note:[/b] To achieve a clean close, you will need to keep polling until either [signal WebSocketClient.connection_closed] or [signal WebSocketServer.client_disconnected] is received.
+ Closes this WebSocket connection. [param code] is the status code for the closure (see RFC 6455 section 7.4 for a list of valid status codes). [param reason] is the human readable reason for closing the connection (can be any UTF-8 string that's smaller than 123 bytes). If [param code] is negative, the connection will be closed immediately without notifying the remote peer.
+ [b]Note:[/b] To achieve a clean close, you will need to keep polling until [constant STATE_CLOSED] is reached.
[b]Note:[/b] The Web export might not support all status codes. Please refer to browser-specific documentation for more details.
</description>
</method>
+ <method name="connect_to_url">
+ <return type="int" enum="Error" />
+ <param index="0" name="url" type="String" />
+ <param index="1" name="verify_tls" type="bool" default="true" />
+ <param index="2" name="trusted_tls_certificate" type="X509Certificate" default="null" />
+ <description>
+ Connects to the given URL. If [param verify_tls] is [code]false[/code] certificate validation will be disabled. If specified, the [param trusted_tls_certificate] will be the only one accepted when connecting to a TLS host.
+ [b]Note:[/b] To avoid mixed content warnings or errors in Web, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's TLS certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the TLS certificate.
+ </description>
+ </method>
+ <method name="get_close_code" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the received WebSocket close frame status code, or [code]-1[/code] when the connection was not cleanly closed. Only call this method when [method get_ready_state] returns [constant STATE_CLOSED].
+ </description>
+ </method>
+ <method name="get_close_reason" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the received WebSocket close frame status reason string. Only call this method when [method get_ready_state] returns [constant STATE_CLOSED].
+ </description>
+ </method>
<method name="get_connected_host" qualifiers="const">
<return type="String" />
<description>
@@ -40,31 +97,51 @@
Returns the current amount of data in the outbound websocket buffer. [b]Note:[/b] Web exports use WebSocket.bufferedAmount, while other platforms use an internal buffer.
</description>
</method>
- <method name="get_write_mode" qualifiers="const">
- <return type="int" enum="WebSocketPeer.WriteMode" />
+ <method name="get_ready_state" qualifiers="const">
+ <return type="int" enum="WebSocketPeer.State" />
<description>
- Gets the current selected write mode. See [enum WriteMode].
+ Returns the ready state of the connection. See [enum State].
</description>
</method>
- <method name="is_connected_to_host" qualifiers="const">
- <return type="bool" />
+ <method name="get_requested_url" qualifiers="const">
+ <return type="String" />
<description>
- Returns [code]true[/code] if this peer is currently connected.
+ Returns the URL requested by this peer. The URL is derived from the [code]url[/code] passed to [method connect_to_url] or from the HTTP headers when acting as server (i.e. when using [method accept_stream]).
</description>
</method>
- <method name="set_no_delay">
+ <method name="get_selected_protocol" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the selected WebSocket sub-protocol for this connection or an empty string if the sub-protocol has not been selected yet.
+ </description>
+ </method>
+ <method name="poll">
<return type="void" />
- <param index="0" name="enabled" type="bool" />
<description>
- Disable Nagle's algorithm on the underling TCP socket (default). See [method StreamPeerTCP.set_no_delay] for more information.
- [b]Note:[/b] Not available in the Web export.
+ Updates the connection state and receive incoming packets. Call this function regularly to keep it in a clean state.
</description>
</method>
- <method name="set_write_mode">
+ <method name="send">
+ <return type="int" enum="Error" />
+ <param index="0" name="message" type="PackedByteArray" />
+ <param index="1" name="write_mode" type="int" enum="WebSocketPeer.WriteMode" default="1" />
+ <description>
+ Sends the given [param message] using the desired [param write_mode]. When sending a [String], prefer using [method send_text].
+ </description>
+ </method>
+ <method name="send_text">
+ <return type="int" enum="Error" />
+ <param index="0" name="message" type="String" />
+ <description>
+ Sends the given [param message] using WebSocket text mode. Perfer this method over [method PacketPeer.put_packet] when interacting with third-party text-based API (e.g. when using [JSON] formatted messages).
+ </description>
+ </method>
+ <method name="set_no_delay">
<return type="void" />
- <param index="0" name="mode" type="int" enum="WebSocketPeer.WriteMode" />
+ <param index="0" name="enabled" type="bool" />
<description>
- Sets the socket to use the given [enum WriteMode].
+ Disable Nagle's algorithm on the underling TCP socket (default). See [method StreamPeerTCP.set_no_delay] for more information.
+ [b]Note:[/b] Not available in the Web export.
</description>
</method>
<method name="was_string_packet" qualifiers="const">
@@ -74,6 +151,24 @@
</description>
</method>
</methods>
+ <members>
+ <member name="handshake_headers" type="PackedStringArray" setter="set_handshake_headers" getter="get_handshake_headers" default="PackedStringArray()">
+ The extra HTTP headers to be sent during the WebSocket handshake.
+ [b]Note:[/b] Not supported in Web exports due to browsers' restrictions.
+ </member>
+ <member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
+ The size of the input buffer in bytes (roughly the maximum amount of memory that will be allocated for the inbound packets).
+ </member>
+ <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="2048">
+ The maximum amount of packets that will be allowed in the queues (both inbound and outbound).
+ </member>
+ <member name="outbound_buffer_size" type="int" setter="set_outbound_buffer_size" getter="get_outbound_buffer_size" default="65535">
+ The size of the input buffer in bytes (roughly the maximum amount of memory that will be allocated for the outbound packets).
+ </member>
+ <member name="supported_protocols" type="PackedStringArray" setter="set_supported_protocols" getter="get_supported_protocols" default="PackedStringArray()">
+ The WebSocket sub-protocols allowed during the WebSocket handshake.
+ </member>
+ </members>
<constants>
<constant name="WRITE_MODE_TEXT" value="0" enum="WriteMode">
Specifies that WebSockets messages should be transferred as text payload (only valid UTF-8 is allowed).
@@ -81,5 +176,17 @@
<constant name="WRITE_MODE_BINARY" value="1" enum="WriteMode">
Specifies that WebSockets messages should be transferred as binary payload (any byte combination is allowed).
</constant>
+ <constant name="STATE_CONNECTING" value="0" enum="State">
+ Socket has been created. The connection is not yet open.
+ </constant>
+ <constant name="STATE_OPEN" value="1" enum="State">
+ The connection is open and ready to communicate.
+ </constant>
+ <constant name="STATE_CLOSING" value="2" enum="State">
+ The connection is in the process of closing. This means a close request has been sent to the remote peer but confirmation has not been received.
+ </constant>
+ <constant name="STATE_CLOSED" value="3" enum="State">
+ The connection is closed or couldn't be opened.
+ </constant>
</constants>
</class>
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
deleted file mode 100644
index 07a55b73f1..0000000000
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A WebSocket server implementation.
- </brief_description>
- <description>
- This class implements a WebSocket server that can also support the high-level multiplayer API.
- After starting the server ([method listen]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal.
- [b]Note:[/b] Not available in Web exports.
- [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="disconnect_peer">
- <return type="void" />
- <param index="0" name="id" type="int" />
- <param index="1" name="code" type="int" default="1000" />
- <param index="2" name="reason" type="String" default="&quot;&quot;" />
- <description>
- Disconnects the peer identified by [code]id[/code] from the server. See [method WebSocketPeer.close] for more information.
- </description>
- </method>
- <method name="get_peer_address" qualifiers="const">
- <return type="String" />
- <param index="0" name="id" type="int" />
- <description>
- Returns the IP address of the given peer.
- </description>
- </method>
- <method name="get_peer_port" qualifiers="const">
- <return type="int" />
- <param index="0" name="id" type="int" />
- <description>
- Returns the remote port of the given peer.
- </description>
- </method>
- <method name="has_peer" qualifiers="const">
- <return type="bool" />
- <param index="0" name="id" type="int" />
- <description>
- Returns [code]true[/code] if a peer with the given ID is connected.
- </description>
- </method>
- <method name="is_listening" qualifiers="const">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the server is actively listening on a port.
- </description>
- </method>
- <method name="listen">
- <return type="int" enum="Error" />
- <param index="0" name="port" type="int" />
- <param index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
- <param index="2" name="gd_mp_api" type="bool" default="false" />
- <description>
- Starts listening on the given port.
- You can specify the desired subprotocols via the "protocols" array. If the list empty (default), no sub-protocol will be requested.
- If [code]true[/code] is passed as [code]gd_mp_api[/code], the server will behave like a multiplayer peer for the [MultiplayerAPI], connections from non-Godot clients will not work, and [signal data_received] will not be emitted.
- If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.), on the [WebSocketPeer] returned via [code]get_peer(id)[/code] to communicate with the peer with given [code]id[/code] (e.g. [code]get_peer(id).get_available_packet_count[/code]).
- </description>
- </method>
- <method name="set_extra_headers">
- <return type="void" />
- <param index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" />
- <description>
- Sets additional headers to be sent to clients during the HTTP handshake.
- </description>
- </method>
- <method name="stop">
- <return type="void" />
- <description>
- Stops the server and clear its state.
- </description>
- </method>
- </methods>
- <members>
- <member name="bind_ip" type="String" setter="set_bind_ip" getter="get_bind_ip" default="&quot;*&quot;">
- When not set to [code]*[/code] will restrict incoming connections to the specified IP address. Setting [code]bind_ip[/code] to [code]127.0.0.1[/code] will cause the server to listen only to the local host.
- </member>
- <member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain">
- When using TLS (see [member private_key] and [member tls_certificate]), you can set this to a valid [X509Certificate] to be provided as additional CA chain information during the TLS handshake.
- </member>
- <member name="handshake_timeout" type="float" setter="set_handshake_timeout" getter="get_handshake_timeout" default="3.0">
- The time in seconds before a pending client (i.e. a client that has not yet finished the HTTP handshake) is considered stale and forcefully disconnected.
- </member>
- <member name="private_key" type="CryptoKey" setter="set_private_key" getter="get_private_key">
- When set to a valid [CryptoKey] (along with [member tls_certificate]) will cause the server to require TLS instead of regular TCP (i.e. the [code]wss://[/code] protocol).
- </member>
- <member name="tls_certificate" type="X509Certificate" setter="set_tls_certificate" getter="get_tls_certificate">
- When set to a valid [X509Certificate] (along with [member private_key]) will cause the server to require TLS instead of regular TCP (i.e. the [code]wss://[/code] protocol).
- </member>
- </members>
- <signals>
- <signal name="client_close_request">
- <param index="0" name="id" type="int" />
- <param index="1" name="code" type="int" />
- <param index="2" name="reason" type="String" />
- <description>
- Emitted when a client requests a clean close. You should keep polling until you get a [signal client_disconnected] signal with the same [code]id[/code] to achieve the clean close. See [method WebSocketPeer.close] for more details.
- </description>
- </signal>
- <signal name="client_connected">
- <param index="0" name="id" type="int" />
- <param index="1" name="protocol" type="String" />
- <param index="2" name="resource_name" type="String" />
- <description>
- Emitted when a new client connects. "protocol" will be the sub-protocol agreed with the client, and "resource_name" will be the resource name of the URI the peer used.
- "resource_name" is a path (at the very least a single forward slash) and potentially a query string.
- </description>
- </signal>
- <signal name="client_disconnected">
- <param index="0" name="id" type="int" />
- <param index="1" name="was_clean_close" type="bool" />
- <description>
- Emitted when a client disconnects. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly.
- </description>
- </signal>
- <signal name="data_received">
- <param index="0" name="id" type="int" />
- <description>
- Emitted when a new message is received.
- [b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level multiplayer peer.
- </description>
- </signal>
- </signals>
-</class>
diff --git a/modules/websocket/editor/editor_debugger_server_websocket.cpp b/modules/websocket/editor/editor_debugger_server_websocket.cpp
index 0443147d98..a9c44141aa 100644
--- a/modules/websocket/editor/editor_debugger_server_websocket.cpp
+++ b/modules/websocket/editor/editor_debugger_server_websocket.cpp
@@ -38,18 +38,31 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
-void EditorDebuggerServerWebSocket::_peer_connected(int p_id, String _protocol) {
- pending_peers.push_back(p_id);
-}
+void EditorDebuggerServerWebSocket::poll() {
+ if (pending_peer.is_null() && tcp_server->is_connection_available()) {
+ Ref<WebSocketPeer> peer = Ref<WebSocketPeer>(WebSocketPeer::create());
+ ERR_FAIL_COND(peer.is_null()); // Bug.
-void EditorDebuggerServerWebSocket::_peer_disconnected(int p_id, bool p_was_clean) {
- if (pending_peers.find(p_id)) {
- pending_peers.erase(p_id);
- }
-}
+ Vector<String> ws_protocols;
+ ws_protocols.push_back("binary"); // Compatibility for emscripten TCP-to-WebSocket.
+ peer->set_supported_protocols(ws_protocols);
-void EditorDebuggerServerWebSocket::poll() {
- server->poll();
+ Error err = peer->accept_stream(tcp_server->take_connection());
+ if (err == OK) {
+ pending_timer = OS::get_singleton()->get_ticks_msec();
+ pending_peer = peer;
+ }
+ }
+ if (pending_peer.is_valid() && pending_peer->get_ready_state() != WebSocketPeer::STATE_OPEN) {
+ pending_peer->poll();
+ WebSocketPeer::State ready_state = pending_peer->get_ready_state();
+ if (ready_state != WebSocketPeer::STATE_CONNECTING && ready_state != WebSocketPeer::STATE_OPEN) {
+ pending_peer.unref(); // Failed.
+ }
+ if (ready_state == WebSocketPeer::STATE_CONNECTING && OS::get_singleton()->get_ticks_msec() - pending_timer > 3000) {
+ pending_peer.unref(); // Timeout.
+ }
+ }
}
String EditorDebuggerServerWebSocket::get_uri() const {
@@ -58,8 +71,8 @@ String EditorDebuggerServerWebSocket::get_uri() const {
Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
// Default host and port
- String bind_host = (String)EditorSettings::get_singleton()->get("network/debug/remote_host");
- int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ String bind_host = (String)EDITOR_GET("network/debug/remote_host");
+ int bind_port = (int)EDITOR_GET("network/debug/remote_port");
// Optionally override
if (!p_uri.is_empty() && p_uri != "ws://") {
@@ -69,15 +82,10 @@ Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
}
- // Set up the server
- server->set_bind_ip(bind_host);
- Vector<String> compatible_protocols;
- compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer.
-
// Try listening on ports
const int max_attempts = 5;
for (int attempt = 1;; ++attempt) {
- const Error err = server->listen(bind_port, compatible_protocols);
+ const Error err = tcp_server->listen(bind_port, bind_host);
if (err == OK) {
break;
}
@@ -96,31 +104,27 @@ Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
}
void EditorDebuggerServerWebSocket::stop() {
- server->stop();
- pending_peers.clear();
+ pending_peer.unref();
+ tcp_server->stop();
}
bool EditorDebuggerServerWebSocket::is_active() const {
- return server->is_listening();
+ return tcp_server->is_listening();
}
bool EditorDebuggerServerWebSocket::is_connection_available() const {
- return pending_peers.size() > 0;
+ return pending_peer.is_valid() && pending_peer->get_ready_state() == WebSocketPeer::STATE_OPEN;
}
Ref<RemoteDebuggerPeer> EditorDebuggerServerWebSocket::take_connection() {
ERR_FAIL_COND_V(!is_connection_available(), Ref<RemoteDebuggerPeer>());
- RemoteDebuggerPeer *peer = memnew(RemoteDebuggerPeerWebSocket(server->get_peer(pending_peers[0])));
- pending_peers.pop_front();
+ RemoteDebuggerPeer *peer = memnew(RemoteDebuggerPeerWebSocket(pending_peer));
+ pending_peer.unref();
return peer;
}
EditorDebuggerServerWebSocket::EditorDebuggerServerWebSocket() {
- server = Ref<WebSocketServer>(WebSocketServer::create());
- int max_pkts = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
- server->set_buffers(8192, max_pkts, 8192, max_pkts);
- server->connect("client_connected", callable_mp(this, &EditorDebuggerServerWebSocket::_peer_connected));
- server->connect("client_disconnected", callable_mp(this, &EditorDebuggerServerWebSocket::_peer_disconnected));
+ tcp_server.instantiate();
}
EditorDebuggerServerWebSocket::~EditorDebuggerServerWebSocket() {
diff --git a/modules/websocket/editor/editor_debugger_server_websocket.h b/modules/websocket/editor/editor_debugger_server_websocket.h
index 7c0705302d..31e54cb5df 100644
--- a/modules/websocket/editor/editor_debugger_server_websocket.h
+++ b/modules/websocket/editor/editor_debugger_server_websocket.h
@@ -33,15 +33,18 @@
#ifdef TOOLS_ENABLED
-#include "../websocket_server.h"
+#include "../websocket_peer.h"
+
+#include "core/io/tcp_server.h"
#include "editor/debugger/editor_debugger_server.h"
class EditorDebuggerServerWebSocket : public EditorDebuggerServer {
GDCLASS(EditorDebuggerServerWebSocket, EditorDebuggerServer);
private:
- Ref<WebSocketServer> server;
- List<int> pending_peers;
+ Ref<TCPServer> tcp_server;
+ Ref<WebSocketPeer> pending_peer;
+ uint64_t pending_timer = 0;
String endpoint;
public:
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
deleted file mode 100644
index 933a1f43e9..0000000000
--- a/modules/websocket/emws_client.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*************************************************************************/
-/* emws_client.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. */
-/*************************************************************************/
-
-#ifdef WEB_ENABLED
-
-#include "emws_client.h"
-
-#include "core/config/project_settings.h"
-#include "core/io/ip.h"
-#include "emscripten.h"
-
-void EMWSClient::_esws_on_connect(void *obj, char *proto) {
- EMWSClient *client = static_cast<EMWSClient *>(obj);
- client->_is_connecting = false;
- client->_on_connect(String(proto));
-}
-
-void EMWSClient::_esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string) {
- EMWSClient *client = static_cast<EMWSClient *>(obj);
-
- Error err = static_cast<EMWSPeer *>(*client->get_peer(1))->read_msg(p_data, p_data_size, p_is_string == 1);
- if (err == OK) {
- client->_on_peer_packet();
- }
-}
-
-void EMWSClient::_esws_on_error(void *obj) {
- EMWSClient *client = static_cast<EMWSClient *>(obj);
- client->_is_connecting = false;
- client->_on_error();
-}
-
-void EMWSClient::_esws_on_close(void *obj, int code, const char *reason, int was_clean) {
- EMWSClient *client = static_cast<EMWSClient *>(obj);
- client->_on_close_request(code, String(reason));
- client->_is_connecting = false;
- client->disconnect_from_host();
- client->_on_disconnect(was_clean != 0);
-}
-
-Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_tls, const Vector<String> p_protocols, const Vector<String> p_custom_headers) {
- if (_js_id) {
- godot_js_websocket_destroy(_js_id);
- _js_id = 0;
- }
-
- String proto_string;
- for (int i = 0; i < p_protocols.size(); i++) {
- if (i != 0) {
- proto_string += ",";
- }
- proto_string += p_protocols[i];
- }
-
- String str = "ws://";
-
- if (p_custom_headers.size()) {
- WARN_PRINT_ONCE("Custom headers are not supported in Web platform.");
- }
- if (p_tls) {
- str = "wss://";
- if (tls_cert.is_valid()) {
- WARN_PRINT_ONCE("Custom SSL certificate is not supported in Web platform.");
- }
- }
- str += p_host + ":" + itos(p_port) + p_path;
- _is_connecting = true;
-
- _js_id = godot_js_websocket_create(this, str.utf8().get_data(), proto_string.utf8().get_data(), &_esws_on_connect, &_esws_on_message, &_esws_on_error, &_esws_on_close);
- if (!_js_id) {
- return FAILED;
- }
-
- static_cast<Ref<EMWSPeer>>(_peer)->set_sock(_js_id, _in_buf_size, _in_pkt_size, _out_buf_size);
-
- return OK;
-}
-
-void EMWSClient::poll() {
-}
-
-Ref<WebSocketPeer> EMWSClient::get_peer(int p_peer_id) const {
- return _peer;
-}
-
-MultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const {
- if (_peer->is_connected_to_host()) {
- if (_is_connecting) {
- return CONNECTION_CONNECTING;
- }
- return CONNECTION_CONNECTED;
- }
-
- return CONNECTION_DISCONNECTED;
-}
-
-void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
- _peer->close(p_code, p_reason);
-}
-
-IPAddress EMWSClient::get_connected_host() const {
- ERR_FAIL_V_MSG(IPAddress(), "Not supported in Web export.");
-}
-
-uint16_t EMWSClient::get_connected_port() const {
- ERR_FAIL_V_MSG(0, "Not supported in Web export.");
-}
-
-int EMWSClient::get_max_packet_size() const {
- return (1 << _in_buf_size) - PROTO_SIZE;
-}
-
-Error EMWSClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
- _in_pkt_size = nearest_shift(p_in_packets - 1);
- _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
- return OK;
-}
-
-EMWSClient::EMWSClient() {
- _peer = Ref<EMWSPeer>(memnew(EMWSPeer));
-}
-
-EMWSClient::~EMWSClient() {
- disconnect_from_host();
- _peer = Ref<EMWSPeer>();
- if (_js_id) {
- godot_js_websocket_destroy(_js_id);
- }
-}
-
-#endif // WEB_ENABLED
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 859c92b457..3bd132bc73 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -34,55 +34,116 @@
#include "core/io/ip.h"
-void EMWSPeer::set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size) {
- peer_sock = p_sock;
- _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
- _packet_buffer.resize((1 << p_in_buf_size));
- _out_buf_size = p_out_buf_size;
+void EMWSPeer::_esws_on_connect(void *p_obj, char *p_proto) {
+ EMWSPeer *peer = static_cast<EMWSPeer *>(p_obj);
+ peer->ready_state = STATE_OPEN;
+ peer->selected_protocol.parse_utf8(p_proto);
}
-void EMWSPeer::set_write_mode(WriteMode p_mode) {
- write_mode = p_mode;
+void EMWSPeer::_esws_on_message(void *p_obj, const uint8_t *p_data, int p_data_size, int p_is_string) {
+ EMWSPeer *peer = static_cast<EMWSPeer *>(p_obj);
+ uint8_t is_string = p_is_string ? 1 : 0;
+ peer->in_buffer.write_packet(p_data, p_data_size, &is_string);
}
-EMWSPeer::WriteMode EMWSPeer::get_write_mode() const {
- return write_mode;
+void EMWSPeer::_esws_on_error(void *p_obj) {
+ EMWSPeer *peer = static_cast<EMWSPeer *>(p_obj);
+ peer->ready_state = STATE_CLOSED;
}
-Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string) {
- uint8_t is_string = p_is_string ? 1 : 0;
- return _in_buffer.write_packet(p_data, p_size, &is_string);
+void EMWSPeer::_esws_on_close(void *p_obj, int p_code, const char *p_reason, int p_was_clean) {
+ EMWSPeer *peer = static_cast<EMWSPeer *>(p_obj);
+ peer->close_code = p_code;
+ peer->close_reason.parse_utf8(p_reason);
+ peer->ready_state = STATE_CLOSED;
}
-Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(_out_buf_size && ((uint64_t)godot_js_websocket_buffered_amount(peer_sock) + p_buffer_size >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY);
+Error EMWSPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate) {
+ ERR_FAIL_COND_V(ready_state != STATE_CLOSED, ERR_ALREADY_IN_USE);
+ _clear();
+
+ String host;
+ String path;
+ String scheme;
+ int port = 0;
+ Error err = p_url.parse_url(scheme, host, port, path);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url);
+
+ if (scheme.is_empty()) {
+ scheme = "ws://";
+ }
+ ERR_FAIL_COND_V_MSG(scheme != "ws://" && scheme != "wss://", ERR_INVALID_PARAMETER, vformat("Invalid protocol: \"%s\" (must be either \"ws://\" or \"wss://\").", scheme));
+
+ String proto_string;
+ for (int i = 0; i < supported_protocols.size(); i++) {
+ if (i != 0) {
+ proto_string += ",";
+ }
+ proto_string += supported_protocols[i];
+ }
+
+ if (handshake_headers.size()) {
+ WARN_PRINT_ONCE("Custom headers are not supported in Web platform.");
+ }
+ if (p_tls_certificate.is_valid()) {
+ WARN_PRINT_ONCE("Custom SSL certificates are not supported in Web platform.");
+ }
- int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0;
+ requested_url = scheme + host;
- if (godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, is_bin) != 0) {
+ if (port && ((scheme == "ws://" && port != 80) || (scheme == "wss://" && port != 443))) {
+ requested_url += ":" + String::num(port);
+ }
+
+ peer_sock = godot_js_websocket_create(this, requested_url.utf8().get_data(), proto_string.utf8().get_data(), &_esws_on_connect, &_esws_on_message, &_esws_on_error, &_esws_on_close);
+ if (peer_sock == -1) {
return FAILED;
}
+ in_buffer.resize(nearest_shift(inbound_buffer_size), max_queued_packets);
+ packet_buffer.resize(inbound_buffer_size);
+ ready_state = STATE_CONNECTING;
+ return OK;
+}
+
+Error EMWSPeer::accept_stream(Ref<StreamPeer> p_stream) {
+ WARN_PRINT_ONCE("Acting as WebSocket server is not supported in Web platforms.");
+ return ERR_UNAVAILABLE;
+}
+
+Error EMWSPeer::_send(const uint8_t *p_buffer, int p_buffer_size, bool p_binary) {
+ ERR_FAIL_COND_V(outbound_buffer_size > 0 && (get_current_outbound_buffered_amount() + p_buffer_size >= outbound_buffer_size), ERR_OUT_OF_MEMORY);
+ if (godot_js_websocket_send(peer_sock, p_buffer, p_buffer_size, p_binary ? 1 : 0) != 0) {
+ return FAILED;
+ }
return OK;
}
+Error EMWSPeer::send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) {
+ return _send(p_buffer, p_buffer_size, p_mode == WRITE_MODE_BINARY);
+}
+
+Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+ return _send(p_buffer, p_buffer_size, true);
+}
+
Error EMWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- if (_in_buffer.packets_left() == 0) {
+ if (in_buffer.packets_left() == 0) {
return ERR_UNAVAILABLE;
}
int read = 0;
- Error err = _in_buffer.read_packet(_packet_buffer.ptrw(), _packet_buffer.size(), &_is_string, read);
+ Error err = in_buffer.read_packet(packet_buffer.ptrw(), packet_buffer.size(), &was_string, read);
ERR_FAIL_COND_V(err != OK, err);
- *r_buffer = _packet_buffer.ptr();
+ *r_buffer = packet_buffer.ptr();
r_buffer_size = read;
return OK;
}
int EMWSPeer::get_available_packet_count() const {
- return _in_buffer.packets_left();
+ return in_buffer.packets_left();
}
int EMWSPeer::get_current_outbound_buffered_amount() const {
@@ -93,20 +154,66 @@ int EMWSPeer::get_current_outbound_buffered_amount() const {
}
bool EMWSPeer::was_string_packet() const {
- return _is_string;
+ return was_string;
}
-bool EMWSPeer::is_connected_to_host() const {
- return peer_sock != -1;
+void EMWSPeer::_clear() {
+ if (peer_sock != -1) {
+ godot_js_websocket_destroy(peer_sock);
+ peer_sock = -1;
+ }
+ ready_state = STATE_CLOSED;
+ was_string = 0;
+ close_code = -1;
+ close_reason.clear();
+ selected_protocol.clear();
+ requested_url.clear();
+ in_buffer.clear();
+ packet_buffer.clear();
}
void EMWSPeer::close(int p_code, String p_reason) {
- if (peer_sock != -1) {
- godot_js_websocket_close(peer_sock, p_code, p_reason.utf8().get_data());
+ if (p_code < 0) {
+ if (peer_sock != -1) {
+ godot_js_websocket_destroy(peer_sock);
+ peer_sock = -1;
+ }
+ ready_state = STATE_CLOSED;
+ }
+ if (ready_state == STATE_CONNECTING || ready_state == STATE_OPEN) {
+ ready_state = STATE_CLOSING;
+ if (peer_sock != -1) {
+ godot_js_websocket_close(peer_sock, p_code, p_reason.utf8().get_data());
+ } else {
+ ready_state = STATE_CLOSED;
+ }
}
- _is_string = 0;
- _in_buffer.clear();
- peer_sock = -1;
+ in_buffer.clear();
+ packet_buffer.clear();
+}
+
+void EMWSPeer::poll() {
+ // Automatically polled by the navigator.
+}
+
+WebSocketPeer::State EMWSPeer::get_ready_state() const {
+ return ready_state;
+}
+
+int EMWSPeer::get_close_code() const {
+ return close_code;
+}
+
+String EMWSPeer::get_close_reason() const {
+ return close_reason;
+}
+
+String EMWSPeer::get_selected_protocol() const {
+ return selected_protocol;
+}
+
+String EMWSPeer::get_requested_url() const {
+ return requested_url;
}
IPAddress EMWSPeer::get_connected_host() const {
@@ -122,11 +229,10 @@ void EMWSPeer::set_no_delay(bool p_enabled) {
}
EMWSPeer::EMWSPeer() {
- close();
}
EMWSPeer::~EMWSPeer() {
- close();
+ _clear();
}
#endif // WEB_ENABLED
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index cdbc9212a5..322cc3b700 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -54,33 +54,53 @@ extern void godot_js_websocket_destroy(int p_id);
}
class EMWSPeer : public WebSocketPeer {
- GDCIIMPL(EMWSPeer, WebSocketPeer);
-
private:
int peer_sock = -1;
- WriteMode write_mode = WRITE_MODE_BINARY;
- Vector<uint8_t> _packet_buffer;
- PacketBuffer<uint8_t> _in_buffer;
- uint8_t _is_string = 0;
- int _out_buf_size = 0;
+ State ready_state = STATE_CLOSED;
+ Vector<uint8_t> packet_buffer;
+ PacketBuffer<uint8_t> in_buffer;
+ uint8_t was_string = 0;
+ int close_code = -1;
+ String close_reason;
+ String selected_protocol;
+ String requested_url;
+
+ static WebSocketPeer *_create() { return memnew(EMWSPeer); }
+ static void _esws_on_connect(void *obj, char *proto);
+ static void _esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string);
+ static void _esws_on_error(void *obj);
+ static void _esws_on_close(void *obj, int code, const char *reason, int was_clean);
+
+ void _clear();
+ Error _send(const uint8_t *p_buffer, int p_buffer_size, bool p_binary);
public:
- Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string);
- void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size);
+ static void initialize() { WebSocketPeer::_create = EMWSPeer::_create; }
+
+ // PacketPeer
virtual int get_available_packet_count() const override;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const override;
+ virtual int get_max_packet_size() const override { return packet_buffer.size(); };
+ // WebSocketPeer
+ virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) override;
+ virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) override;
+ virtual Error accept_stream(Ref<StreamPeer> p_stream) override;
virtual void close(int p_code = 1000, String p_reason = "") override;
- virtual bool is_connected_to_host() const override;
+ virtual void poll() override;
+
+ virtual State get_ready_state() const override;
+ virtual int get_close_code() const override;
+ virtual String get_close_reason() const override;
+ virtual int get_current_outbound_buffered_amount() const override;
+
virtual IPAddress get_connected_host() const override;
virtual uint16_t get_connected_port() const override;
+ virtual String get_selected_protocol() const override;
+ virtual String get_requested_url() const override;
- virtual WriteMode get_write_mode() const override;
- virtual void set_write_mode(WriteMode p_mode) override;
virtual bool was_string_packet() const override;
virtual void set_no_delay(bool p_enabled) override;
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index 7b4a164576..cd81dc43cd 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -41,32 +41,29 @@ private:
T info;
} _Packet;
- RingBuffer<_Packet> _packets;
+ Vector<_Packet> _packets;
+ int _queued = 0;
+ int _write_pos = 0;
+ int _read_pos = 0;
RingBuffer<uint8_t> _payload;
public:
Error write_packet(const uint8_t *p_payload, uint32_t p_size, const T *p_info) {
-#ifdef TOOLS_ENABLED
- // Verbose buffer warnings
- if (p_payload && _payload.space_left() < (int32_t)p_size) {
- ERR_PRINT("Buffer payload full! Dropping data.");
- ERR_FAIL_V(ERR_OUT_OF_MEMORY);
- }
- if (p_info && _packets.space_left() < 1) {
- ERR_PRINT("Too many packets in queue! Dropping data.");
- ERR_FAIL_V(ERR_OUT_OF_MEMORY);
- }
-#else
- ERR_FAIL_COND_V(p_payload && (uint32_t)_payload.space_left() < p_size, ERR_OUT_OF_MEMORY);
- ERR_FAIL_COND_V(p_info && _packets.space_left() < 1, ERR_OUT_OF_MEMORY);
-#endif
+ ERR_FAIL_COND_V_MSG(p_payload && (uint32_t)_payload.space_left() < p_size, ERR_OUT_OF_MEMORY, "Buffer payload full! Dropping data.");
+ ERR_FAIL_COND_V_MSG(p_info && _queued >= _packets.size(), ERR_OUT_OF_MEMORY, "Too many packets in queue! Dropping data.");
// If p_info is nullptr, only the payload is written
if (p_info) {
+ ERR_FAIL_COND_V(_write_pos > _packets.size(), ERR_OUT_OF_MEMORY);
_Packet p;
p.size = p_size;
- memcpy(&p.info, p_info, sizeof(T));
- _packets.write(p);
+ p.info = *p_info;
+ _packets.write[_write_pos] = p;
+ _queued += 1;
+ _write_pos++;
+ if (_write_pos >= _packets.size()) {
+ _write_pos = 0;
+ }
}
// If p_payload is nullptr, only the packet information is written.
@@ -78,9 +75,14 @@ public:
}
Error read_packet(uint8_t *r_payload, int p_bytes, T *r_info, int &r_read) {
- ERR_FAIL_COND_V(_packets.data_left() < 1, ERR_UNAVAILABLE);
- _Packet p;
- _packets.read(&p, 1);
+ ERR_FAIL_COND_V(_queued < 1, ERR_UNAVAILABLE);
+ _Packet p = _packets[_read_pos];
+ _read_pos += 1;
+ if (_read_pos >= _packets.size()) {
+ _read_pos = 0;
+ }
+ _queued -= 1;
+
ERR_FAIL_COND_V(_payload.data_left() < (int)p.size, ERR_BUG);
ERR_FAIL_COND_V(p_bytes < (int)p.size, ERR_OUT_OF_MEMORY);
@@ -90,22 +92,24 @@ public:
return OK;
}
- void discard_payload(int p_size) {
- _packets.decrease_write(p_size);
- }
-
- void resize(int p_pkt_shift, int p_buf_shift) {
- _packets.resize(p_pkt_shift);
+ void resize(int p_buf_shift, int p_max_packets) {
_payload.resize(p_buf_shift);
+ _packets.resize(p_max_packets);
+ _read_pos = 0;
+ _write_pos = 0;
+ _queued = 0;
}
int packets_left() const {
- return _packets.data_left();
+ return _queued;
}
void clear() {
_payload.resize(0);
_packets.resize(0);
+ _read_pos = 0;
+ _write_pos = 0;
+ _queued = 0;
}
PacketBuffer() {
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index faa7021b2f..c55a651ab0 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -31,18 +31,18 @@
#include "register_types.h"
#include "core/config/project_settings.h"
+#include "core/debugger/engine_debugger.h"
#include "core/error/error_macros.h"
-#include "websocket_client.h"
-#include "websocket_server.h"
+#include "websocket_multiplayer_peer.h"
+#include "websocket_peer.h"
+
+#include "remote_debugger_peer_websocket.h"
#ifdef WEB_ENABLED
-#include "emscripten.h"
-#include "emws_client.h"
#include "emws_peer.h"
#else
-#include "wsl_client.h"
-#include "wsl_server.h"
+#include "wsl_peer.h"
#endif
#ifdef TOOLS_ENABLED
@@ -58,20 +58,18 @@ static void _editor_init_callback() {
#endif
void initialize_websocket_module(ModuleInitializationLevel p_level) {
- if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_CORE) {
#ifdef WEB_ENABLED
- EMWSPeer::make_default();
- EMWSClient::make_default();
+ EMWSPeer::initialize();
#else
- WSLPeer::make_default();
- WSLClient::make_default();
- WSLServer::make_default();
+ WSLPeer::initialize();
#endif
- GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer);
- ClassDB::register_custom_instance_class<WebSocketServer>();
- ClassDB::register_custom_instance_class<WebSocketClient>();
+ GDREGISTER_CLASS(WebSocketMultiplayerPeer);
ClassDB::register_custom_instance_class<WebSocketPeer>();
+
+ EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create);
+ EngineDebugger::register_uri_handler("wss://", RemoteDebuggerPeerWebSocket::create);
}
#ifdef TOOLS_ENABLED
@@ -82,7 +80,10 @@ void initialize_websocket_module(ModuleInitializationLevel p_level) {
}
void uninitialize_websocket_module(ModuleInitializationLevel p_level) {
- if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
return;
}
+#ifndef WEB_ENABLED
+ WSLPeer::deinitialize();
+#endif
}
diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp
index f703873cbf..58adb76208 100644
--- a/modules/websocket/remote_debugger_peer_websocket.cpp
+++ b/modules/websocket/remote_debugger_peer_websocket.cpp
@@ -33,30 +33,39 @@
#include "core/config/project_settings.h"
Error RemoteDebuggerPeerWebSocket::connect_to_host(const String &p_uri) {
+ ws_peer = Ref<WebSocketPeer>(WebSocketPeer::create());
+ ERR_FAIL_COND_V(ws_peer.is_null(), ERR_BUG);
+
Vector<String> protocols;
protocols.push_back("binary"); // Compatibility for emscripten TCP-to-WebSocket.
- ws_client->connect_to_url(p_uri, protocols);
- ws_client->poll();
+ ws_peer->set_supported_protocols(protocols);
+ ws_peer->set_max_queued_packets(max_queued_messages);
+ ws_peer->set_inbound_buffer_size((1 << 23) - 1);
+ ws_peer->set_outbound_buffer_size((1 << 23) - 1);
+
+ Error err = ws_peer->connect_to_url(p_uri);
+ ERR_FAIL_COND_V(err != OK, err);
- if (ws_client->get_connection_status() == WebSocketClient::CONNECTION_DISCONNECTED) {
- ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(ws_client->get_connection_status()) + ".");
+ ws_peer->poll();
+ WebSocketPeer::State ready_state = ws_peer->get_ready_state();
+ if (ready_state != WebSocketPeer::STATE_CONNECTING && ready_state != WebSocketPeer::STATE_OPEN) {
+ ERR_PRINT(vformat("Remote Debugger: Unable to connect. State: %s.", ws_peer->get_ready_state()));
return FAILED;
}
- ws_peer = ws_client->get_peer(1);
-
return OK;
}
bool RemoteDebuggerPeerWebSocket::is_peer_connected() {
- return ws_peer.is_valid() && ws_peer->is_connected_to_host();
+ return ws_peer.is_valid() && (ws_peer->get_ready_state() == WebSocketPeer::STATE_OPEN || ws_peer->get_ready_state() == WebSocketPeer::STATE_CONNECTING);
}
void RemoteDebuggerPeerWebSocket::poll() {
- ws_client->poll();
+ ERR_FAIL_COND(ws_peer.is_null());
+ ws_peer->poll();
- while (ws_peer->is_connected_to_host() && ws_peer->get_available_packet_count() > 0 && in_queue.size() < max_queued_messages) {
+ while (ws_peer->get_ready_state() == WebSocketPeer::STATE_OPEN && ws_peer->get_available_packet_count() > 0 && in_queue.size() < max_queued_messages) {
Variant var;
Error err = ws_peer->get_var(var);
ERR_CONTINUE(err != OK);
@@ -64,7 +73,7 @@ void RemoteDebuggerPeerWebSocket::poll() {
in_queue.push_back(var);
}
- while (ws_peer->is_connected_to_host() && out_queue.size() > 0) {
+ while (ws_peer->get_ready_state() == WebSocketPeer::STATE_OPEN && out_queue.size() > 0) {
Array var = out_queue[0];
Error err = ws_peer->put_var(var);
ERR_BREAK(err != OK); // Peer buffer full?
@@ -73,7 +82,8 @@ void RemoteDebuggerPeerWebSocket::poll() {
}
int RemoteDebuggerPeerWebSocket::get_max_message_size() const {
- return 8 << 20; // 8 Mib
+ ERR_FAIL_COND_V(ws_peer.is_null(), 0);
+ return ws_peer->get_max_packet_size();
}
bool RemoteDebuggerPeerWebSocket::has_message() {
@@ -99,7 +109,6 @@ void RemoteDebuggerPeerWebSocket::close() {
if (ws_peer.is_valid()) {
ws_peer.unref();
}
- ws_client->disconnect_from_host();
}
bool RemoteDebuggerPeerWebSocket::can_block() const {
@@ -111,14 +120,13 @@ bool RemoteDebuggerPeerWebSocket::can_block() const {
}
RemoteDebuggerPeerWebSocket::RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer) {
-#ifdef WEB_ENABLED
- ws_client = Ref<WebSocketClient>(memnew(EMWSClient));
-#else
- ws_client = Ref<WebSocketClient>(memnew(WSLClient));
-#endif
max_queued_messages = (int)GLOBAL_GET("network/limits/debugger/max_queued_messages");
- ws_client->set_buffers(8192, max_queued_messages, 8192, max_queued_messages);
ws_peer = p_peer;
+ if (ws_peer.is_valid()) {
+ ws_peer->set_max_queued_packets(max_queued_messages);
+ ws_peer->set_inbound_buffer_size((1 << 23) - 1);
+ ws_peer->set_outbound_buffer_size((1 << 23) - 1);
+ }
}
RemoteDebuggerPeer *RemoteDebuggerPeerWebSocket::create(const String &p_uri) {
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index 0292de68ad..4d496ae891 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -33,14 +33,9 @@
#include "core/debugger/remote_debugger_peer.h"
-#ifdef WEB_ENABLED
-#include "emws_client.h"
-#else
-#include "wsl_client.h"
-#endif
+#include "websocket_peer.h"
class RemoteDebuggerPeerWebSocket : public RemoteDebuggerPeer {
- Ref<WebSocketClient> ws_client;
Ref<WebSocketPeer> ws_peer;
List<Array> in_queue;
List<Array> out_queue;
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
deleted file mode 100644
index 0b2d5d1918..0000000000
--- a/modules/websocket/websocket_client.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*************************************************************************/
-/* websocket_client.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 "websocket_client.h"
-
-GDCINULL(WebSocketClient);
-
-WebSocketClient::WebSocketClient() {
-}
-
-WebSocketClient::~WebSocketClient() {
-}
-
-Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_protocols, bool gd_mp_api, const Vector<String> p_custom_headers) {
- _is_multiplayer = gd_mp_api;
-
- String host = p_url;
- String path;
- String scheme;
- int port = 0;
- Error err = p_url.parse_url(scheme, host, port, path);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url);
-
- bool tls = false;
- if (scheme == "wss://") {
- tls = true;
- }
- if (port == 0) {
- port = tls ? 443 : 80;
- }
- if (path.is_empty()) {
- path = "/";
- }
- return connect_to_host(host, path, port, tls, p_protocols, p_custom_headers);
-}
-
-void WebSocketClient::set_verify_tls_enabled(bool p_verify_tls) {
- verify_tls = p_verify_tls;
-}
-
-bool WebSocketClient::is_verify_tls_enabled() const {
- return verify_tls;
-}
-
-Ref<X509Certificate> WebSocketClient::get_trusted_tls_certificate() const {
- return tls_cert;
-}
-
-void WebSocketClient::set_trusted_tls_certificate(Ref<X509Certificate> p_cert) {
- ERR_FAIL_COND(get_connection_status() != CONNECTION_DISCONNECTED);
- tls_cert = p_cert;
-}
-
-bool WebSocketClient::is_server() const {
- return false;
-}
-
-void WebSocketClient::_on_peer_packet() {
- if (_is_multiplayer) {
- _process_multiplayer(get_peer(1), 1);
- } else {
- emit_signal(SNAME("data_received"));
- }
-}
-
-void WebSocketClient::_on_connect(String p_protocol) {
- if (_is_multiplayer) {
- // need to wait for ID confirmation...
- } else {
- emit_signal(SNAME("connection_established"), p_protocol);
- }
-}
-
-void WebSocketClient::_on_close_request(int p_code, String p_reason) {
- emit_signal(SNAME("server_close_request"), p_code, p_reason);
-}
-
-void WebSocketClient::_on_disconnect(bool p_was_clean) {
- if (_is_multiplayer) {
- emit_signal(SNAME("connection_failed"));
- } else {
- emit_signal(SNAME("connection_closed"), p_was_clean);
- }
-}
-
-void WebSocketClient::_on_error() {
- if (_is_multiplayer) {
- emit_signal(SNAME("connection_failed"));
- } else {
- emit_signal(SNAME("connection_error"));
- }
-}
-
-void WebSocketClient::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_to_url", "url", "protocols", "gd_mp_api", "custom_headers"), &WebSocketClient::connect_to_url, DEFVAL(Vector<String>()), DEFVAL(false), DEFVAL(Vector<String>()));
- ClassDB::bind_method(D_METHOD("disconnect_from_host", "code", "reason"), &WebSocketClient::disconnect_from_host, DEFVAL(1000), DEFVAL(""));
- ClassDB::bind_method(D_METHOD("get_connected_host"), &WebSocketClient::get_connected_host);
- ClassDB::bind_method(D_METHOD("get_connected_port"), &WebSocketClient::get_connected_port);
- ClassDB::bind_method(D_METHOD("set_verify_tls_enabled", "enabled"), &WebSocketClient::set_verify_tls_enabled);
- ClassDB::bind_method(D_METHOD("is_verify_tls_enabled"), &WebSocketClient::is_verify_tls_enabled);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_tls", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_verify_tls_enabled", "is_verify_tls_enabled");
-
- ClassDB::bind_method(D_METHOD("get_trusted_tls_certificate"), &WebSocketClient::get_trusted_tls_certificate);
- ClassDB::bind_method(D_METHOD("set_trusted_tls_certificate", "cert"), &WebSocketClient::set_trusted_tls_certificate);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_tls_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_trusted_tls_certificate", "get_trusted_tls_certificate");
-
- ADD_SIGNAL(MethodInfo("data_received"));
- ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol")));
- ADD_SIGNAL(MethodInfo("server_close_request", PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason")));
- ADD_SIGNAL(MethodInfo("connection_closed", PropertyInfo(Variant::BOOL, "was_clean_close")));
- ADD_SIGNAL(MethodInfo("connection_error"));
-}
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 7a3bbf1c47..827c618e4e 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -33,72 +33,128 @@
#include "core/os/os.h"
WebSocketMultiplayerPeer::WebSocketMultiplayerPeer() {
+ peer_config = Ref<WebSocketPeer>(WebSocketPeer::create());
}
WebSocketMultiplayerPeer::~WebSocketMultiplayerPeer() {
_clear();
}
+Ref<WebSocketPeer> WebSocketMultiplayerPeer::_create_peer() {
+ Ref<WebSocketPeer> peer = Ref<WebSocketPeer>(WebSocketPeer::create());
+ peer->set_supported_protocols(get_supported_protocols());
+ peer->set_handshake_headers(get_handshake_headers());
+ peer->set_inbound_buffer_size(get_inbound_buffer_size());
+ peer->set_outbound_buffer_size(get_outbound_buffer_size());
+ peer->set_max_queued_packets(get_max_queued_packets());
+ return peer;
+}
+
void WebSocketMultiplayerPeer::_clear() {
- _peer_map.clear();
- if (_current_packet.data != nullptr) {
- memfree(_current_packet.data);
+ connection_status = CONNECTION_DISCONNECTED;
+ unique_id = 0;
+ peers_map.clear();
+ use_tls = false;
+ tcp_server.unref();
+ pending_peers.clear();
+ tls_certificate.unref();
+ tls_key.unref();
+ if (current_packet.data != nullptr) {
+ memfree(current_packet.data);
+ current_packet.data = nullptr;
}
- for (Packet &E : _incoming_packets) {
+ for (Packet &E : incoming_packets) {
memfree(E.data);
E.data = nullptr;
}
- _incoming_packets.clear();
+ incoming_packets.clear();
}
void WebSocketMultiplayerPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_buffers", "input_buffer_size_kb", "input_max_packets", "output_buffer_size_kb", "output_max_packets"), &WebSocketMultiplayerPeer::set_buffers);
+ ClassDB::bind_method(D_METHOD("create_client", "url", "verify_tls", "tls_certificate"), &WebSocketMultiplayerPeer::create_client, DEFVAL(true), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("create_server", "port", "bind_address", "tls_key", "tls_certificate"), &WebSocketMultiplayerPeer::create_server, DEFVAL("*"), DEFVAL(Ref<CryptoKey>()), DEFVAL(Ref<X509Certificate>()));
+
ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebSocketMultiplayerPeer::get_peer);
+ ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketMultiplayerPeer::get_peer_address);
+ ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketMultiplayerPeer::get_peer_port);
+
+ ClassDB::bind_method(D_METHOD("get_supported_protocols"), &WebSocketMultiplayerPeer::get_supported_protocols);
+ ClassDB::bind_method(D_METHOD("set_supported_protocols", "protocols"), &WebSocketMultiplayerPeer::set_supported_protocols);
+
+ ClassDB::bind_method(D_METHOD("get_handshake_headers"), &WebSocketMultiplayerPeer::get_handshake_headers);
+ ClassDB::bind_method(D_METHOD("set_handshake_headers", "protocols"), &WebSocketMultiplayerPeer::set_handshake_headers);
+
+ ClassDB::bind_method(D_METHOD("get_inbound_buffer_size"), &WebSocketMultiplayerPeer::get_inbound_buffer_size);
+ ClassDB::bind_method(D_METHOD("set_inbound_buffer_size", "buffer_size"), &WebSocketMultiplayerPeer::set_inbound_buffer_size);
+
+ ClassDB::bind_method(D_METHOD("get_outbound_buffer_size"), &WebSocketMultiplayerPeer::get_outbound_buffer_size);
+ ClassDB::bind_method(D_METHOD("set_outbound_buffer_size", "buffer_size"), &WebSocketMultiplayerPeer::set_outbound_buffer_size);
+
+ ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketMultiplayerPeer::get_handshake_timeout);
+ ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketMultiplayerPeer::set_handshake_timeout);
+
+ ClassDB::bind_method(D_METHOD("set_max_queued_packets", "max_queued_packets"), &WebSocketMultiplayerPeer::set_max_queued_packets);
+ ClassDB::bind_method(D_METHOD("get_max_queued_packets"), &WebSocketMultiplayerPeer::get_max_queued_packets);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "supported_protocols"), "set_supported_protocols", "get_supported_protocols");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "handshake_headers"), "set_handshake_headers", "get_handshake_headers");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "inbound_buffer_size"), "set_inbound_buffer_size", "get_inbound_buffer_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "outbound_buffer_size"), "set_outbound_buffer_size", "get_outbound_buffer_size");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout");
- ADD_SIGNAL(MethodInfo("peer_packet", PropertyInfo(Variant::INT, "peer_source")));
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_queued_packets"), "set_max_queued_packets", "get_max_queued_packets");
}
//
// PacketPeer
//
int WebSocketMultiplayerPeer::get_available_packet_count() const {
- ERR_FAIL_COND_V_MSG(!_is_multiplayer, 0, "Please use get_peer(ID).get_available_packet_count to get available packet count from peers when not using the MultiplayerAPI.");
-
- return _incoming_packets.size();
+ return incoming_packets.size();
}
Error WebSocketMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).get_packet/var to communicate with peers when not using the MultiplayerAPI.");
+ ERR_FAIL_COND_V(get_connection_status() != CONNECTION_CONNECTED, ERR_UNCONFIGURED);
r_buffer_size = 0;
- if (_current_packet.data != nullptr) {
- memfree(_current_packet.data);
- _current_packet.data = nullptr;
+ if (current_packet.data != nullptr) {
+ memfree(current_packet.data);
+ current_packet.data = nullptr;
}
- ERR_FAIL_COND_V(_incoming_packets.size() == 0, ERR_UNAVAILABLE);
+ ERR_FAIL_COND_V(incoming_packets.size() == 0, ERR_UNAVAILABLE);
- _current_packet = _incoming_packets.front()->get();
- _incoming_packets.pop_front();
+ current_packet = incoming_packets.front()->get();
+ incoming_packets.pop_front();
- *r_buffer = _current_packet.data;
- r_buffer_size = _current_packet.size;
+ *r_buffer = current_packet.data;
+ r_buffer_size = current_packet.size;
return OK;
}
Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V_MSG(!_is_multiplayer, ERR_UNCONFIGURED, "Please use get_peer(ID).put_packet/var to communicate with peers when not using the MultiplayerAPI.");
-
- Vector<uint8_t> buffer = _make_pkt(SYS_NONE, get_unique_id(), _target_peer, p_buffer, p_buffer_size);
+ ERR_FAIL_COND_V(get_connection_status() != CONNECTION_CONNECTED, ERR_UNCONFIGURED);
if (is_server()) {
- return _server_relay(1, _target_peer, &(buffer.ptr()[0]), buffer.size());
+ if (target_peer > 0) {
+ ERR_FAIL_COND_V_MSG(!peers_map.has(target_peer), ERR_INVALID_PARAMETER, "Peer not found: " + itos(target_peer));
+ get_peer(target_peer)->put_packet(p_buffer, p_buffer_size);
+ } else {
+ for (KeyValue<int, Ref<WebSocketPeer>> &E : peers_map) {
+ if (target_peer && -target_peer == E.key) {
+ continue; // Excluded.
+ }
+ E.value->put_packet(p_buffer, p_buffer_size);
+ }
+ }
+ return OK;
} else {
- return get_peer(1)->put_packet(&(buffer.ptr()[0]), buffer.size());
+ return get_peer(1)->put_packet(p_buffer, p_buffer_size);
}
}
@@ -106,185 +162,341 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer
// MultiplayerPeer
//
void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) {
- _target_peer = p_target_peer;
+ target_peer = p_target_peer;
}
int WebSocketMultiplayerPeer::get_packet_peer() const {
- ERR_FAIL_COND_V_MSG(!_is_multiplayer, 1, "This function is not available when not using the MultiplayerAPI.");
- ERR_FAIL_COND_V(_incoming_packets.size() == 0, 1);
+ ERR_FAIL_COND_V(incoming_packets.size() == 0, 1);
- return _incoming_packets.front()->get().source;
+ return incoming_packets.front()->get().source;
}
int WebSocketMultiplayerPeer::get_unique_id() const {
- return _peer_id;
+ return unique_id;
}
-void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) {
- ERR_FAIL_COND(!p_peer.is_valid());
- ERR_FAIL_COND(!p_peer->is_connected_to_host());
-
- Vector<uint8_t> message = _make_pkt(p_type, 1, 0, (uint8_t *)&p_peer_id, 4);
- p_peer->put_packet(&(message.ptr()[0]), message.size());
+int WebSocketMultiplayerPeer::get_max_packet_size() const {
+ return get_outbound_buffer_size() - PROTO_SIZE;
}
-Vector<uint8_t> WebSocketMultiplayerPeer::_make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size) {
- Vector<uint8_t> out;
- out.resize(PROTO_SIZE + p_data_size);
-
- uint8_t *w = out.ptrw();
- memcpy(&w[0], &p_type, 1);
- memcpy(&w[1], &p_from, 4);
- memcpy(&w[5], &p_to, 4);
- memcpy(&w[PROTO_SIZE], p_data, p_data_size);
-
- return out;
+Error WebSocketMultiplayerPeer::create_server(int p_port, IPAddress p_bind_ip, Ref<CryptoKey> p_tls_key, Ref<X509Certificate> p_tls_certificate) {
+ ERR_FAIL_COND_V(get_connection_status() != CONNECTION_DISCONNECTED, ERR_ALREADY_IN_USE);
+ _clear();
+ tcp_server.instantiate();
+ Error err = tcp_server->listen(p_port, p_bind_ip);
+ if (err != OK) {
+ tcp_server.unref();
+ return err;
+ }
+ unique_id = 1;
+ connection_status = CONNECTION_CONNECTED;
+ // TLS config
+ tls_key = p_tls_key;
+ tls_certificate = p_tls_certificate;
+ if (tls_key.is_valid() && tls_certificate.is_valid()) {
+ use_tls = true;
+ }
+ return OK;
}
-void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
- // First of all, confirm the ID!
- _send_sys(get_peer(p_peer_id), SYS_ID, p_peer_id);
+Error WebSocketMultiplayerPeer::create_client(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate) {
+ ERR_FAIL_COND_V(get_connection_status() != CONNECTION_DISCONNECTED, ERR_ALREADY_IN_USE);
+ _clear();
+ Ref<WebSocketPeer> peer = _create_peer();
+ Error err = peer->connect_to_url(p_url, p_verify_tls, p_tls_certificate);
+ if (err != OK) {
+ return err;
+ }
+ PendingPeer pending;
+ pending.time = OS::get_singleton()->get_ticks_msec();
+ pending_peers[1] = pending;
+ peers_map[1] = peer;
+ connection_status = CONNECTION_CONNECTING;
+ return OK;
+}
- // Then send the server peer (which will trigger connection_succeded in client)
- _send_sys(get_peer(p_peer_id), SYS_ADD, 1);
+bool WebSocketMultiplayerPeer::is_server() const {
+ return tcp_server.is_valid();
+}
- for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- int32_t id = E.key;
- if (p_peer_id == id) {
- continue; // Skip the newly added peer (already confirmed)
+void WebSocketMultiplayerPeer::_poll_client() {
+ ERR_FAIL_COND(connection_status == CONNECTION_DISCONNECTED); // Bug.
+ ERR_FAIL_COND(!peers_map.has(1) || peers_map[1].is_null()); // Bug.
+ Ref<WebSocketPeer> peer = peers_map[1];
+ peer->poll(); // Update state and fetch packets.
+ WebSocketPeer::State ready_state = peer->get_ready_state();
+ if (ready_state == WebSocketPeer::STATE_OPEN) {
+ if (connection_status == CONNECTION_CONNECTING) {
+ if (peer->get_available_packet_count() > 0) {
+ const uint8_t *in_buffer;
+ int size = 0;
+ Error err = peer->get_packet(&in_buffer, size);
+ if (err != OK || size != 4) {
+ peer->close(); // Will cause connection error on next poll.
+ ERR_FAIL_MSG("Invalid ID received from server");
+ }
+ unique_id = *((int32_t *)in_buffer);
+ if (unique_id < 2) {
+ peer->close(); // Will cause connection error on next poll.
+ ERR_FAIL_MSG("Invalid ID received from server");
+ }
+ connection_status = CONNECTION_CONNECTED;
+ emit_signal("peer_connected", 1);
+ emit_signal("connection_succeeded");
+ } else {
+ return; // Still waiting for an ID.
+ }
}
-
- // Send new peer to others
- _send_sys(get_peer(id), SYS_ADD, p_peer_id);
- // Send others to new peer
- _send_sys(get_peer(p_peer_id), SYS_ADD, id);
+ int pkts = peer->get_available_packet_count();
+ while (pkts > 0 && peer->get_ready_state() == WebSocketPeer::STATE_OPEN) {
+ const uint8_t *in_buffer;
+ int size = 0;
+ Error err = peer->get_packet(&in_buffer, size);
+ ERR_FAIL_COND(err != OK);
+ ERR_FAIL_COND(size <= 0);
+ Packet packet;
+ packet.data = (uint8_t *)memalloc(size);
+ memcpy(packet.data, in_buffer, size);
+ packet.size = size;
+ packet.source = 1;
+ incoming_packets.push_back(packet);
+ pkts--;
+ }
+ } else if (peer->get_ready_state() == WebSocketPeer::STATE_CLOSED) {
+ if (connection_status == CONNECTION_CONNECTED) {
+ emit_signal(SNAME("server_disconnected"));
+ } else {
+ emit_signal(SNAME("connection_failed"));
+ }
+ _clear();
+ return;
}
-}
-
-void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
- for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- int32_t id = E.key;
- if (p_peer_id != id) {
- _send_sys(get_peer(id), SYS_DEL, p_peer_id);
+ if (connection_status == CONNECTION_CONNECTING) {
+ // Still connecting
+ ERR_FAIL_COND(!pending_peers.has(1)); // Bug.
+ if (OS::get_singleton()->get_ticks_msec() - pending_peers[1].time > handshake_timeout) {
+ print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", handshake_timeout * 0.001));
+ emit_signal(SNAME("connection_failed"));
+ _clear();
+ return;
}
}
}
-void WebSocketMultiplayerPeer::_store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size) {
- Packet packet;
- packet.data = (uint8_t *)memalloc(p_data_size);
- packet.size = p_data_size;
- packet.source = p_source;
- packet.destination = p_dest;
- memcpy(packet.data, &p_data[PROTO_SIZE], p_data_size);
- _incoming_packets.push_back(packet);
- emit_signal(SNAME("peer_packet"), p_source);
-}
+void WebSocketMultiplayerPeer::_poll_server() {
+ ERR_FAIL_COND(connection_status != CONNECTION_CONNECTED); // Bug.
+ ERR_FAIL_COND(tcp_server.is_null() || !tcp_server->is_listening()); // Bug.
+
+ // Accept new connections.
+ if (!is_refusing_new_connections() && tcp_server->is_connection_available()) {
+ PendingPeer peer;
+ peer.time = OS::get_singleton()->get_ticks_msec();
+ peer.tcp = tcp_server->take_connection();
+ peer.connection = peer.tcp;
+ pending_peers[generate_unique_id()] = peer;
+ }
-Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size) {
- if (p_to == 1) {
- return OK; // Will not send to self
+ // Process pending peers.
+ HashSet<int> to_remove;
+ for (KeyValue<int, PendingPeer> &E : pending_peers) {
+ PendingPeer &peer = E.value;
+ int id = E.key;
- } else if (p_to == 0) {
- for (KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- if (E.key != p_from) {
- E.value->put_packet(p_buffer, p_buffer_size);
- }
+ if (OS::get_singleton()->get_ticks_msec() - peer.time > handshake_timeout) {
+ print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", handshake_timeout * 0.001));
+ to_remove.insert(id);
+ continue;
}
- return OK; // Sent to all but sender
- } else if (p_to < 0) {
- for (KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- if (E.key != p_from && E.key != -p_to) {
- E.value->put_packet(p_buffer, p_buffer_size);
+ if (peer.ws.is_valid()) {
+ peer.ws->poll();
+ WebSocketPeer::State state = peer.ws->get_ready_state();
+ if (state == WebSocketPeer::STATE_OPEN) {
+ // Connected.
+ to_remove.insert(id);
+ if (is_refusing_new_connections()) {
+ // The user does not want new connections, dropping it.
+ continue;
+ }
+ int32_t peer_id = id;
+ Error err = peer.ws->put_packet((const uint8_t *)&peer_id, sizeof(peer_id));
+ if (err == OK) {
+ peers_map[id] = peer.ws;
+ emit_signal("peer_connected", id);
+ } else {
+ ERR_PRINT("Failed to send ID to newly connected peer.");
+ }
+ continue;
+ } else if (state == WebSocketPeer::STATE_CONNECTING) {
+ continue; // Still connecting.
+ }
+ to_remove.insert(id); // Error.
+ continue;
+ }
+ if (peer.tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ to_remove.insert(id); // Error.
+ continue;
+ }
+ if (!use_tls) {
+ peer.ws = _create_peer();
+ peer.ws->accept_stream(peer.tcp);
+ continue;
+ } else {
+ if (peer.connection == peer.tcp) {
+ Ref<StreamPeerTLS> tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
+ Error err = tls->accept_stream(peer.tcp, tls_key, tls_certificate);
+ if (err != OK) {
+ to_remove.insert(id);
+ continue;
+ }
+ }
+ Ref<StreamPeerTLS> tls = static_cast<Ref<StreamPeerTLS>>(peer.connection);
+ tls->poll();
+ if (tls->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
+ peer.ws = _create_peer();
+ peer.ws->accept_stream(peer.connection);
+ continue;
+ } else if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
+ // Still connecting.
+ continue;
+ } else {
+ // Error
+ to_remove.insert(id);
}
}
- return OK; // Sent to all but sender and excluded
+ }
- } else {
- ERR_FAIL_COND_V(p_to == p_from, FAILED);
+ // Remove disconnected pending peers.
+ for (const int &pid : to_remove) {
+ pending_peers.erase(pid);
+ }
+ to_remove.clear();
+
+ // Process connected peers.
+ for (KeyValue<int, Ref<WebSocketPeer>> &E : peers_map) {
+ Ref<WebSocketPeer> ws = E.value;
+ int id = E.key;
+ ws->poll();
+ if (ws->get_ready_state() != WebSocketPeer::STATE_OPEN) {
+ to_remove.insert(id); // Disconnected.
+ continue;
+ }
+ // Fetch packets
+ int pkts = ws->get_available_packet_count();
+ while (pkts > 0 && ws->get_ready_state() == WebSocketPeer::STATE_OPEN) {
+ const uint8_t *in_buffer;
+ int size = 0;
+ Error err = ws->get_packet(&in_buffer, size);
+ if (err != OK || size <= 0) {
+ break;
+ }
+ Packet packet;
+ packet.data = (uint8_t *)memalloc(size);
+ memcpy(packet.data, in_buffer, size);
+ packet.size = size;
+ packet.source = E.key;
+ incoming_packets.push_back(packet);
+ pkts--;
+ }
+ }
- Ref<WebSocketPeer> peer_to = get_peer(p_to);
- ERR_FAIL_COND_V(peer_to.is_null(), FAILED);
+ // Remove disconnected peers.
+ for (const int &pid : to_remove) {
+ emit_signal(SNAME("peer_disconnected"), pid);
+ peers_map.erase(pid);
+ }
+}
- return peer_to->put_packet(p_buffer, p_buffer_size); // Sending to specific peer
+void WebSocketMultiplayerPeer::poll() {
+ if (connection_status == CONNECTION_DISCONNECTED) {
+ return;
+ }
+ if (is_server()) {
+ _poll_server();
+ } else {
+ _poll_client();
}
}
-void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id) {
- ERR_FAIL_COND(!p_peer.is_valid());
+MultiplayerPeer::ConnectionStatus WebSocketMultiplayerPeer::get_connection_status() const {
+ return connection_status;
+}
- const uint8_t *in_buffer;
- int size = 0;
- int data_size = 0;
+Ref<WebSocketPeer> WebSocketMultiplayerPeer::get_peer(int p_id) const {
+ ERR_FAIL_COND_V(!peers_map.has(p_id), Ref<WebSocketPeer>());
+ return peers_map[p_id];
+}
- Error err = p_peer->get_packet(&in_buffer, size);
+void WebSocketMultiplayerPeer::set_supported_protocols(const Vector<String> &p_protocols) {
+ peer_config->set_supported_protocols(p_protocols);
+}
- ERR_FAIL_COND(err != OK);
- ERR_FAIL_COND(size < PROTO_SIZE);
+Vector<String> WebSocketMultiplayerPeer::get_supported_protocols() const {
+ return peer_config->get_supported_protocols();
+}
- data_size = size - PROTO_SIZE;
+void WebSocketMultiplayerPeer::set_handshake_headers(const Vector<String> &p_headers) {
+ peer_config->set_handshake_headers(p_headers);
+}
- uint8_t type = 0;
- uint32_t from = 0;
- int32_t to = 0;
- memcpy(&type, in_buffer, 1);
- memcpy(&from, &in_buffer[1], 4);
- memcpy(&to, &in_buffer[5], 4);
+Vector<String> WebSocketMultiplayerPeer::get_handshake_headers() const {
+ return peer_config->get_handshake_headers();
+}
- if (is_server()) { // Server can resend
+void WebSocketMultiplayerPeer::set_outbound_buffer_size(int p_buffer_size) {
+ peer_config->set_outbound_buffer_size(p_buffer_size);
+}
- ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages
- ERR_FAIL_COND(from != p_peer_id); // Someone is cheating
+int WebSocketMultiplayerPeer::get_outbound_buffer_size() const {
+ return peer_config->get_outbound_buffer_size();
+}
- if (to == 1) { // This is for the server
+void WebSocketMultiplayerPeer::set_inbound_buffer_size(int p_buffer_size) {
+ peer_config->set_inbound_buffer_size(p_buffer_size);
+}
- _store_pkt(from, to, in_buffer, data_size);
+int WebSocketMultiplayerPeer::get_inbound_buffer_size() const {
+ return peer_config->get_inbound_buffer_size();
+}
- } else if (to == 0) {
- // Broadcast, for us too
- _store_pkt(from, to, in_buffer, data_size);
+void WebSocketMultiplayerPeer::set_max_queued_packets(int p_max_queued_packets) {
+ peer_config->set_max_queued_packets(p_max_queued_packets);
+}
- } else if (to < 0) {
- // All but one, for us if not excluded
- if (_peer_id != -(int32_t)p_peer_id) {
- _store_pkt(from, to, in_buffer, data_size);
- }
- }
- // Relay if needed (i.e. "to" includes a peer that is not the server)
- _server_relay(from, to, in_buffer, size);
+int WebSocketMultiplayerPeer::get_max_queued_packets() const {
+ return peer_config->get_max_queued_packets();
+}
- } else {
- if (type == SYS_NONE) { // Payload message
+float WebSocketMultiplayerPeer::get_handshake_timeout() const {
+ return handshake_timeout / 1000.0;
+}
- _store_pkt(from, to, in_buffer, data_size);
- return;
- }
+void WebSocketMultiplayerPeer::set_handshake_timeout(float p_timeout) {
+ ERR_FAIL_COND(p_timeout <= 0.0);
+ handshake_timeout = p_timeout * 1000;
+}
- // System message
- ERR_FAIL_COND(data_size < 4);
- int id = 0;
- memcpy(&id, &in_buffer[PROTO_SIZE], 4);
-
- switch (type) {
- case SYS_ADD: // Add peer
- _peer_map[id] = Ref<WebSocketPeer>();
- emit_signal(SNAME("peer_connected"), id);
- if (id == 1) { // We just connected to the server
- emit_signal(SNAME("connection_succeeded"));
- }
- break;
+IPAddress WebSocketMultiplayerPeer::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V(!peers_map.has(p_peer_id), IPAddress());
+ return peers_map[p_peer_id]->get_connected_host();
+}
- case SYS_DEL: // Remove peer
- _peer_map.erase(id);
- emit_signal(SNAME("peer_disconnected"), id);
- break;
- case SYS_ID: // Hello, server assigned ID
- _peer_id = id;
- break;
- default:
- ERR_FAIL_MSG("Invalid multiplayer message.");
- break;
+int WebSocketMultiplayerPeer::get_peer_port(int p_peer_id) const {
+ ERR_FAIL_COND_V(!peers_map.has(p_peer_id), 0);
+ return peers_map[p_peer_id]->get_connected_port();
+}
+
+void WebSocketMultiplayerPeer::disconnect_peer(int p_peer_id, bool p_force) {
+ ERR_FAIL_COND(!peers_map.has(p_peer_id));
+ peers_map[p_peer_id]->close();
+ if (p_force) {
+ peers_map.erase(p_peer_id);
+ if (!is_server()) {
+ _clear();
}
}
}
+
+void WebSocketMultiplayerPeer::close() {
+ _clear();
+}
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index 3259e78b3b..78a58162ab 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -32,6 +32,8 @@
#define WEBSOCKET_MULTIPLAYER_PEER_H
#include "core/error/error_list.h"
+#include "core/io/stream_peer_tls.h"
+#include "core/io/tcp_server.h"
#include "core/templates/list.h"
#include "scene/main/multiplayer_peer.h"
#include "websocket_peer.h"
@@ -40,9 +42,7 @@ class WebSocketMultiplayerPeer : public MultiplayerPeer {
GDCLASS(WebSocketMultiplayerPeer, MultiplayerPeer);
private:
- Vector<uint8_t> _make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size);
- void _store_pkt(int32_t p_source, int32_t p_dest, const uint8_t *p_data, uint32_t p_data_size);
- Error _server_relay(int32_t p_from, int32_t p_to, const uint8_t *p_buffer, uint32_t p_buffer_size);
+ Ref<WebSocketPeer> _create_peer();
protected:
enum {
@@ -56,30 +56,56 @@ protected:
struct Packet {
int source = 0;
- int destination = 0;
uint8_t *data = nullptr;
uint32_t size = 0;
};
- List<Packet> _incoming_packets;
- HashMap<int, Ref<WebSocketPeer>> _peer_map;
- Packet _current_packet;
+ struct PendingPeer {
+ uint64_t time = 0;
+ Ref<StreamPeerTCP> tcp;
+ Ref<StreamPeer> connection;
+ Ref<WebSocketPeer> ws;
+ };
+
+ uint64_t handshake_timeout = 3000;
+ Ref<WebSocketPeer> peer_config;
+ HashMap<int, PendingPeer> pending_peers;
+ Ref<TCPServer> tcp_server;
+ bool use_tls = false;
+ Ref<X509Certificate> tls_certificate;
+ Ref<CryptoKey> tls_key;
+
+ ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
+
+ List<Packet> incoming_packets;
+ HashMap<int, Ref<WebSocketPeer>> peers_map;
+ Packet current_packet;
- bool _is_multiplayer = false;
- int _target_peer = 0;
- int _peer_id = 0;
+ int target_peer = 0;
+ int unique_id = 0;
static void _bind_methods();
- void _send_add(int32_t p_peer_id);
- void _send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id);
- void _send_del(int32_t p_peer_id);
+ void _poll_client();
+ void _poll_server();
+ void _clear();
public:
/* MultiplayerPeer */
- void set_target_peer(int p_target_peer) override;
- int get_packet_peer() const override;
- int get_unique_id() const override;
+ virtual void set_target_peer(int p_target_peer) override;
+ virtual int get_packet_peer() const override;
+ virtual int get_packet_channel() const override { return 0; }
+ virtual TransferMode get_packet_mode() const override { return TRANSFER_MODE_RELIABLE; }
+ virtual int get_unique_id() const override;
+ virtual bool is_server_relay_supported() const override { return true; }
+
+ virtual int get_max_packet_size() const override;
+ virtual bool is_server() const override;
+ virtual void poll() override;
+ virtual void close() override;
+ virtual void disconnect_peer(int p_peer_id, bool p_force = false) override;
+
+ virtual ConnectionStatus get_connection_status() const override;
/* PacketPeer */
virtual int get_available_packet_count() const override;
@@ -87,11 +113,31 @@ public:
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
/* WebSocketPeer */
- virtual Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) = 0;
- virtual Ref<WebSocketPeer> get_peer(int p_peer_id) const = 0;
+ virtual Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- void _process_multiplayer(Ref<WebSocketPeer> p_peer, uint32_t p_peer_id);
- void _clear();
+ Error create_client(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_tls_certificate);
+ Error create_server(int p_port, IPAddress p_bind_ip, Ref<CryptoKey> p_tls_key, Ref<X509Certificate> p_tls_certificate);
+
+ void set_supported_protocols(const Vector<String> &p_protocols);
+ Vector<String> get_supported_protocols() const;
+
+ void set_handshake_headers(const Vector<String> &p_headers);
+ Vector<String> get_handshake_headers() const;
+
+ void set_outbound_buffer_size(int p_buffer_size);
+ int get_outbound_buffer_size() const;
+
+ void set_inbound_buffer_size(int p_buffer_size);
+ int get_inbound_buffer_size() const;
+
+ float get_handshake_timeout() const;
+ void set_handshake_timeout(float p_timeout);
+
+ IPAddress get_peer_address(int p_peer_id) const;
+ int get_peer_port(int p_peer_id) const;
+
+ void set_max_queued_packets(int p_max_queued_packets);
+ int get_max_queued_packets() const;
WebSocketMultiplayerPeer();
~WebSocketMultiplayerPeer();
diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp
index a0af9303b8..b46b20bef2 100644
--- a/modules/websocket/websocket_peer.cpp
+++ b/modules/websocket/websocket_peer.cpp
@@ -30,7 +30,7 @@
#include "websocket_peer.h"
-GDCINULL(WebSocketPeer);
+WebSocketPeer *(*WebSocketPeer::_create)() = nullptr;
WebSocketPeer::WebSocketPeer() {
}
@@ -39,16 +39,115 @@ WebSocketPeer::~WebSocketPeer() {
}
void WebSocketPeer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_write_mode"), &WebSocketPeer::get_write_mode);
- ClassDB::bind_method(D_METHOD("set_write_mode", "mode"), &WebSocketPeer::set_write_mode);
- ClassDB::bind_method(D_METHOD("is_connected_to_host"), &WebSocketPeer::is_connected_to_host);
+ ClassDB::bind_method(D_METHOD("connect_to_url", "url", "verify_tls", "trusted_tls_certificate"), &WebSocketPeer::connect_to_url, DEFVAL(true), DEFVAL(Ref<X509Certificate>()));
+ ClassDB::bind_method(D_METHOD("accept_stream", "stream"), &WebSocketPeer::accept_stream);
+ ClassDB::bind_method(D_METHOD("send", "message", "write_mode"), &WebSocketPeer::_send_bind, DEFVAL(WRITE_MODE_BINARY));
+ ClassDB::bind_method(D_METHOD("send_text", "message"), &WebSocketPeer::send_text);
ClassDB::bind_method(D_METHOD("was_string_packet"), &WebSocketPeer::was_string_packet);
+ ClassDB::bind_method(D_METHOD("poll"), &WebSocketPeer::poll);
ClassDB::bind_method(D_METHOD("close", "code", "reason"), &WebSocketPeer::close, DEFVAL(1000), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_connected_host"), &WebSocketPeer::get_connected_host);
ClassDB::bind_method(D_METHOD("get_connected_port"), &WebSocketPeer::get_connected_port);
+ ClassDB::bind_method(D_METHOD("get_selected_protocol"), &WebSocketPeer::get_selected_protocol);
+ ClassDB::bind_method(D_METHOD("get_requested_url"), &WebSocketPeer::get_requested_url);
ClassDB::bind_method(D_METHOD("set_no_delay", "enabled"), &WebSocketPeer::set_no_delay);
ClassDB::bind_method(D_METHOD("get_current_outbound_buffered_amount"), &WebSocketPeer::get_current_outbound_buffered_amount);
+ ClassDB::bind_method(D_METHOD("get_ready_state"), &WebSocketPeer::get_ready_state);
+ ClassDB::bind_method(D_METHOD("get_close_code"), &WebSocketPeer::get_close_code);
+ ClassDB::bind_method(D_METHOD("get_close_reason"), &WebSocketPeer::get_close_reason);
+
+ ClassDB::bind_method(D_METHOD("get_supported_protocols"), &WebSocketPeer::_get_supported_protocols);
+ ClassDB::bind_method(D_METHOD("set_supported_protocols", "protocols"), &WebSocketPeer::set_supported_protocols);
+ ClassDB::bind_method(D_METHOD("get_handshake_headers"), &WebSocketPeer::_get_handshake_headers);
+ ClassDB::bind_method(D_METHOD("set_handshake_headers", "protocols"), &WebSocketPeer::set_handshake_headers);
+
+ ClassDB::bind_method(D_METHOD("get_inbound_buffer_size"), &WebSocketPeer::get_inbound_buffer_size);
+ ClassDB::bind_method(D_METHOD("set_inbound_buffer_size", "buffer_size"), &WebSocketPeer::set_inbound_buffer_size);
+ ClassDB::bind_method(D_METHOD("get_outbound_buffer_size"), &WebSocketPeer::get_outbound_buffer_size);
+ ClassDB::bind_method(D_METHOD("set_outbound_buffer_size", "buffer_size"), &WebSocketPeer::set_outbound_buffer_size);
+
+ ClassDB::bind_method(D_METHOD("set_max_queued_packets", "buffer_size"), &WebSocketPeer::set_max_queued_packets);
+ ClassDB::bind_method(D_METHOD("get_max_queued_packets"), &WebSocketPeer::get_max_queued_packets);
+
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "supported_protocols"), "set_supported_protocols", "get_supported_protocols");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "handshake_headers"), "set_handshake_headers", "get_handshake_headers");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "inbound_buffer_size"), "set_inbound_buffer_size", "get_inbound_buffer_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "outbound_buffer_size"), "set_outbound_buffer_size", "get_outbound_buffer_size");
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_queued_packets"), "set_max_queued_packets", "get_max_queued_packets");
+
BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
+
+ BIND_ENUM_CONSTANT(STATE_CONNECTING);
+ BIND_ENUM_CONSTANT(STATE_OPEN);
+ BIND_ENUM_CONSTANT(STATE_CLOSING);
+ BIND_ENUM_CONSTANT(STATE_CLOSED);
+}
+
+Error WebSocketPeer::_send_bind(const PackedByteArray &p_message, WriteMode p_mode) {
+ return send(p_message.ptr(), p_message.size(), p_mode);
+}
+
+Error WebSocketPeer::send_text(const String &p_text) {
+ const CharString cs = p_text.utf8();
+ return send((const uint8_t *)cs.ptr(), cs.length(), WRITE_MODE_TEXT);
+}
+
+void WebSocketPeer::set_supported_protocols(const Vector<String> &p_protocols) {
+ // Strip edges from protocols.
+ supported_protocols.resize(p_protocols.size());
+ for (int i = 0; i < p_protocols.size(); i++) {
+ supported_protocols.write[i] = p_protocols[i].strip_edges();
+ }
+}
+
+const Vector<String> WebSocketPeer::get_supported_protocols() const {
+ return supported_protocols;
+}
+
+Vector<String> WebSocketPeer::_get_supported_protocols() const {
+ Vector<String> out;
+ out.append_array(supported_protocols);
+ return out;
+}
+
+void WebSocketPeer::set_handshake_headers(const Vector<String> &p_headers) {
+ handshake_headers = p_headers;
+}
+
+const Vector<String> WebSocketPeer::get_handshake_headers() const {
+ return handshake_headers;
+}
+
+Vector<String> WebSocketPeer::_get_handshake_headers() const {
+ Vector<String> out;
+ out.append_array(handshake_headers);
+ return out;
+}
+
+void WebSocketPeer::set_outbound_buffer_size(int p_buffer_size) {
+ outbound_buffer_size = p_buffer_size;
+}
+
+int WebSocketPeer::get_outbound_buffer_size() const {
+ return outbound_buffer_size;
+}
+
+void WebSocketPeer::set_inbound_buffer_size(int p_buffer_size) {
+ inbound_buffer_size = p_buffer_size;
+}
+
+int WebSocketPeer::get_inbound_buffer_size() const {
+ return inbound_buffer_size;
+}
+
+void WebSocketPeer::set_max_queued_packets(int p_max_queued_packets) {
+ max_queued_packets = p_max_queued_packets;
+}
+
+int WebSocketPeer::get_max_queued_packets() const {
+ return max_queued_packets;
}
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index 22099f7258..db969dd08e 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -31,40 +31,97 @@
#ifndef WEBSOCKET_PEER_H
#define WEBSOCKET_PEER_H
+#include "core/crypto/crypto.h"
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
-#include "websocket_macros.h"
class WebSocketPeer : public PacketPeer {
GDCLASS(WebSocketPeer, PacketPeer);
- GDCICLASS(WebSocketPeer);
public:
+ enum State {
+ STATE_CONNECTING,
+ STATE_OPEN,
+ STATE_CLOSING,
+ STATE_CLOSED
+ };
+
enum WriteMode {
WRITE_MODE_TEXT,
WRITE_MODE_BINARY,
};
+ enum {
+ DEFAULT_BUFFER_SIZE = 65535,
+ };
+
+private:
+ virtual Error _send_bind(const PackedByteArray &p_data, WriteMode p_mode = WRITE_MODE_BINARY);
+
protected:
+ static WebSocketPeer *(*_create)();
+
static void _bind_methods();
+ Vector<String> supported_protocols;
+ Vector<String> handshake_headers;
+
+ Vector<String> _get_supported_protocols() const;
+ Vector<String> _get_handshake_headers() const;
+
+ int outbound_buffer_size = DEFAULT_BUFFER_SIZE;
+ int inbound_buffer_size = DEFAULT_BUFFER_SIZE;
+ int max_queued_packets = 2048;
+
public:
- virtual WriteMode get_write_mode() const = 0;
- virtual void set_write_mode(WriteMode p_mode) = 0;
+ static WebSocketPeer *create() {
+ if (!_create) {
+ return nullptr;
+ }
+ return _create();
+ }
+ virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) { return ERR_UNAVAILABLE; };
+ virtual Error accept_stream(Ref<StreamPeer> p_stream) = 0;
+
+ virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) = 0;
virtual void close(int p_code = 1000, String p_reason = "") = 0;
- virtual bool is_connected_to_host() const = 0;
virtual IPAddress get_connected_host() const = 0;
virtual uint16_t get_connected_port() const = 0;
virtual bool was_string_packet() const = 0;
virtual void set_no_delay(bool p_enabled) = 0;
virtual int get_current_outbound_buffered_amount() const = 0;
+ virtual String get_selected_protocol() const = 0;
+ virtual String get_requested_url() const = 0;
+
+ virtual void poll() = 0;
+ virtual State get_ready_state() const = 0;
+ virtual int get_close_code() const = 0;
+ virtual String get_close_reason() const = 0;
+
+ Error send_text(const String &p_text);
+
+ void set_supported_protocols(const Vector<String> &p_protocols);
+ const Vector<String> get_supported_protocols() const;
+
+ void set_handshake_headers(const Vector<String> &p_headers);
+ const Vector<String> get_handshake_headers() const;
+
+ void set_outbound_buffer_size(int p_buffer_size);
+ int get_outbound_buffer_size() const;
+
+ void set_inbound_buffer_size(int p_buffer_size);
+ int get_inbound_buffer_size() const;
+
+ void set_max_queued_packets(int p_max_queued_packets);
+ int get_max_queued_packets() const;
WebSocketPeer();
~WebSocketPeer();
};
VARIANT_ENUM_CAST(WebSocketPeer::WriteMode);
+VARIANT_ENUM_CAST(WebSocketPeer::State);
#endif // WEBSOCKET_PEER_H
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
deleted file mode 100644
index 25a6e420fc..0000000000
--- a/modules/websocket/websocket_server.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*************************************************************************/
-/* websocket_server.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 "websocket_server.h"
-
-GDCINULL(WebSocketServer);
-
-WebSocketServer::WebSocketServer() {
- _peer_id = 1;
- bind_ip = IPAddress("*");
-}
-
-WebSocketServer::~WebSocketServer() {
-}
-
-void WebSocketServer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening);
- ClassDB::bind_method(D_METHOD("set_extra_headers", "headers"), &WebSocketServer::set_extra_headers, DEFVAL(Vector<String>()));
- ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(Vector<String>()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop);
- ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer);
- ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &WebSocketServer::get_peer_address);
- ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &WebSocketServer::get_peer_port);
- ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL(""));
-
- ClassDB::bind_method(D_METHOD("get_bind_ip"), &WebSocketServer::get_bind_ip);
- ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &WebSocketServer::set_bind_ip);
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "bind_ip"), "set_bind_ip", "get_bind_ip");
-
- ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key);
- ClassDB::bind_method(D_METHOD("set_private_key", "key"), &WebSocketServer::set_private_key);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", PROPERTY_USAGE_NONE), "set_private_key", "get_private_key");
-
- ClassDB::bind_method(D_METHOD("get_tls_certificate"), &WebSocketServer::get_tls_certificate);
- ClassDB::bind_method(D_METHOD("set_tls_certificate", "cert"), &WebSocketServer::set_tls_certificate);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tls_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_tls_certificate", "get_tls_certificate");
-
- ClassDB::bind_method(D_METHOD("get_ca_chain"), &WebSocketServer::get_ca_chain);
- ClassDB::bind_method(D_METHOD("set_ca_chain", "ca_chain"), &WebSocketServer::set_ca_chain);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ca_chain", "get_ca_chain");
-
- ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout);
- ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketServer::set_handshake_timeout);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout");
-
- ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason")));
- ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close")));
- ADD_SIGNAL(MethodInfo("client_connected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "protocol"), PropertyInfo(Variant::STRING, "resource_name")));
- ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
-}
-
-IPAddress WebSocketServer::get_bind_ip() const {
- return bind_ip;
-}
-
-void WebSocketServer::set_bind_ip(const IPAddress &p_bind_ip) {
- ERR_FAIL_COND(is_listening());
- ERR_FAIL_COND(!p_bind_ip.is_valid() && !p_bind_ip.is_wildcard());
- bind_ip = p_bind_ip;
-}
-
-Ref<CryptoKey> WebSocketServer::get_private_key() const {
- return private_key;
-}
-
-void WebSocketServer::set_private_key(Ref<CryptoKey> p_key) {
- ERR_FAIL_COND(is_listening());
- private_key = p_key;
-}
-
-Ref<X509Certificate> WebSocketServer::get_tls_certificate() const {
- return tls_cert;
-}
-
-void WebSocketServer::set_tls_certificate(Ref<X509Certificate> p_cert) {
- ERR_FAIL_COND(is_listening());
- tls_cert = p_cert;
-}
-
-Ref<X509Certificate> WebSocketServer::get_ca_chain() const {
- return ca_chain;
-}
-
-void WebSocketServer::set_ca_chain(Ref<X509Certificate> p_ca_chain) {
- ERR_FAIL_COND(is_listening());
- ca_chain = p_ca_chain;
-}
-
-float WebSocketServer::get_handshake_timeout() const {
- return handshake_timeout / 1000.0;
-}
-
-void WebSocketServer::set_handshake_timeout(float p_timeout) {
- ERR_FAIL_COND(p_timeout <= 0.0);
- handshake_timeout = p_timeout * 1000;
-}
-
-MultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const {
- if (is_listening()) {
- return CONNECTION_CONNECTED;
- }
-
- return CONNECTION_DISCONNECTED;
-}
-
-bool WebSocketServer::is_server() const {
- return true;
-}
-
-void WebSocketServer::_on_peer_packet(int32_t p_peer_id) {
- if (_is_multiplayer) {
- _process_multiplayer(get_peer(p_peer_id), p_peer_id);
- } else {
- emit_signal(SNAME("data_received"), p_peer_id);
- }
-}
-
-void WebSocketServer::_on_connect(int32_t p_peer_id, String p_protocol, String p_resource_name) {
- if (_is_multiplayer) {
- // Send add to clients
- _send_add(p_peer_id);
- emit_signal(SNAME("peer_connected"), p_peer_id);
- } else {
- emit_signal(SNAME("client_connected"), p_peer_id, p_protocol, p_resource_name);
- }
-}
-
-void WebSocketServer::_on_disconnect(int32_t p_peer_id, bool p_was_clean) {
- if (_is_multiplayer) {
- // Send delete to clients
- _send_del(p_peer_id);
- emit_signal(SNAME("peer_disconnected"), p_peer_id);
- } else {
- emit_signal(SNAME("client_disconnected"), p_peer_id, p_was_clean);
- }
-}
-
-void WebSocketServer::_on_close_request(int32_t p_peer_id, int p_code, String p_reason) {
- emit_signal(SNAME("client_close_request"), p_peer_id, p_code, p_reason);
-}
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
deleted file mode 100644
index de23ee884d..0000000000
--- a/modules/websocket/websocket_server.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*************************************************************************/
-/* websocket_server.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 WEBSOCKET_SERVER_H
-#define WEBSOCKET_SERVER_H
-
-#include "core/crypto/crypto.h"
-#include "core/object/ref_counted.h"
-#include "websocket_multiplayer_peer.h"
-#include "websocket_peer.h"
-
-class WebSocketServer : public WebSocketMultiplayerPeer {
- GDCLASS(WebSocketServer, WebSocketMultiplayerPeer);
- GDCICLASS(WebSocketServer);
-
- IPAddress bind_ip;
-
-protected:
- static void _bind_methods();
-
- Ref<CryptoKey> private_key;
- Ref<X509Certificate> tls_cert;
- Ref<X509Certificate> ca_chain;
- uint32_t handshake_timeout = 3000;
-
-public:
- virtual void set_extra_headers(const Vector<String> &p_headers) = 0;
- virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0;
- virtual void stop() = 0;
- virtual bool is_listening() const = 0;
- virtual bool has_peer(int p_id) const = 0;
- virtual bool is_server() const override;
- ConnectionStatus get_connection_status() const override;
-
- virtual IPAddress get_peer_address(int p_peer_id) const = 0;
- virtual int get_peer_port(int p_peer_id) const = 0;
- virtual void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") = 0;
-
- void _on_peer_packet(int32_t p_peer_id);
- void _on_connect(int32_t p_peer_id, String p_protocol, String p_resource_name);
- void _on_disconnect(int32_t p_peer_id, bool p_was_clean);
- void _on_close_request(int32_t p_peer_id, int p_code, String p_reason);
-
- IPAddress get_bind_ip() const;
- void set_bind_ip(const IPAddress &p_bind_ip);
-
- Ref<CryptoKey> get_private_key() const;
- void set_private_key(Ref<CryptoKey> p_key);
-
- Ref<X509Certificate> get_tls_certificate() const;
- void set_tls_certificate(Ref<X509Certificate> p_cert);
-
- Ref<X509Certificate> get_ca_chain() const;
- void set_ca_chain(Ref<X509Certificate> p_ca_chain);
-
- float get_handshake_timeout() const;
- void set_handshake_timeout(float p_timeout);
-
- WebSocketServer();
- ~WebSocketServer();
-};
-
-#endif // WEBSOCKET_SERVER_H
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
deleted file mode 100644
index 50ef53e267..0000000000
--- a/modules/websocket/wsl_client.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-/*************************************************************************/
-/* wsl_client.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. */
-/*************************************************************************/
-
-#ifndef WEB_ENABLED
-
-#include "wsl_client.h"
-#include "core/config/project_settings.h"
-#include "core/io/ip.h"
-
-void WSLClient::_do_handshake() {
- if (_requested < _request.size() - 1) {
- int sent = 0;
- Error err = _connection->put_partial_data(((const uint8_t *)_request.get_data() + _requested), _request.size() - _requested - 1, sent);
- // Sending handshake failed
- if (err != OK) {
- disconnect_from_host();
- _on_error();
- return;
- }
- _requested += sent;
-
- } else {
- int read = 0;
- while (true) {
- if (_resp_pos >= WSL_MAX_HEADER_SIZE) {
- // Header is too big
- disconnect_from_host();
- _on_error();
- ERR_FAIL_MSG("Response headers too big.");
- }
- Error err = _connection->get_partial_data(&_resp_buf[_resp_pos], 1, read);
- if (err == ERR_FILE_EOF) {
- // We got a disconnect.
- disconnect_from_host();
- _on_error();
- return;
- } else if (err != OK) {
- // Got some error.
- disconnect_from_host();
- _on_error();
- return;
- } else if (read != 1) {
- // Busy, wait next poll.
- break;
- }
- // Check "\r\n\r\n" header terminator
- char *r = (char *)_resp_buf;
- int l = _resp_pos;
- if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
- r[l - 3] = '\0';
- String protocol;
- // Response is over, verify headers and create peer.
- if (!_verify_headers(protocol)) {
- disconnect_from_host();
- _on_error();
- ERR_FAIL_MSG("Invalid response headers.");
- }
- // Create peer.
- WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
- data->obj = this;
- data->conn = _connection;
- data->tcp = _tcp;
- data->is_server = false;
- data->id = 1;
- _peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
- _peer->set_no_delay(true);
- _status = CONNECTION_CONNECTED;
- _on_connect(protocol);
- break;
- }
- _resp_pos += 1;
- }
- }
-}
-
-bool WSLClient::_verify_headers(String &r_protocol) {
- String s = (char *)_resp_buf;
- Vector<String> psa = s.split("\r\n");
- int len = psa.size();
- ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4.");
-
- Vector<String> req = psa[0].split(" ", false);
- ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code. Got '" + psa[0] + "', expected 'HTTP/1.1 101'.");
-
- // Wrong protocol
- ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'.");
- ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'.");
-
- HashMap<String, String> headers;
- for (int i = 1; i < len; i++) {
- Vector<String> header = psa[i].split(":", false, 1);
- ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i] + ".");
- String name = header[0].to_lower();
- String value = header[1].strip_edges();
- if (headers.has(name)) {
- headers[name] += "," + value;
- } else {
- headers[name] = value;
- }
- }
-
-#define WSL_CHECK(NAME, VALUE) \
- ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \
- "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
-#define WSL_CHECK_NC(NAME, VALUE) \
- ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME] != VALUE, false, \
- "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
- WSL_CHECK("connection", "upgrade");
- WSL_CHECK("upgrade", "websocket");
- WSL_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key));
-#undef WSL_CHECK_NC
-#undef WSL_CHECK
- if (_protocols.size() == 0) {
- // We didn't request a custom protocol
- ERR_FAIL_COND_V_MSG(headers.has("sec-websocket-protocol"), false, "Received unrequested sub-protocol -> " + headers["sec-websocket-protocol"]);
- } else {
- // We requested at least one custom protocol but didn't receive one
- ERR_FAIL_COND_V_MSG(!headers.has("sec-websocket-protocol"), false, "Requested sub-protocol(s) but received none.");
- // Check received sub-protocol was one of those requested.
- r_protocol = headers["sec-websocket-protocol"];
- bool valid = false;
- for (int i = 0; i < _protocols.size(); i++) {
- if (_protocols[i] != r_protocol) {
- continue;
- }
- valid = true;
- break;
- }
- if (!valid) {
- ERR_FAIL_V_MSG(false, "Received unrequested sub-protocol -> " + r_protocol);
- return false;
- }
- }
- return true;
-}
-
-Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_tls, const Vector<String> p_protocols, const Vector<String> p_custom_headers) {
- ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE);
- ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER);
-
- _peer = Ref<WSLPeer>(memnew(WSLPeer));
-
- if (p_host.is_valid_ip_address()) {
- _ip_candidates.push_back(IPAddress(p_host));
- } else {
- // Queue hostname for resolution.
- _resolver_id = IP::get_singleton()->resolve_hostname_queue_item(p_host);
- ERR_FAIL_COND_V(_resolver_id == IP::RESOLVER_INVALID_ID, ERR_INVALID_PARAMETER);
- // Check if it was found in cache.
- IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id);
- if (ip_status == IP::RESOLVER_STATUS_DONE) {
- _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id);
- IP::get_singleton()->erase_resolve_item(_resolver_id);
- _resolver_id = IP::RESOLVER_INVALID_ID;
- }
- }
-
- // We assume OK while hostname resolution is pending.
- Error err = _resolver_id != IP::RESOLVER_INVALID_ID ? OK : FAILED;
- while (_ip_candidates.size()) {
- err = _tcp->connect_to_host(_ip_candidates.pop_front(), p_port);
- if (err == OK) {
- break;
- }
- }
- if (err != OK) {
- _tcp->disconnect_from_host();
- _on_error();
- return err;
- }
- _connection = _tcp;
- _use_tls = p_tls;
- _host = p_host;
- _port = p_port;
- // Strip edges from protocols.
- _protocols.resize(p_protocols.size());
- String *pw = _protocols.ptrw();
- for (int i = 0; i < p_protocols.size(); i++) {
- pw[i] = p_protocols[i].strip_edges();
- }
-
- _key = WSLPeer::generate_key();
- String request = "GET " + p_path + " HTTP/1.1\r\n";
- String port = "";
- if ((p_port != 80 && !p_tls) || (p_port != 443 && p_tls)) {
- port = ":" + itos(p_port);
- }
- request += "Host: " + p_host + port + "\r\n";
- request += "Upgrade: websocket\r\n";
- request += "Connection: Upgrade\r\n";
- request += "Sec-WebSocket-Key: " + _key + "\r\n";
- request += "Sec-WebSocket-Version: 13\r\n";
- if (p_protocols.size() > 0) {
- request += "Sec-WebSocket-Protocol: ";
- for (int i = 0; i < p_protocols.size(); i++) {
- if (i != 0) {
- request += ",";
- }
- request += p_protocols[i];
- }
- request += "\r\n";
- }
- for (int i = 0; i < p_custom_headers.size(); i++) {
- request += p_custom_headers[i] + "\r\n";
- }
- request += "\r\n";
- _request = request.utf8();
- _status = CONNECTION_CONNECTING;
-
- return OK;
-}
-
-int WSLClient::get_max_packet_size() const {
- return (1 << _out_buf_size) - PROTO_SIZE;
-}
-
-void WSLClient::poll() {
- if (_resolver_id != IP::RESOLVER_INVALID_ID) {
- IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(_resolver_id);
- if (ip_status == IP::RESOLVER_STATUS_WAITING) {
- return;
- }
- // Anything else is either a candidate or a failure.
- Error err = FAILED;
- if (ip_status == IP::RESOLVER_STATUS_DONE) {
- _ip_candidates = IP::get_singleton()->get_resolve_item_addresses(_resolver_id);
- while (_ip_candidates.size()) {
- err = _tcp->connect_to_host(_ip_candidates.pop_front(), _port);
- if (err == OK) {
- break;
- }
- }
- }
- IP::get_singleton()->erase_resolve_item(_resolver_id);
- _resolver_id = IP::RESOLVER_INVALID_ID;
- if (err != OK) {
- disconnect_from_host();
- _on_error();
- return;
- }
- }
- if (_peer->is_connected_to_host()) {
- _peer->poll();
- if (!_peer->is_connected_to_host()) {
- disconnect_from_host();
- _on_disconnect(_peer->close_code != -1);
- }
- return;
- }
-
- if (_connection.is_null()) {
- return; // Not connected.
- }
-
- _tcp->poll();
- switch (_tcp->get_status()) {
- case StreamPeerTCP::STATUS_NONE:
- // Clean close
- disconnect_from_host();
- _on_error();
- break;
- case StreamPeerTCP::STATUS_CONNECTED: {
- _ip_candidates.clear();
- Ref<StreamPeerTLS> tls;
- if (_use_tls) {
- if (_connection == _tcp) {
- // Start SSL handshake
- tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
- ERR_FAIL_COND_MSG(tls.is_null(), "SSL is not available in this build.");
- tls->set_blocking_handshake_enabled(false);
- if (tls->connect_to_stream(_tcp, verify_tls, _host, tls_cert) != OK) {
- disconnect_from_host();
- _on_error();
- return;
- }
- _connection = tls;
- } else {
- tls = static_cast<Ref<StreamPeerTLS>>(_connection);
- ERR_FAIL_COND(tls.is_null()); // Bug?
- tls->poll();
- }
- if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
- return; // Need more polling.
- } else if (tls->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
- disconnect_from_host();
- _on_error();
- return; // Error.
- }
- }
- // Do websocket handshake.
- _do_handshake();
- } break;
- case StreamPeerTCP::STATUS_ERROR:
- while (_ip_candidates.size() > 0) {
- _tcp->disconnect_from_host();
- if (_tcp->connect_to_host(_ip_candidates.pop_front(), _port) == OK) {
- return;
- }
- }
- disconnect_from_host();
- _on_error();
- break;
- case StreamPeerTCP::STATUS_CONNECTING:
- break; // Wait for connection
- }
-}
-
-Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const {
- ERR_FAIL_COND_V(p_peer_id != 1, nullptr);
-
- return _peer;
-}
-
-MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
- // This is surprising, but keeps the current behaviour to allow clean close requests.
- // TODO Refactor WebSocket and split Client/Server/Multiplayer like done in other peers.
- if (_peer->is_connected_to_host()) {
- return CONNECTION_CONNECTED;
- }
- return _status;
-}
-
-void WSLClient::disconnect_from_host(int p_code, String p_reason) {
- _peer->close(p_code, p_reason);
- _connection = Ref<StreamPeer>(nullptr);
- _tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP));
- _status = CONNECTION_DISCONNECTED;
-
- _key = "";
- _host = "";
- _protocols.clear();
- _use_tls = false;
-
- _request = "";
- _requested = 0;
-
- memset(_resp_buf, 0, sizeof(_resp_buf));
- _resp_pos = 0;
-
- if (_resolver_id != IP::RESOLVER_INVALID_ID) {
- IP::get_singleton()->erase_resolve_item(_resolver_id);
- _resolver_id = IP::RESOLVER_INVALID_ID;
- }
-
- _ip_candidates.clear();
-}
-
-IPAddress WSLClient::get_connected_host() const {
- ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IPAddress());
- return _peer->get_connected_host();
-}
-
-uint16_t WSLClient::get_connected_port() const {
- ERR_FAIL_COND_V(!_peer->is_connected_to_host(), 0);
- return _peer->get_connected_port();
-}
-
-Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- ERR_FAIL_COND_V_MSG(_connection.is_valid(), FAILED, "Buffers sizes can only be set before listening or connecting.");
-
- _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
- _in_pkt_size = nearest_shift(p_in_packets - 1);
- _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
- _out_pkt_size = nearest_shift(p_out_packets - 1);
- return OK;
-}
-
-WSLClient::WSLClient() {
- _peer.instantiate();
- _tcp.instantiate();
- disconnect_from_host();
-}
-
-WSLClient::~WSLClient() {
- _peer->close_now();
- _peer->invalidate();
- disconnect_from_host();
-}
-
-#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 97bd87a526..84e022182e 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -32,71 +32,537 @@
#include "wsl_peer.h"
-#include "wsl_client.h"
-#include "wsl_server.h"
+#include "wsl_peer.h"
-#include "core/crypto/crypto_core.h"
-#include "core/math/random_number_generator.h"
-#include "core/os/os.h"
+#include "core/io/stream_peer_tls.h"
-String WSLPeer::generate_key() {
- // Random key
- RandomNumberGenerator rng;
- rng.set_seed(OS::get_singleton()->get_unix_time());
- Vector<uint8_t> bkey;
- int len = 16; // 16 bytes, as per RFC
- bkey.resize(len);
- uint8_t *w = bkey.ptrw();
- for (int i = 0; i < len; i++) {
- w[i] = (uint8_t)rng.randi_range(0, 255);
+CryptoCore::RandomGenerator *WSLPeer::_static_rng = nullptr;
+
+void WSLPeer::initialize() {
+ WebSocketPeer::_create = WSLPeer::_create;
+ _static_rng = memnew(CryptoCore::RandomGenerator);
+ _static_rng->init();
+}
+
+void WSLPeer::deinitialize() {
+ if (_static_rng) {
+ memdelete(_static_rng);
+ _static_rng = nullptr;
}
- return CryptoCore::b64_encode_str(&w[0], len);
}
-String WSLPeer::compute_key_response(String p_key) {
- String key = p_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Magic UUID as per RFC
- Vector<uint8_t> sha = key.sha1_buffer();
- return CryptoCore::b64_encode_str(sha.ptr(), sha.size());
+///
+/// Resolver
+///
+void WSLPeer::Resolver::start(const String &p_host, int p_port) {
+ stop();
+
+ port = p_port;
+ if (p_host.is_valid_ip_address()) {
+ ip_candidates.push_back(IPAddress(p_host));
+ } else {
+ // Queue hostname for resolution.
+ resolver_id = IP::get_singleton()->resolve_hostname_queue_item(p_host);
+ ERR_FAIL_COND(resolver_id == IP::RESOLVER_INVALID_ID);
+ // Check if it was found in cache.
+ IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(resolver_id);
+ if (ip_status == IP::RESOLVER_STATUS_DONE) {
+ ip_candidates = IP::get_singleton()->get_resolve_item_addresses(resolver_id);
+ IP::get_singleton()->erase_resolve_item(resolver_id);
+ resolver_id = IP::RESOLVER_INVALID_ID;
+ }
+ }
}
-void WSLPeer::_wsl_destroy(struct PeerData **p_data) {
- if (!p_data || !(*p_data)) {
- return;
+void WSLPeer::Resolver::stop() {
+ if (resolver_id != IP::RESOLVER_INVALID_ID) {
+ IP::get_singleton()->erase_resolve_item(resolver_id);
+ resolver_id = IP::RESOLVER_INVALID_ID;
+ }
+ port = 0;
+}
+
+void WSLPeer::Resolver::try_next_candidate(Ref<StreamPeerTCP> &p_tcp) {
+ // Check if we still need resolving.
+ if (resolver_id != IP::RESOLVER_INVALID_ID) {
+ IP::ResolverStatus ip_status = IP::get_singleton()->get_resolve_item_status(resolver_id);
+ if (ip_status == IP::RESOLVER_STATUS_WAITING) {
+ return;
+ }
+ if (ip_status == IP::RESOLVER_STATUS_DONE) {
+ ip_candidates = IP::get_singleton()->get_resolve_item_addresses(resolver_id);
+ }
+ IP::get_singleton()->erase_resolve_item(resolver_id);
+ resolver_id = IP::RESOLVER_INVALID_ID;
}
- struct PeerData *data = *p_data;
- if (data->polling) {
- data->destroy = true;
+
+ // Try the current candidate if we have one.
+ if (p_tcp->get_status() != StreamPeerTCP::STATUS_NONE) {
+ p_tcp->poll();
+ StreamPeerTCP::Status status = p_tcp->get_status();
+ if (status == StreamPeerTCP::STATUS_CONNECTED) {
+ p_tcp->set_no_delay(true);
+ ip_candidates.clear();
+ return;
+ } else if (status == StreamPeerTCP::STATUS_CONNECTING) {
+ return; // Keep connecting.
+ } else {
+ p_tcp->disconnect_from_host();
+ }
+ }
+
+ // Keep trying next candidate.
+ while (ip_candidates.size()) {
+ Error err = p_tcp->connect_to_host(ip_candidates.pop_front(), port);
+ if (err == OK) {
+ return;
+ } else {
+ p_tcp->disconnect_from_host();
+ }
+ }
+}
+
+///
+/// Server functions
+///
+Error WSLPeer::accept_stream(Ref<StreamPeer> p_stream) {
+ ERR_FAIL_COND_V(wsl_ctx || tcp.is_valid(), ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(p_stream.is_null(), ERR_INVALID_PARAMETER);
+
+ _clear();
+
+ if (p_stream->is_class_ptr(StreamPeerTCP::get_class_ptr_static())) {
+ tcp = p_stream;
+ connection = p_stream;
+ use_tls = false;
+ } else if (p_stream->is_class_ptr(StreamPeerTLS::get_class_ptr_static())) {
+ Ref<StreamPeer> base_stream = static_cast<Ref<StreamPeerTLS>>(p_stream)->get_stream();
+ ERR_FAIL_COND_V(base_stream.is_null() || !base_stream->is_class_ptr(StreamPeerTCP::get_class_ptr_static()), ERR_INVALID_PARAMETER);
+ tcp = static_cast<Ref<StreamPeerTCP>>(base_stream);
+ connection = p_stream;
+ use_tls = true;
+ }
+ ERR_FAIL_COND_V(connection.is_null() || tcp.is_null(), ERR_INVALID_PARAMETER);
+ is_server = true;
+ ready_state = STATE_CONNECTING;
+ handshake_buffer->resize(WSL_MAX_HEADER_SIZE);
+ handshake_buffer->seek(0);
+ return OK;
+}
+
+bool WSLPeer::_parse_client_request() {
+ Vector<String> psa = String((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4).split("\r\n");
+ int len = psa.size();
+ ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
+
+ Vector<String> req = psa[0].split(" ", false);
+ ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code.");
+
+ // Wrong protocol
+ ERR_FAIL_COND_V_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", false, "Invalid method or HTTP version.");
+
+ HashMap<String, String> headers;
+ for (int i = 1; i < len; i++) {
+ Vector<String> header = psa[i].split(":", false, 1);
+ ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i]);
+ String name = header[0].to_lower();
+ String value = header[1].strip_edges();
+ if (headers.has(name)) {
+ headers[name] += "," + value;
+ } else {
+ headers[name] = value;
+ }
+ }
+ requested_host = headers.has("host") ? headers.get("host") : "";
+ requested_url = (use_tls ? "wss://" : "ws://") + requested_host + req[1];
+#define WSL_CHECK(NAME, VALUE) \
+ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \
+ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
+#define WSL_CHECK_EX(NAME) \
+ ERR_FAIL_COND_V_MSG(!headers.has(NAME), false, "Missing header '" + String(NAME) + "'.");
+ WSL_CHECK("upgrade", "websocket");
+ WSL_CHECK("sec-websocket-version", "13");
+ WSL_CHECK_EX("sec-websocket-key");
+ WSL_CHECK_EX("connection");
+#undef WSL_CHECK_EX
+#undef WSL_CHECK
+ session_key = headers["sec-websocket-key"];
+ if (headers.has("sec-websocket-protocol")) {
+ Vector<String> protos = headers["sec-websocket-protocol"].split(",");
+ for (int i = 0; i < protos.size(); i++) {
+ String proto = protos[i].strip_edges();
+ // Check if we have the given protocol
+ for (int j = 0; j < supported_protocols.size(); j++) {
+ if (proto != supported_protocols[j]) {
+ continue;
+ }
+ selected_protocol = proto;
+ break;
+ }
+ // Found a protocol
+ if (!selected_protocol.is_empty()) {
+ break;
+ }
+ }
+ if (selected_protocol.is_empty()) { // Invalid protocol(s) requested
+ return false;
+ }
+ } else if (supported_protocols.size() > 0) { // No protocol requested, but we need one
+ return false;
+ }
+ return true;
+}
+
+Error WSLPeer::_do_server_handshake() {
+ if (use_tls) {
+ Ref<StreamPeerTLS> tls = static_cast<Ref<StreamPeerTLS>>(connection);
+ if (tls.is_null()) {
+ ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerTLS for WebSocket handshake.");
+ close(-1);
+ return FAILED;
+ }
+ tls->poll();
+ if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
+ return OK; // Pending handshake
+ } else if (tls->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
+ print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerTLS status code %d).", tls->get_status()));
+ close(-1);
+ return FAILED;
+ }
+ }
+
+ if (pending_request) {
+ int read = 0;
+ while (true) {
+ ERR_FAIL_COND_V_MSG(handshake_buffer->get_available_bytes() < 1, ERR_OUT_OF_MEMORY, "WebSocket response headers are too big.");
+ int pos = handshake_buffer->get_position();
+ uint8_t byte;
+ Error err = connection->get_partial_data(&byte, 1, read);
+ if (err != OK) { // Got an error
+ print_verbose(vformat("WebSocket error while getting partial data (StreamPeer error code %d).", err));
+ close(-1);
+ return FAILED;
+ } else if (read != 1) { // Busy, wait next poll
+ return OK;
+ }
+ handshake_buffer->put_u8(byte);
+ const char *r = (const char *)handshake_buffer->get_data_array().ptr();
+ int l = pos;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ if (!_parse_client_request()) {
+ close(-1);
+ return FAILED;
+ }
+ String s = "HTTP/1.1 101 Switching Protocols\r\n";
+ s += "Upgrade: websocket\r\n";
+ s += "Connection: Upgrade\r\n";
+ s += "Sec-WebSocket-Accept: " + _compute_key_response(session_key) + "\r\n";
+ if (!selected_protocol.is_empty()) {
+ s += "Sec-WebSocket-Protocol: " + selected_protocol + "\r\n";
+ }
+ for (int i = 0; i < handshake_headers.size(); i++) {
+ s += handshake_headers[i] + "\r\n";
+ }
+ s += "\r\n";
+ CharString cs = s.utf8();
+ handshake_buffer->clear();
+ handshake_buffer->put_data((const uint8_t *)cs.get_data(), cs.length());
+ handshake_buffer->seek(0);
+ pending_request = false;
+ break;
+ }
+ }
+ }
+
+ if (pending_request) { // Still pending.
+ return OK;
+ }
+
+ int left = handshake_buffer->get_available_bytes();
+ if (left) {
+ Vector<uint8_t> data = handshake_buffer->get_data_array();
+ int pos = handshake_buffer->get_position();
+ int sent = 0;
+ Error err = connection->put_partial_data(data.ptr() + pos, left, sent);
+ if (err != OK) {
+ print_verbose(vformat("WebSocket error while putting partial data (StreamPeer error code %d).", err));
+ close(-1);
+ return err;
+ }
+ handshake_buffer->seek(pos + sent);
+ left -= sent;
+ if (left == 0) {
+ resolver.stop();
+ // Response sent, initialize wslay context.
+ wslay_event_context_server_init(&wsl_ctx, &_wsl_callbacks, this);
+ wslay_event_config_set_max_recv_msg_length(wsl_ctx, inbound_buffer_size);
+ in_buffer.resize(nearest_shift(inbound_buffer_size), max_queued_packets);
+ packet_buffer.resize(inbound_buffer_size);
+ ready_state = STATE_OPEN;
+ }
+ }
+
+ return OK;
+}
+
+///
+/// Client functions
+///
+void WSLPeer::_do_client_handshake() {
+ ERR_FAIL_COND(tcp.is_null());
+
+ // Try to connect to candidates.
+ if (resolver.has_more_candidates()) {
+ resolver.try_next_candidate(tcp);
+ if (resolver.has_more_candidates()) {
+ return; // Still pending.
+ }
+ }
+
+ tcp->poll();
+ if (tcp->get_status() == StreamPeerTCP::STATUS_CONNECTING) {
+ return; // Keep connecting.
+ } else if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
+ close(-1); // Failed to connect.
return;
}
- wslay_event_context_free(data->ctx);
- memdelete(data);
- *p_data = nullptr;
+
+ if (use_tls) {
+ Ref<StreamPeerTLS> tls;
+ if (connection == tcp) {
+ // Start SSL handshake
+ tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
+ ERR_FAIL_COND_MSG(tls.is_null(), "SSL is not available in this build.");
+ tls->set_blocking_handshake_enabled(false);
+ if (tls->connect_to_stream(tcp, verify_tls, requested_host, tls_cert) != OK) {
+ close(-1);
+ return; // Error.
+ }
+ connection = tls;
+ } else {
+ tls = static_cast<Ref<StreamPeerTLS>>(connection);
+ ERR_FAIL_COND(tls.is_null());
+ tls->poll();
+ }
+ if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
+ return; // Need more polling.
+ } else if (tls->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
+ close(-1);
+ return; // Error.
+ }
+ }
+
+ // Do websocket handshake.
+ if (pending_request) {
+ int left = handshake_buffer->get_available_bytes();
+ int pos = handshake_buffer->get_position();
+ const Vector<uint8_t> data = handshake_buffer->get_data_array();
+ int sent = 0;
+ Error err = connection->put_partial_data(data.ptr() + pos, left, sent);
+ // Sending handshake failed
+ if (err != OK) {
+ close(-1);
+ return; // Error.
+ }
+ handshake_buffer->seek(pos + sent);
+ if (handshake_buffer->get_available_bytes() == 0) {
+ pending_request = false;
+ handshake_buffer->clear();
+ handshake_buffer->resize(WSL_MAX_HEADER_SIZE);
+ handshake_buffer->seek(0);
+ }
+ } else {
+ int read = 0;
+ while (true) {
+ int left = handshake_buffer->get_available_bytes();
+ int pos = handshake_buffer->get_position();
+ if (left == 0) {
+ // Header is too big
+ close(-1);
+ ERR_FAIL_MSG("Response headers too big.");
+ return;
+ }
+
+ uint8_t byte;
+ Error err = connection->get_partial_data(&byte, 1, read);
+ if (err != OK) {
+ // Got some error.
+ close(-1);
+ return;
+ } else if (read != 1) {
+ // Busy, wait next poll.
+ break;
+ }
+ handshake_buffer->put_u8(byte);
+
+ // Check "\r\n\r\n" header terminator
+ const char *r = (const char *)handshake_buffer->get_data_array().ptr();
+ int l = pos;
+ if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
+ // Response is over, verify headers and initialize wslay context/
+ if (!_verify_server_response()) {
+ close(-1);
+ ERR_FAIL_MSG("Invalid response headers.");
+ return;
+ }
+ wslay_event_context_client_init(&wsl_ctx, &_wsl_callbacks, this);
+ wslay_event_config_set_max_recv_msg_length(wsl_ctx, inbound_buffer_size);
+ in_buffer.resize(nearest_shift(inbound_buffer_size), max_queued_packets);
+ packet_buffer.resize(inbound_buffer_size);
+ ready_state = STATE_OPEN;
+ break;
+ }
+ }
+ }
}
-bool WSLPeer::_wsl_poll(struct PeerData *p_data) {
- p_data->polling = true;
- int err = 0;
- if ((err = wslay_event_recv(p_data->ctx)) != 0 || (err = wslay_event_send(p_data->ctx)) != 0) {
- print_verbose("Websocket (wslay) poll error: " + itos(err));
- p_data->destroy = true;
+bool WSLPeer::_verify_server_response() {
+ Vector<String> psa = String((const char *)handshake_buffer->get_data_array().ptr(), handshake_buffer->get_position() - 4).split("\r\n");
+ int len = psa.size();
+ ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4.");
+
+ Vector<String> req = psa[0].split(" ", false);
+ ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code. Got '" + psa[0] + "', expected 'HTTP/1.1 101'.");
+
+ // Wrong protocol
+ ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'.");
+ ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'.");
+
+ HashMap<String, String> headers;
+ for (int i = 1; i < len; i++) {
+ Vector<String> header = psa[i].split(":", false, 1);
+ ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i] + ".");
+ String name = header[0].to_lower();
+ String value = header[1].strip_edges();
+ if (headers.has(name)) {
+ headers[name] += "," + value;
+ } else {
+ headers[name] = value;
+ }
}
- p_data->polling = false;
- if (p_data->destroy || (wslay_event_get_close_sent(p_data->ctx) && wslay_event_get_close_received(p_data->ctx))) {
- bool valid = p_data->valid;
- _wsl_destroy(&p_data);
- return valid;
+#define WSL_CHECK(NAME, VALUE) \
+ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \
+ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
+#define WSL_CHECK_NC(NAME, VALUE) \
+ ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME] != VALUE, false, \
+ "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
+ WSL_CHECK("connection", "upgrade");
+ WSL_CHECK("upgrade", "websocket");
+ WSL_CHECK_NC("sec-websocket-accept", _compute_key_response(session_key));
+#undef WSL_CHECK_NC
+#undef WSL_CHECK
+ if (supported_protocols.size() == 0) {
+ // We didn't request a custom protocol
+ ERR_FAIL_COND_V_MSG(headers.has("sec-websocket-protocol"), false, "Received unrequested sub-protocol -> " + headers["sec-websocket-protocol"]);
+ } else {
+ // We requested at least one custom protocol but didn't receive one
+ ERR_FAIL_COND_V_MSG(!headers.has("sec-websocket-protocol"), false, "Requested sub-protocol(s) but received none.");
+ // Check received sub-protocol was one of those requested.
+ selected_protocol = headers["sec-websocket-protocol"];
+ bool valid = false;
+ for (int i = 0; i < supported_protocols.size(); i++) {
+ if (supported_protocols[i] != selected_protocol) {
+ continue;
+ }
+ valid = true;
+ break;
+ }
+ if (!valid) {
+ ERR_FAIL_V_MSG(false, "Received unrequested sub-protocol -> " + selected_protocol);
+ return false;
+ }
+ }
+ return true;
+}
+
+Error WSLPeer::connect_to_url(const String &p_url, bool p_verify_tls, Ref<X509Certificate> p_cert) {
+ ERR_FAIL_COND_V(wsl_ctx || tcp.is_valid(), ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(p_url.is_empty(), ERR_INVALID_PARAMETER);
+
+ _clear();
+
+ String host;
+ String path;
+ String scheme;
+ int port = 0;
+ Error err = p_url.parse_url(scheme, host, port, path);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url);
+ if (scheme.is_empty()) {
+ scheme = "ws://";
+ }
+ ERR_FAIL_COND_V_MSG(scheme != "ws://" && scheme != "wss://", ERR_INVALID_PARAMETER, vformat("Invalid protocol: \"%s\" (must be either \"ws://\" or \"wss://\").", scheme));
+
+ use_tls = false;
+ if (scheme == "wss://") {
+ use_tls = true;
+ }
+ if (port == 0) {
+ port = use_tls ? 443 : 80;
+ }
+ if (path.is_empty()) {
+ path = "/";
+ }
+
+ requested_url = p_url;
+ requested_host = host;
+ verify_tls = p_verify_tls;
+ tls_cert = p_cert;
+ tcp.instantiate();
+
+ resolver.start(host, port);
+ resolver.try_next_candidate(tcp);
+
+ if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTING && tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED && !resolver.has_more_candidates()) {
+ _clear();
+ return FAILED;
+ }
+ connection = tcp;
+
+ // Prepare handshake request.
+ session_key = _generate_key();
+ String request = "GET " + path + " HTTP/1.1\r\n";
+ String port_string;
+ if ((port != 80 && !use_tls) || (port != 443 && use_tls)) {
+ port_string = ":" + itos(port);
+ }
+ request += "Host: " + host + port_string + "\r\n";
+ request += "Upgrade: websocket\r\n";
+ request += "Connection: Upgrade\r\n";
+ request += "Sec-WebSocket-Key: " + session_key + "\r\n";
+ request += "Sec-WebSocket-Version: 13\r\n";
+ if (supported_protocols.size() > 0) {
+ request += "Sec-WebSocket-Protocol: ";
+ for (int i = 0; i < supported_protocols.size(); i++) {
+ if (i != 0) {
+ request += ",";
+ }
+ request += supported_protocols[i];
+ }
+ request += "\r\n";
}
- return false;
+ for (int i = 0; i < handshake_headers.size(); i++) {
+ request += handshake_headers[i] + "\r\n";
+ }
+ request += "\r\n";
+ CharString cs = request.utf8();
+ handshake_buffer->put_data((const uint8_t *)cs.get_data(), cs.length());
+ handshake_buffer->seek(0);
+ ready_state = STATE_CONNECTING;
+ is_server = false;
+ return OK;
}
-ssize_t wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags, void *user_data) {
- struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
- if (!peer_data->valid) {
+///
+/// Callback functions.
+///
+ssize_t WSLPeer::_wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ Ref<StreamPeer> conn = peer->connection;
+ if (conn.is_null()) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
- Ref<StreamPeer> conn = peer_data->conn;
int read = 0;
Error err = conn->get_partial_data(data, len, read);
if (err != OK) {
@@ -111,13 +577,13 @@ ssize_t wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len
return read;
}
-ssize_t wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) {
- struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
- if (!peer_data->valid) {
+ssize_t WSLPeer::_wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ Ref<StreamPeer> conn = peer->connection;
+ if (conn.is_null()) {
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
- Ref<StreamPeer> conn = peer_data->conn;
int sent = 0;
Error err = conn->put_partial_data(data, len, sent);
if (err != OK) {
@@ -131,144 +597,142 @@ ssize_t wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size
return sent;
}
-int wsl_genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data) {
- RandomNumberGenerator rng;
- // TODO maybe use crypto in the future?
- rng.set_seed(OS::get_singleton()->get_unix_time());
- for (unsigned int i = 0; i < len; i++) {
- buf[i] = (uint8_t)rng.randi_range(0, 255);
- }
+int WSLPeer::_wsl_genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data) {
+ ERR_FAIL_COND_V(!_static_rng, WSLAY_ERR_CALLBACK_FAILURE);
+ Error err = _static_rng->get_random_bytes(buf, len);
+ ERR_FAIL_COND_V(err != OK, WSLAY_ERR_CALLBACK_FAILURE);
return 0;
}
-void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) {
- struct WSLPeer::PeerData *peer_data = (struct WSLPeer::PeerData *)user_data;
- if (!peer_data->valid || peer_data->closing) {
+void WSLPeer::_wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ uint8_t op = arg->opcode;
+
+ if (op == WSLAY_CONNECTION_CLOSE) {
+ // Close request or confirmation.
+ peer->close_code = arg->status_code;
+ size_t len = arg->msg_length;
+ peer->close_reason = "";
+ if (len > 2 /* first 2 bytes = close code */) {
+ peer->close_reason.parse_utf8((char *)arg->msg + 2, len - 2);
+ }
+ if (peer->ready_state == STATE_OPEN) {
+ peer->ready_state = STATE_CLOSING;
+ }
return;
}
- WSLPeer *peer = static_cast<WSLPeer *>(peer_data->peer);
- if (peer->parse_message(arg) != OK) {
+ if (peer->ready_state == STATE_CLOSING) {
return;
}
- if (peer_data->is_server) {
- WSLServer *helper = static_cast<WSLServer *>(peer_data->obj);
- helper->_on_peer_packet(peer_data->id);
- } else {
- WSLClient *helper = static_cast<WSLClient *>(peer_data->obj);
- helper->_on_peer_packet();
+ if (op == WSLAY_TEXT_FRAME || op == WSLAY_BINARY_FRAME) {
+ // Message.
+ uint8_t is_string = arg->opcode == WSLAY_TEXT_FRAME ? 1 : 0;
+ peer->in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
}
+ // Ping or pong.
}
-wslay_event_callbacks wsl_callbacks = {
- wsl_recv_callback,
- wsl_send_callback,
- wsl_genmask_callback,
+wslay_event_callbacks WSLPeer::_wsl_callbacks = {
+ _wsl_recv_callback,
+ _wsl_send_callback,
+ _wsl_genmask_callback,
nullptr, /* on_frame_recv_start_callback */
nullptr, /* on_frame_recv_callback */
nullptr, /* on_frame_recv_end_callback */
- wsl_msg_recv_callback
+ _wsl_msg_recv_callback
};
-Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) {
- uint8_t is_string = 0;
- if (arg->opcode == WSLAY_TEXT_FRAME) {
- is_string = 1;
- } else if (arg->opcode == WSLAY_CONNECTION_CLOSE) {
- close_code = arg->status_code;
- size_t len = arg->msg_length;
- close_reason = "";
- if (len > 2 /* first 2 bytes = close code */) {
- close_reason.parse_utf8((char *)arg->msg + 2, len - 2);
- }
- if (!wslay_event_get_close_sent(_data->ctx)) {
- if (_data->is_server) {
- WSLServer *helper = static_cast<WSLServer *>(_data->obj);
- helper->_on_close_request(_data->id, close_code, close_reason);
- } else {
- WSLClient *helper = static_cast<WSLClient *>(_data->obj);
- helper->_on_close_request(close_code, close_reason);
- }
- }
- return ERR_FILE_EOF;
- } else if (arg->opcode != WSLAY_BINARY_FRAME) {
- // Ping or pong
- return ERR_SKIP;
- }
- _in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
- return OK;
-}
-
-void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size) {
- ERR_FAIL_COND(_data != nullptr);
- ERR_FAIL_COND(p_data == nullptr);
-
- _in_buffer.resize(p_in_pkt_size, p_in_buf_size);
- _packet_buffer.resize(1 << p_in_buf_size);
- _out_buf_size = p_out_buf_size;
- _out_pkt_size = p_out_pkt_size;
-
- _data = p_data;
- _data->peer = this;
- _data->valid = true;
-
- if (_data->is_server) {
- wslay_event_context_server_init(&(_data->ctx), &wsl_callbacks, _data);
- } else {
- wslay_event_context_client_init(&(_data->ctx), &wsl_callbacks, _data);
- }
- wslay_event_config_set_max_recv_msg_length(_data->ctx, (1ULL << p_in_buf_size));
-}
-
-void WSLPeer::set_write_mode(WriteMode p_mode) {
- write_mode = p_mode;
+String WSLPeer::_generate_key() {
+ // Random key
+ Vector<uint8_t> bkey;
+ int len = 16; // 16 bytes, as per RFC
+ bkey.resize(len);
+ _wsl_genmask_callback(nullptr, bkey.ptrw(), len, nullptr);
+ return CryptoCore::b64_encode_str(bkey.ptrw(), len);
}
-WSLPeer::WriteMode WSLPeer::get_write_mode() const {
- return write_mode;
+String WSLPeer::_compute_key_response(String p_key) {
+ String key = p_key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Magic UUID as per RFC
+ Vector<uint8_t> sha = key.sha1_buffer();
+ return CryptoCore::b64_encode_str(sha.ptr(), sha.size());
}
void WSLPeer::poll() {
- if (!_data) {
+ // Nothing to do.
+ if (ready_state == STATE_CLOSED) {
return;
}
- if (_wsl_poll(_data)) {
- _data = nullptr;
+ if (ready_state == STATE_CONNECTING) {
+ if (is_server) {
+ _do_server_handshake();
+ } else {
+ _do_client_handshake();
+ }
+ }
+
+ if (ready_state == STATE_OPEN || ready_state == STATE_CLOSING) {
+ ERR_FAIL_COND(!wsl_ctx);
+ int err = 0;
+ if ((err = wslay_event_recv(wsl_ctx)) != 0 || (err = wslay_event_send(wsl_ctx)) != 0) {
+ // Error close.
+ print_verbose("Websocket (wslay) poll error: " + itos(err));
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ }
+ if (wslay_event_get_close_sent(wsl_ctx) && wslay_event_get_close_received(wsl_ctx)) {
+ // Clean close.
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ }
}
}
-Error WSLPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
- ERR_FAIL_COND_V(_out_pkt_size && (wslay_event_get_queued_msg_count(_data->ctx) >= (1ULL << _out_pkt_size)), ERR_OUT_OF_MEMORY);
- ERR_FAIL_COND_V(_out_buf_size && (wslay_event_get_queued_msg_length(_data->ctx) + p_buffer_size >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY);
+Error WSLPeer::_send(const uint8_t *p_buffer, int p_buffer_size, wslay_opcode p_opcode) {
+ ERR_FAIL_COND_V(ready_state != STATE_OPEN, FAILED);
+ ERR_FAIL_COND_V(wslay_event_get_queued_msg_count(wsl_ctx) >= (uint32_t)max_queued_packets, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_COND_V(outbound_buffer_size > 0 && (wslay_event_get_queued_msg_length(wsl_ctx) + p_buffer_size > (uint32_t)outbound_buffer_size), ERR_OUT_OF_MEMORY);
struct wslay_event_msg msg;
- msg.opcode = write_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME;
+ msg.opcode = p_opcode;
msg.msg = p_buffer;
msg.msg_length = p_buffer_size;
// Queue & send message.
- if (wslay_event_queue_msg(_data->ctx, &msg) != 0 || wslay_event_send(_data->ctx) != 0) {
- close_now();
+ if (wslay_event_queue_msg(wsl_ctx, &msg) != 0 || wslay_event_send(wsl_ctx) != 0) {
+ close(-1);
return FAILED;
}
return OK;
}
+Error WSLPeer::send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) {
+ wslay_opcode opcode = p_mode == WRITE_MODE_TEXT ? WSLAY_TEXT_FRAME : WSLAY_BINARY_FRAME;
+ return _send(p_buffer, p_buffer_size, opcode);
+}
+
+Error WSLPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+ return _send(p_buffer, p_buffer_size, WSLAY_BINARY_FRAME);
+}
+
Error WSLPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
r_buffer_size = 0;
- ERR_FAIL_COND_V(!is_connected_to_host(), FAILED);
+ ERR_FAIL_COND_V(ready_state != STATE_OPEN, FAILED);
- if (_in_buffer.packets_left() == 0) {
+ if (in_buffer.packets_left() == 0) {
return ERR_UNAVAILABLE;
}
int read = 0;
- uint8_t *rw = _packet_buffer.ptrw();
- _in_buffer.read_packet(rw, _packet_buffer.size(), &_is_string, read);
+ uint8_t *rw = packet_buffer.ptrw();
+ in_buffer.read_packet(rw, packet_buffer.size(), &was_string, read);
*r_buffer = rw;
r_buffer_size = read;
@@ -277,75 +741,106 @@ Error WSLPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
}
int WSLPeer::get_available_packet_count() const {
- if (!is_connected_to_host()) {
+ if (ready_state != STATE_OPEN) {
return 0;
}
- return _in_buffer.packets_left();
+ return in_buffer.packets_left();
}
int WSLPeer::get_current_outbound_buffered_amount() const {
- ERR_FAIL_COND_V(!_data, 0);
-
- return wslay_event_get_queued_msg_length(_data->ctx);
-}
-
-bool WSLPeer::was_string_packet() const {
- return _is_string;
-}
-
-bool WSLPeer::is_connected_to_host() const {
- return _data != nullptr;
-}
+ if (ready_state != STATE_OPEN) {
+ return 0;
+ }
-void WSLPeer::close_now() {
- close(1000, "");
- _wsl_destroy(&_data);
+ return wslay_event_get_queued_msg_length(wsl_ctx);
}
void WSLPeer::close(int p_code, String p_reason) {
- if (_data && !wslay_event_get_close_sent(_data->ctx)) {
+ if (p_code < 0) {
+ // Force immediate close.
+ ready_state = STATE_CLOSED;
+ }
+
+ if (ready_state == STATE_OPEN && !wslay_event_get_close_sent(wsl_ctx)) {
CharString cs = p_reason.utf8();
- wslay_event_queue_close(_data->ctx, p_code, (uint8_t *)cs.ptr(), cs.size());
- wslay_event_send(_data->ctx);
- _data->closing = true;
+ wslay_event_queue_close(wsl_ctx, p_code, (uint8_t *)cs.ptr(), cs.length());
+ wslay_event_send(wsl_ctx);
+ ready_state = STATE_CLOSING;
+ } else if (ready_state == STATE_CONNECTING || ready_state == STATE_CLOSED) {
+ ready_state = STATE_CLOSED;
+ connection.unref();
+ if (tcp.is_valid()) {
+ tcp->disconnect_from_host();
+ tcp.unref();
+ }
}
- _in_buffer.clear();
- _packet_buffer.resize(0);
+ in_buffer.clear();
+ packet_buffer.resize(0);
}
IPAddress WSLPeer::get_connected_host() const {
- ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IPAddress());
-
- return _data->tcp->get_connected_host();
+ ERR_FAIL_COND_V(tcp.is_null(), IPAddress());
+ return tcp->get_connected_host();
}
uint16_t WSLPeer::get_connected_port() const {
- ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), 0);
+ ERR_FAIL_COND_V(tcp.is_null(), 0);
+ return tcp->get_connected_port();
+}
+
+String WSLPeer::get_selected_protocol() const {
+ return selected_protocol;
+}
- return _data->tcp->get_connected_port();
+String WSLPeer::get_requested_url() const {
+ return requested_url;
}
void WSLPeer::set_no_delay(bool p_enabled) {
- ERR_FAIL_COND(!is_connected_to_host() || _data->tcp.is_null());
- _data->tcp->set_no_delay(p_enabled);
+ ERR_FAIL_COND(tcp.is_null());
+ tcp->set_no_delay(p_enabled);
}
-void WSLPeer::invalidate() {
- if (_data) {
- _data->valid = false;
+void WSLPeer::_clear() {
+ // Connection info.
+ ready_state = STATE_CLOSED;
+ is_server = false;
+ connection.unref();
+ if (tcp.is_valid()) {
+ tcp->disconnect_from_host();
+ tcp.unref();
}
+ if (wsl_ctx) {
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ }
+
+ resolver.stop();
+ requested_url.clear();
+ requested_host.clear();
+ pending_request = true;
+ handshake_buffer->clear();
+ selected_protocol.clear();
+ session_key.clear();
+
+ // Pending packets info.
+ was_string = 0;
+ in_buffer.clear();
+ packet_buffer.clear();
+
+ // Close code info.
+ close_code = -1;
+ close_reason.clear();
}
WSLPeer::WSLPeer() {
+ handshake_buffer.instantiate();
}
WSLPeer::~WSLPeer() {
- close();
- invalidate();
- _wsl_destroy(&_data);
- _data = nullptr;
+ close(-1);
}
#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 92672eb2c4..379002739c 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -33,79 +33,123 @@
#ifndef WEB_ENABLED
+#include "websocket_peer.h"
+
+#include "packet_buffer.h"
+
+#include "core/crypto/crypto_core.h"
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
#include "core/io/stream_peer_tcp.h"
#include "core/templates/ring_buffer.h"
-#include "packet_buffer.h"
-#include "websocket_peer.h"
#include "wslay/wslay.h"
#define WSL_MAX_HEADER_SIZE 4096
class WSLPeer : public WebSocketPeer {
- GDCIIMPL(WSLPeer, WebSocketPeer);
-
-public:
- struct PeerData {
- bool polling = false;
- bool destroy = false;
- bool valid = false;
- bool is_server = false;
- bool closing = false;
- void *obj = nullptr;
- void *peer = nullptr;
- Ref<StreamPeer> conn;
- Ref<StreamPeerTCP> tcp;
- int id = 1;
- wslay_event_context_ptr ctx = nullptr;
+private:
+ static CryptoCore::RandomGenerator *_static_rng;
+ static WebSocketPeer *_create() { return memnew(WSLPeer); }
+
+ // Callbacks.
+ static ssize_t _wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags, void *user_data);
+ static ssize_t _wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data);
+ static int _wsl_genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data);
+ static void _wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
+
+ static wslay_event_callbacks _wsl_callbacks;
+
+ // Helpers
+ static String _compute_key_response(String p_key);
+ static String _generate_key();
+
+ // Client IP resolver.
+ class Resolver {
+ Array ip_candidates;
+ IP::ResolverID resolver_id = IP::RESOLVER_INVALID_ID;
+ int port = 0;
+
+ public:
+ bool has_more_candidates() {
+ return ip_candidates.size() > 0 || resolver_id != IP::RESOLVER_INVALID_ID;
+ }
+
+ void try_next_candidate(Ref<StreamPeerTCP> &p_tcp);
+ void start(const String &p_host, int p_port);
+ void stop();
+ Resolver() {}
};
- static String compute_key_response(String p_key);
- static String generate_key();
+ Resolver resolver;
-private:
- static bool _wsl_poll(struct PeerData *p_data);
- static void _wsl_destroy(struct PeerData **p_data);
+ // WebSocket connection state.
+ WebSocketPeer::State ready_state = WebSocketPeer::STATE_CLOSED;
+ bool is_server = false;
+ Ref<StreamPeerTCP> tcp;
+ Ref<StreamPeer> connection;
+ wslay_event_context_ptr wsl_ctx = nullptr;
+
+ String requested_url;
+ String requested_host;
+ bool pending_request = true;
+ Ref<StreamPeerBuffer> handshake_buffer;
+ String selected_protocol;
+ String session_key;
- struct PeerData *_data = nullptr;
- uint8_t _is_string = 0;
+ int close_code = -1;
+ String close_reason;
+ uint8_t was_string = 0;
+
+ // WebSocket configuration.
+ bool use_tls = true;
+ bool verify_tls = true;
+ Ref<X509Certificate> tls_cert;
+
+ // Packet buffers.
+ Vector<uint8_t> packet_buffer;
// Our packet info is just a boolean (is_string), using uint8_t for it.
- PacketBuffer<uint8_t> _in_buffer;
+ PacketBuffer<uint8_t> in_buffer;
- Vector<uint8_t> _packet_buffer;
+ Error _send(const uint8_t *p_buffer, int p_buffer_size, wslay_opcode p_opcode);
- WriteMode write_mode = WRITE_MODE_BINARY;
+ Error _do_server_handshake();
+ bool _parse_client_request();
- int _out_buf_size = 0;
- int _out_pkt_size = 0;
+ void _do_client_handshake();
+ bool _verify_server_response();
+
+ void _clear();
public:
- int close_code = -1;
- String close_reason;
- void poll(); // Used by client and server.
+ static void initialize();
+ static void deinitialize();
+ // PacketPeer
virtual int get_available_packet_count() const override;
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const override;
+ virtual int get_max_packet_size() const override { return packet_buffer.size(); };
- virtual void close_now();
+ // WebSocketPeer
+ virtual Error send(const uint8_t *p_buffer, int p_buffer_size, WriteMode p_mode) override;
+ virtual Error connect_to_url(const String &p_url, bool p_verify_tls = true, Ref<X509Certificate> p_cert = Ref<X509Certificate>()) override;
+ virtual Error accept_stream(Ref<StreamPeer> p_stream) override;
virtual void close(int p_code = 1000, String p_reason = "") override;
- virtual bool is_connected_to_host() const override;
+ virtual void poll() override;
+
+ virtual State get_ready_state() const override { return ready_state; }
+ virtual int get_close_code() const override { return close_code; }
+ virtual String get_close_reason() const override { return close_reason; }
+ virtual int get_current_outbound_buffered_amount() const override;
+
virtual IPAddress get_connected_host() const override;
virtual uint16_t get_connected_port() const override;
+ virtual String get_selected_protocol() const override;
+ virtual String get_requested_url() const override;
- virtual WriteMode get_write_mode() const override;
- virtual void set_write_mode(WriteMode p_mode) override;
- virtual bool was_string_packet() const override;
+ virtual bool was_string_packet() const override { return was_string; }
virtual void set_no_delay(bool p_enabled) override;
- void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size);
- Error parse_message(const wslay_event_on_msg_recv_arg *arg);
- void invalidate();
-
WSLPeer();
~WSLPeer();
};
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
deleted file mode 100644
index 01dcd53839..0000000000
--- a/modules/websocket/wsl_server.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/*************************************************************************/
-/* wsl_server.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. */
-/*************************************************************************/
-
-#ifndef WEB_ENABLED
-
-#include "wsl_server.h"
-#include "core/config/project_settings.h"
-#include "core/os/os.h"
-
-bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, String &r_resource_name) {
- Vector<String> psa = String((char *)req_buf).split("\r\n");
- int len = psa.size();
- ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
-
- Vector<String> req = psa[0].split(" ", false);
- ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code.");
-
- // Wrong protocol
- ERR_FAIL_COND_V_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", false, "Invalid method or HTTP version.");
-
- r_resource_name = req[1];
- HashMap<String, String> headers;
- for (int i = 1; i < len; i++) {
- Vector<String> header = psa[i].split(":", false, 1);
- ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i]);
- String name = header[0].to_lower();
- String value = header[1].strip_edges();
- if (headers.has(name)) {
- headers[name] += "," + value;
- } else {
- headers[name] = value;
- }
- }
-#define WSL_CHECK(NAME, VALUE) \
- ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \
- "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'.");
-#define WSL_CHECK_EX(NAME) \
- ERR_FAIL_COND_V_MSG(!headers.has(NAME), false, "Missing header '" + String(NAME) + "'.");
- WSL_CHECK("upgrade", "websocket");
- WSL_CHECK("sec-websocket-version", "13");
- WSL_CHECK_EX("sec-websocket-key");
- WSL_CHECK_EX("connection");
-#undef WSL_CHECK_EX
-#undef WSL_CHECK
- key = headers["sec-websocket-key"];
- if (headers.has("sec-websocket-protocol")) {
- Vector<String> protos = headers["sec-websocket-protocol"].split(",");
- for (int i = 0; i < protos.size(); i++) {
- String proto = protos[i].strip_edges();
- // Check if we have the given protocol
- for (int j = 0; j < p_protocols.size(); j++) {
- if (proto != p_protocols[j]) {
- continue;
- }
- protocol = proto;
- break;
- }
- // Found a protocol
- if (!protocol.is_empty()) {
- break;
- }
- }
- if (protocol.is_empty()) { // Invalid protocol(s) requested
- return false;
- }
- } else if (p_protocols.size() > 0) { // No protocol requested, but we need one
- return false;
- }
- return true;
-}
-
-Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers) {
- if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) {
- print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001));
- return ERR_TIMEOUT;
- }
-
- if (use_tls) {
- Ref<StreamPeerTLS> tls = static_cast<Ref<StreamPeerTLS>>(connection);
- if (tls.is_null()) {
- ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerTLS for WebSocket handshake.");
- }
- tls->poll();
- if (tls->get_status() == StreamPeerTLS::STATUS_HANDSHAKING) {
- return ERR_BUSY;
- } else if (tls->get_status() != StreamPeerTLS::STATUS_CONNECTED) {
- print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerTLS status code %d).", tls->get_status()));
- return FAILED;
- }
- }
-
- if (!has_request) {
- int read = 0;
- while (true) {
- ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "WebSocket response headers are too big.");
- Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
- if (err != OK) { // Got an error
- print_verbose(vformat("WebSocket error while getting partial data (StreamPeer error code %d).", err));
- return FAILED;
- } else if (read != 1) { // Busy, wait next poll
- return ERR_BUSY;
- }
- char *r = (char *)req_buf;
- int l = req_pos;
- if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
- r[l - 3] = '\0';
- if (!_parse_request(p_protocols, r_resource_name)) {
- return FAILED;
- }
- String s = "HTTP/1.1 101 Switching Protocols\r\n";
- s += "Upgrade: websocket\r\n";
- s += "Connection: Upgrade\r\n";
- s += "Sec-WebSocket-Accept: " + WSLPeer::compute_key_response(key) + "\r\n";
- if (!protocol.is_empty()) {
- s += "Sec-WebSocket-Protocol: " + protocol + "\r\n";
- }
- for (int i = 0; i < p_extra_headers.size(); i++) {
- s += p_extra_headers[i] + "\r\n";
- }
- s += "\r\n";
- response = s.utf8();
- has_request = true;
- break;
- }
- req_pos += 1;
- }
- }
-
- if (has_request && response_sent < response.size() - 1) {
- int sent = 0;
- Error err = connection->put_partial_data((const uint8_t *)response.get_data() + response_sent, response.size() - response_sent - 1, sent);
- if (err != OK) {
- print_verbose(vformat("WebSocket error while putting partial data (StreamPeer error code %d).", err));
- return err;
- }
- response_sent += sent;
- }
-
- if (response_sent < response.size() - 1) {
- return ERR_BUSY;
- }
-
- return OK;
-}
-
-void WSLServer::set_extra_headers(const Vector<String> &p_headers) {
- _extra_headers = p_headers;
-}
-
-Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp_api) {
- ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE);
-
- _is_multiplayer = gd_mp_api;
- // Strip edges from protocols.
- _protocols.resize(p_protocols.size());
- String *pw = _protocols.ptrw();
- for (int i = 0; i < p_protocols.size(); i++) {
- pw[i] = p_protocols[i].strip_edges();
- }
- return _server->listen(p_port, bind_ip);
-}
-
-void WSLServer::poll() {
- List<int> remove_ids;
- for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
- peer->poll();
- if (!peer->is_connected_to_host()) {
- _on_disconnect(E.key, peer->close_code != -1);
- remove_ids.push_back(E.key);
- }
- }
- for (int &E : remove_ids) {
- _peer_map.erase(E);
- }
- remove_ids.clear();
-
- List<Ref<PendingPeer>> remove_peers;
- for (const Ref<PendingPeer> &E : _pending) {
- String resource_name;
- Ref<PendingPeer> ppeer = E;
- Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name, _extra_headers);
- if (err == ERR_BUSY) {
- continue;
- } else if (err != OK) {
- remove_peers.push_back(ppeer);
- continue;
- }
- // Creating new peer
- int32_t id = generate_unique_id();
-
- WSLPeer::PeerData *data = memnew(struct WSLPeer::PeerData);
- data->obj = this;
- data->conn = ppeer->connection;
- data->tcp = ppeer->tcp;
- data->is_server = true;
- data->id = id;
-
- Ref<WSLPeer> ws_peer = memnew(WSLPeer);
- ws_peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
- ws_peer->set_no_delay(true);
-
- _peer_map[id] = ws_peer;
- remove_peers.push_back(ppeer);
- _on_connect(id, ppeer->protocol, resource_name);
- }
- for (const Ref<PendingPeer> &E : remove_peers) {
- _pending.erase(E);
- }
- remove_peers.clear();
-
- if (!_server->is_listening()) {
- return;
- }
-
- while (_server->is_connection_available()) {
- Ref<StreamPeerTCP> conn = _server->take_connection();
- if (is_refusing_new_connections()) {
- continue; // Conn will go out-of-scope and be closed.
- }
-
- Ref<PendingPeer> peer = memnew(PendingPeer);
- if (private_key.is_valid() && tls_cert.is_valid()) {
- Ref<StreamPeerTLS> tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
- tls->set_blocking_handshake_enabled(false);
- tls->accept_stream(conn, private_key, tls_cert, ca_chain);
- peer->connection = tls;
- peer->use_tls = true;
- } else {
- peer->connection = conn;
- }
- peer->tcp = conn;
- peer->time = OS::get_singleton()->get_ticks_msec();
- _pending.push_back(peer);
- }
-}
-
-bool WSLServer::is_listening() const {
- return _server->is_listening();
-}
-
-int WSLServer::get_max_packet_size() const {
- return (1 << _out_buf_size) - PROTO_SIZE;
-}
-
-void WSLServer::stop() {
- _server->stop();
- for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
- peer->close_now();
- }
- _pending.clear();
- _peer_map.clear();
- _protocols.clear();
-}
-
-bool WSLServer::has_peer(int p_id) const {
- return _peer_map.has(p_id);
-}
-
-Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const {
- ERR_FAIL_COND_V(!has_peer(p_id), nullptr);
- return _peer_map[p_id];
-}
-
-IPAddress WSLServer::get_peer_address(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), IPAddress());
-
- return _peer_map[p_peer_id]->get_connected_host();
-}
-
-int WSLServer::get_peer_port(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), 0);
-
- return _peer_map[p_peer_id]->get_connected_port();
-}
-
-void WSLServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
- ERR_FAIL_COND(!has_peer(p_peer_id));
-
- get_peer(p_peer_id)->close(p_code, p_reason);
-}
-
-Error WSLServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- ERR_FAIL_COND_V_MSG(_server->is_listening(), FAILED, "Buffers sizes can only be set before listening or connecting.");
-
- _in_buf_size = nearest_shift(p_in_buffer - 1) + 10;
- _in_pkt_size = nearest_shift(p_in_packets - 1);
- _out_buf_size = nearest_shift(p_out_buffer - 1) + 10;
- _out_pkt_size = nearest_shift(p_out_packets - 1);
- return OK;
-}
-
-WSLServer::WSLServer() {
- _server.instantiate();
-}
-
-WSLServer::~WSLServer() {
- stop();
-}
-
-#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
deleted file mode 100644
index df0c1dc68a..0000000000
--- a/modules/websocket/wsl_server.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*************************************************************************/
-/* wsl_server.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 WSL_SERVER_H
-#define WSL_SERVER_H
-
-#ifndef WEB_ENABLED
-
-#include "websocket_server.h"
-#include "wsl_peer.h"
-
-#include "core/io/stream_peer_tcp.h"
-#include "core/io/stream_peer_tls.h"
-#include "core/io/tcp_server.h"
-
-class WSLServer : public WebSocketServer {
- GDCIIMPL(WSLServer, WebSocketServer);
-
-private:
- class PendingPeer : public RefCounted {
- private:
- bool _parse_request(const Vector<String> p_protocols, String &r_resource_name);
-
- public:
- Ref<StreamPeerTCP> tcp;
- Ref<StreamPeer> connection;
- bool use_tls = false;
-
- uint64_t time = 0;
- uint8_t req_buf[WSL_MAX_HEADER_SIZE] = {};
- int req_pos = 0;
- String key;
- String protocol;
- bool has_request = false;
- CharString response;
- int response_sent = 0;
-
- Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers);
- };
-
- int _in_buf_size = DEF_BUF_SHIFT;
- int _in_pkt_size = DEF_PKT_SHIFT;
- int _out_buf_size = DEF_BUF_SHIFT;
- int _out_pkt_size = DEF_PKT_SHIFT;
-
- List<Ref<PendingPeer>> _pending;
- Ref<TCPServer> _server;
- Vector<String> _protocols;
- Vector<String> _extra_headers;
-
-public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
- void set_extra_headers(const Vector<String> &p_headers) override;
- Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
- void stop() override;
- bool is_listening() const override;
- int get_max_packet_size() const override;
- bool has_peer(int p_id) const override;
- Ref<WebSocketPeer> get_peer(int p_id) const override;
- IPAddress get_peer_address(int p_peer_id) const override;
- int get_peer_port(int p_peer_id) const override;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
- virtual void poll() override;
-
- WSLServer();
- ~WSLServer();
-};
-
-#endif // WEB_ENABLED
-
-#endif // WSL_SERVER_H
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 49ff454f07..49dd9f7318 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -18,16 +18,16 @@
func _ready():
# We assume this node has a button as a child.
# This button is for the user to consent to entering immersive VR mode.
- $Button.connect("pressed", self, "_on_Button_pressed")
+ $Button.pressed.connect(self._on_Button_pressed)
webxr_interface = XRServer.find_interface("WebXR")
if webxr_interface:
# WebXR uses a lot of asynchronous callbacks, so we connect to various
# signals in order to receive them.
- webxr_interface.connect("session_supported", self, "_webxr_session_supported")
- webxr_interface.connect("session_started", self, "_webxr_session_started")
- webxr_interface.connect("session_ended", self, "_webxr_session_ended")
- webxr_interface.connect("session_failed", self, "_webxr_session_failed")
+ webxr_interface.session_supported.connect(self._webxr_session_supported)
+ webxr_interface.session_started.connect(self._webxr_session_started)
+ webxr_interface.session_ended.connect(self._webxr_session_ended)
+ webxr_interface.session_failed.connect(self._webxr_session_failed)
# This returns immediately - our _webxr_session_supported() method
# (which we connected to the "session_supported" signal above) will
diff --git a/modules/webxr/godot_webxr.h b/modules/webxr/godot_webxr.h
index 34d068be3e..d8d5bd99cc 100644
--- a/modules/webxr/godot_webxr.h
+++ b/modules/webxr/godot_webxr.h
@@ -65,7 +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 void godot_webxr_commit_for_eye(int p_eye, unsigned int p_destination_fbo);
+extern void godot_webxr_commit(unsigned int p_texture);
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 9b75796ee5..c476a54c59 100644
--- a/modules/webxr/native/library_godot_webxr.js
+++ b/modules/webxr/native/library_godot_webxr.js
@@ -337,20 +337,18 @@ const GodotWebXR = {
return buf;
},
- godot_webxr_commit_for_eye__proxy: 'sync',
- godot_webxr_commit_for_eye__sig: 'vii',
- godot_webxr_commit_for_eye: function (p_eye, p_destination_fbo) {
+ godot_webxr_commit__proxy: 'sync',
+ godot_webxr_commit__sig: 'vi',
+ godot_webxr_commit: function (p_texture) {
if (!GodotWebXR.session || !GodotWebXR.pose) {
return;
}
- const view_index = (p_eye === 2 /* ARVRInterface::EYE_RIGHT */) ? 1 : 0;
const glLayer = GodotWebXR.session.renderState.baseLayer;
- const view = GodotWebXR.pose.views[view_index];
- const viewport = glLayer.getViewport(view);
+ const views = GodotWebXR.pose.views;
const gl = GodotWebXR.gl;
- const framebuffer = GL.framebuffers[p_destination_fbo];
+ const texture = GL.textures[p_texture];
const orig_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
const orig_read_framebuffer = gl.getParameter(gl.READ_FRAMEBUFFER_BINDING);
@@ -359,14 +357,27 @@ const GodotWebXR = {
// 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);
-
- // 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);
+ for (let i = 0; i < views.length; i++) {
+ const viewport = glLayer.getViewport(views[i]);
+
+ const read_fbo = gl.createFramebuffer();
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, read_fbo);
+ if (views.length > 1) {
+ gl.framebufferTextureLayer(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, texture, 0, i);
+ } else {
+ gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
+ }
+ gl.readBuffer(gl.COLOR_ATTACHMENT0);
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, glLayer.framebuffer);
+
+ // Flip Y upside down on destination.
+ gl.blitFramebuffer(0, 0, viewport.width, viewport.height,
+ viewport.x, viewport.y + viewport.height, viewport.x + viewport.width, viewport.y,
+ gl.COLOR_BUFFER_BIT, gl.NEAREST);
+
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
+ gl.deleteFramebuffer(read_fbo);
+ }
// Restore state.
gl.bindFramebuffer(gl.FRAMEBUFFER, orig_framebuffer);
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index d0c7484aa1..f6ed9f027e 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -388,15 +388,15 @@ Projection WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_a
int k = 0;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- eye.matrix[i][j] = js_matrix[k++];
+ eye.columns[i][j] = js_matrix[k++];
}
}
free(js_matrix);
// Copied from godot_oculus_mobile's ovr_mobile_session.cpp
- eye.matrix[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near);
- eye.matrix[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near);
+ eye.columns[2][2] = -(p_z_far + p_z_near) / (p_z_far - p_z_near);
+ eye.columns[3][2] = -(2.0f * p_z_far * p_z_near) / (p_z_far - p_z_near);
return eye;
}
@@ -415,8 +415,7 @@ Vector<BlitToScreen> WebXRInterfaceJS::post_draw_viewport(RID p_render_target, c
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
- // @todo Support multiple eyes!
- godot_webxr_commit_for_eye(1, rt->fbo);
+ godot_webxr_commit(rt->color);
return blit_to_screen;
};
diff --git a/modules/zip/SCsub b/modules/zip/SCsub
new file mode 100644
index 0000000000..b7710123fd
--- /dev/null
+++ b/modules/zip/SCsub
@@ -0,0 +1,9 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_zip = env_modules.Clone()
+
+# Module files
+env_zip.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/zip/config.py b/modules/zip/config.py
new file mode 100644
index 0000000000..96cd2fc5bd
--- /dev/null
+++ b/modules/zip/config.py
@@ -0,0 +1,17 @@
+def can_build(env, platform):
+ return env["minizip"]
+
+
+def configure(env):
+ pass
+
+
+def get_doc_classes():
+ return [
+ "ZIPReader",
+ "ZIPPacker",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/zip/doc_classes/ZIPPacker.xml b/modules/zip/doc_classes/ZIPPacker.xml
new file mode 100644
index 0000000000..95d7ef50f9
--- /dev/null
+++ b/modules/zip/doc_classes/ZIPPacker.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ZIPPacker" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Allows the creation of zip files.
+ </brief_description>
+ <description>
+ This class implements a writer that allows storing the multiple blobs in a zip archive.
+ [codeblock]
+ func write_zip_file():
+ var writer := ZIPPacker.new()
+ var err := writer.open("user://archive.zip")
+ if err != OK:
+ return err
+ writer.start_file("hello.txt")
+ writer.write_file("Hello World".to_utf8_buffer())
+ writer.close_file()
+
+ writer.close()
+ return OK
+ [/codeblock]
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="close">
+ <return type="int" enum="Error" />
+ <description>
+ Closes the underlying resources used by this instance.
+ </description>
+ </method>
+ <method name="close_file">
+ <return type="int" enum="Error" />
+ <description>
+ Stops writing to a file within the archive.
+ It will fail if there is no open file.
+ </description>
+ </method>
+ <method name="open">
+ <return type="int" enum="Error" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="append" type="int" enum="ZIPPacker.ZipAppend" default="0" />
+ <description>
+ Opens a zip file for writing at the given path using the specified write mode.
+ This must be called before everything else.
+ </description>
+ </method>
+ <method name="start_file">
+ <return type="int" enum="Error" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Starts writing to a file within the archive. Only one file can be written at the same time.
+ Must be called after [method open].
+ </description>
+ </method>
+ <method name="write_file">
+ <return type="int" enum="Error" />
+ <param index="0" name="data" type="PackedByteArray" />
+ <description>
+ Write the given [param data] to the file.
+ Needs to be called after [method start_file].
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="APPEND_CREATE" value="0" enum="ZipAppend">
+ </constant>
+ <constant name="APPEND_CREATEAFTER" value="1" enum="ZipAppend">
+ </constant>
+ <constant name="APPEND_ADDINZIP" value="2" enum="ZipAppend">
+ </constant>
+ </constants>
+</class>
diff --git a/modules/zip/doc_classes/ZIPReader.xml b/modules/zip/doc_classes/ZIPReader.xml
new file mode 100644
index 0000000000..717116a531
--- /dev/null
+++ b/modules/zip/doc_classes/ZIPReader.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ZIPReader" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+ <brief_description>
+ Allows reading the content of a zip file.
+ </brief_description>
+ <description>
+ This class implements a reader that can extract the content of individual files inside a zip archive.
+ [codeblock]
+ func read_zip_file():
+ var reader := ZIPReader.new()
+ var err := reader.open("user://archive.zip")
+ if err == OK:
+ return PackedByteArray()
+ var res := reader.read_file("hello.txt")
+ reader.close()
+ return res
+ [/codeblock]
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="close">
+ <return type="int" enum="Error" />
+ <description>
+ Closes the underlying resources used by this instance.
+ </description>
+ </method>
+ <method name="get_files">
+ <return type="PackedStringArray" />
+ <description>
+ Returns the list of names of all files in the loaded archive.
+ Must be called after [method open].
+ </description>
+ </method>
+ <method name="open">
+ <return type="int" enum="Error" />
+ <param index="0" name="path" type="String" />
+ <description>
+ Opens the zip archive at the given [param path] and reads its file index.
+ </description>
+ </method>
+ <method name="read_file">
+ <return type="PackedByteArray" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="case_sensitive" type="bool" default="true" />
+ <description>
+ Loads the whole content of a file in the loaded zip archive into memory and returns it.
+ Must be called after [method open].
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/zip/register_types.cpp b/modules/zip/register_types.cpp
new file mode 100644
index 0000000000..20fb484cfe
--- /dev/null
+++ b/modules/zip/register_types.cpp
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* register_types.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 "register_types.h"
+
+#include "core/object/class_db.h"
+#include "zip_packer.h"
+#include "zip_reader.h"
+
+void initialize_zip_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
+ GDREGISTER_CLASS(ZIPPacker);
+ GDREGISTER_CLASS(ZIPReader);
+}
+
+void uninitialize_zip_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/zip/register_types.h b/modules/zip/register_types.h
new file mode 100644
index 0000000000..2640be12b8
--- /dev/null
+++ b/modules/zip/register_types.h
@@ -0,0 +1,39 @@
+/*************************************************************************/
+/* register_types.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 ZIP_REGISTER_TYPES_H
+#define ZIP_REGISTER_TYPES_H
+
+#include "modules/register_module_types.h"
+
+void initialize_zip_module(ModuleInitializationLevel p_level);
+void uninitialize_zip_module(ModuleInitializationLevel p_level);
+
+#endif // ZIP_REGISTER_TYPES_H
diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp
new file mode 100644
index 0000000000..e62700f191
--- /dev/null
+++ b/modules/zip/zip_packer.cpp
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* zip_packer.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 "zip_packer.h"
+
+#include "core/io/zip_io.h"
+#include "core/os/os.h"
+
+Error ZIPPacker::open(String p_path, ZipAppend p_append) {
+ if (fa.is_valid()) {
+ close();
+ }
+
+ zlib_filefunc_def io = zipio_create_io(&fa);
+ zf = zipOpen2(p_path.utf8().get_data(), p_append, NULL, &io);
+ return zf != NULL ? OK : FAILED;
+}
+
+Error ZIPPacker::close() {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker cannot be closed because it is not open.");
+
+ return zipClose(zf, NULL) == ZIP_OK ? OK : FAILED;
+}
+
+Error ZIPPacker::start_file(String p_path) {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
+
+ zip_fileinfo zipfi;
+
+ OS::DateTime time = OS::get_singleton()->get_datetime();
+
+ zipfi.tmz_date.tm_hour = time.hour;
+ zipfi.tmz_date.tm_mday = time.day;
+ zipfi.tmz_date.tm_min = time.minute;
+ zipfi.tmz_date.tm_mon = time.month - 1;
+ zipfi.tmz_date.tm_sec = time.second;
+ zipfi.tmz_date.tm_year = time.year;
+ zipfi.dosDate = 0;
+ zipfi.external_fa = 0;
+ zipfi.internal_fa = 0;
+
+ int ret = zipOpenNewFileInZip(zf, p_path.utf8().get_data(), &zipfi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION);
+ return ret == ZIP_OK ? OK : FAILED;
+}
+
+Error ZIPPacker::write_file(Vector<uint8_t> p_data) {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
+
+ return zipWriteInFileInZip(zf, p_data.ptr(), p_data.size()) == ZIP_OK ? OK : FAILED;
+}
+
+Error ZIPPacker::close_file() {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
+
+ Error err = zipCloseFileInZip(zf) == ZIP_OK ? OK : FAILED;
+ if (err == OK) {
+ zf = NULL;
+ }
+ return err;
+}
+
+void ZIPPacker::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("open", "path", "append"), &ZIPPacker::open, DEFVAL(Variant(APPEND_CREATE)));
+ ClassDB::bind_method(D_METHOD("start_file", "path"), &ZIPPacker::start_file);
+ ClassDB::bind_method(D_METHOD("write_file", "data"), &ZIPPacker::write_file);
+ ClassDB::bind_method(D_METHOD("close_file"), &ZIPPacker::close_file);
+ ClassDB::bind_method(D_METHOD("close"), &ZIPPacker::close);
+
+ BIND_ENUM_CONSTANT(APPEND_CREATE);
+ BIND_ENUM_CONSTANT(APPEND_CREATEAFTER);
+ BIND_ENUM_CONSTANT(APPEND_ADDINZIP);
+}
+
+ZIPPacker::ZIPPacker() {}
+
+ZIPPacker::~ZIPPacker() {
+ if (fa.is_valid()) {
+ close();
+ }
+}
diff --git a/modules/websocket/websocket_client.h b/modules/zip/zip_packer.h
index e747aee4e4..23e96b5ad2 100644
--- a/modules/websocket/websocket_client.h
+++ b/modules/zip/zip_packer.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* websocket_client.h */
+/* zip_packer.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,48 +28,41 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WEBSOCKET_CLIENT_H
-#define WEBSOCKET_CLIENT_H
+#ifndef ZIP_PACKER_H
+#define ZIP_PACKER_H
-#include "core/crypto/crypto.h"
-#include "core/error/error_list.h"
-#include "websocket_multiplayer_peer.h"
-#include "websocket_peer.h"
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
-class WebSocketClient : public WebSocketMultiplayerPeer {
- GDCLASS(WebSocketClient, WebSocketMultiplayerPeer);
- GDCICLASS(WebSocketClient);
+#include "thirdparty/minizip/zip.h"
-protected:
- Ref<WebSocketPeer> _peer;
- bool verify_tls = true;
- Ref<X509Certificate> tls_cert;
+class ZIPPacker : public RefCounted {
+ GDCLASS(ZIPPacker, RefCounted);
+
+ Ref<FileAccess> fa;
+ zipFile zf;
+protected:
static void _bind_methods();
public:
- Error connect_to_url(String p_url, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false, const Vector<String> p_custom_headers = Vector<String>());
+ enum ZipAppend {
+ APPEND_CREATE = 0,
+ APPEND_CREATEAFTER = 1,
+ APPEND_ADDINZIP = 2,
+ };
- void set_verify_tls_enabled(bool p_verify_tls);
- bool is_verify_tls_enabled() const;
- Ref<X509Certificate> get_trusted_tls_certificate() const;
- void set_trusted_tls_certificate(Ref<X509Certificate> p_cert);
+ Error open(String p_path, ZipAppend p_append);
+ Error close();
- virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_tls, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) = 0;
- virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0;
- virtual IPAddress get_connected_host() const = 0;
- virtual uint16_t get_connected_port() const = 0;
+ Error start_file(String p_path);
+ Error write_file(Vector<uint8_t> p_data);
+ Error close_file();
- virtual bool is_server() const override;
-
- void _on_peer_packet();
- void _on_connect(String p_protocol);
- void _on_close_request(int p_code, String p_reason);
- void _on_disconnect(bool p_was_clean);
- void _on_error();
-
- WebSocketClient();
- ~WebSocketClient();
+ ZIPPacker();
+ ~ZIPPacker();
};
-#endif // WEBSOCKET_CLIENT_H
+VARIANT_ENUM_CAST(ZIPPacker::ZipAppend)
+
+#endif // ZIP_PACKER_H
diff --git a/modules/zip/zip_reader.cpp b/modules/zip/zip_reader.cpp
new file mode 100644
index 0000000000..f35b947cef
--- /dev/null
+++ b/modules/zip/zip_reader.cpp
@@ -0,0 +1,123 @@
+/*************************************************************************/
+/* zip_reader.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 "zip_reader.h"
+
+#include "core/error/error_macros.h"
+#include "core/io/zip_io.h"
+
+Error ZIPReader::open(String p_path) {
+ if (fa.is_valid()) {
+ close();
+ }
+
+ zlib_filefunc_def io = zipio_create_io(&fa);
+ uzf = unzOpen2(p_path.utf8().get_data(), &io);
+ return uzf != NULL ? OK : FAILED;
+}
+
+Error ZIPReader::close() {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPReader cannot be closed because it is not open.");
+
+ return unzClose(uzf) == UNZ_OK ? OK : FAILED;
+}
+
+PackedStringArray ZIPReader::get_files() {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), PackedStringArray(), "ZIPReader must be opened before use.");
+
+ List<String> s;
+
+ if (unzGoToFirstFile(uzf) != UNZ_OK) {
+ return PackedStringArray();
+ }
+
+ do {
+ unz_file_info64 file_info;
+ char filename[256]; // Note filename is a path !
+ int err = unzGetCurrentFileInfo64(uzf, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0);
+ if (err == UNZ_OK) {
+ s.push_back(filename);
+ } else {
+ // Assume filename buffer was too small
+ char *long_filename_buff = (char *)memalloc(file_info.size_filename);
+ int err2 = unzGetCurrentFileInfo64(uzf, NULL, long_filename_buff, sizeof(long_filename_buff), NULL, 0, NULL, 0);
+ if (err2 == UNZ_OK) {
+ s.push_back(long_filename_buff);
+ memfree(long_filename_buff);
+ }
+ }
+ } while (unzGoToNextFile(uzf) == UNZ_OK);
+
+ PackedStringArray arr;
+ arr.resize(s.size());
+ int idx = 0;
+ for (const List<String>::Element *E = s.front(); E; E = E->next()) {
+ arr.set(idx++, E->get());
+ }
+ return arr;
+}
+
+PackedByteArray ZIPReader::read_file(String p_path, bool p_case_sensitive) {
+ ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "ZIPReader must be opened before use.");
+
+ int cs = p_case_sensitive ? 1 : 2;
+ if (unzLocateFile(uzf, p_path.utf8().get_data(), cs) != UNZ_OK) {
+ ERR_FAIL_V_MSG(PackedByteArray(), "File does not exist in zip archive: " + p_path);
+ }
+ if (unzOpenCurrentFile(uzf) != UNZ_OK) {
+ ERR_FAIL_V_MSG(PackedByteArray(), "Could not open file within zip archive.");
+ }
+
+ unz_file_info info;
+ unzGetCurrentFileInfo(uzf, &info, NULL, 0, NULL, 0, NULL, 0);
+ PackedByteArray data;
+ data.resize(info.uncompressed_size);
+
+ uint8_t *w = data.ptrw();
+ unzReadCurrentFile(uzf, &w[0], info.uncompressed_size);
+
+ unzCloseCurrentFile(uzf);
+ return data;
+}
+
+ZIPReader::ZIPReader() {}
+
+ZIPReader::~ZIPReader() {
+ if (fa.is_valid()) {
+ close();
+ }
+}
+
+void ZIPReader::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("open", "path"), &ZIPReader::open);
+ ClassDB::bind_method(D_METHOD("close"), &ZIPReader::close);
+ ClassDB::bind_method(D_METHOD("get_files"), &ZIPReader::get_files);
+ ClassDB::bind_method(D_METHOD("read_file", "path", "case_sensitive"), &ZIPReader::read_file, DEFVAL(Variant(true)));
+}
diff --git a/modules/zip/zip_reader.h b/modules/zip/zip_reader.h
new file mode 100644
index 0000000000..fbc2fc0409
--- /dev/null
+++ b/modules/zip/zip_reader.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* zip_reader.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 ZIP_READER_H
+#define ZIP_READER_H
+
+#include "core/io/file_access.h"
+#include "core/object/ref_counted.h"
+
+#include "thirdparty/minizip/unzip.h"
+
+class ZIPReader : public RefCounted {
+ GDCLASS(ZIPReader, RefCounted)
+
+ Ref<FileAccess> fa;
+ unzFile uzf;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error open(String p_path);
+ Error close();
+
+ PackedStringArray get_files();
+ PackedByteArray read_file(String p_path, bool p_case_sensitive);
+
+ ZIPReader();
+ ~ZIPReader();
+};
+
+#endif // ZIP_READER_H
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 9f5b8d8387..e4d04f1df9 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -53,10 +53,10 @@ else:
print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin")
if lib_arch_dir != "":
- if env.debug_features:
- lib_type_dir = "debug"
- elif env.dev_build:
+ if env.dev_build:
lib_type_dir = "dev"
+ elif env.debug_features:
+ lib_type_dir = "debug"
else: # Release
lib_type_dir = "release"
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 454bcd2eda..c0b098cd7f 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -118,7 +118,7 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycod
Input::get_singleton()->parse_input_event(ev);
}
-void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
+void AndroidInputHandler::_parse_all_touch(bool p_pressed, bool p_double_tap) {
if (touch.size()) {
//end all if exist
for (int i = 0; i < touch.size(); i++) {
@@ -127,17 +127,18 @@ void AndroidInputHandler::_parse_all_touch(bool p_pressed) {
ev->set_index(touch[i].id);
ev->set_pressed(p_pressed);
ev->set_position(touch[i].pos);
+ ev->set_double_tap(p_double_tap);
Input::get_singleton()->parse_input_event(ev);
}
}
}
void AndroidInputHandler::_release_all_touch() {
- _parse_all_touch(false);
+ _parse_all_touch(false, false);
touch.clear();
}
-void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points) {
+void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap) {
switch (p_event) {
case AMOTION_EVENT_ACTION_DOWN: { //gesture begin
// Release any remaining touches or mouse event
@@ -151,7 +152,7 @@ void AndroidInputHandler::process_touch_event(int p_event, int p_pointer, const
}
//send touch
- _parse_all_touch(true);
+ _parse_all_touch(true, p_double_tap);
} break;
case AMOTION_EVENT_ACTION_MOVE: { //motion
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 88490f0407..4da8a910c0 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -87,13 +87,13 @@ private:
void _release_mouse_event_info(bool p_source_mouse_relative = false);
- void _parse_all_touch(bool p_pressed);
+ void _parse_all_touch(bool p_pressed, bool p_double_tap);
void _release_all_touch();
public:
void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
- void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points);
+ void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
void process_joy_event(JoypadEvent p_event);
diff --git a/platform/android/api/jni_singleton.h b/platform/android/api/jni_singleton.h
index 690fddae21..895bc70103 100644
--- a/platform/android/api/jni_singleton.h
+++ b/platform/android/api/jni_singleton.h
@@ -150,9 +150,8 @@ public:
env->DeleteLocalRef(arr);
} break;
-#ifndef _MSC_VER
-#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
-#endif
+ // TODO: This is missing 64 bits arrays, I have no idea how to do it in JNI.
+
case Variant::DICTIONARY: {
jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
ret = _jobject_to_variant(env, obj);
diff --git a/platform/android/detect.py b/platform/android/detect.py
index e541aa0373..6eb8ba34ed 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -156,22 +156,16 @@ def configure(env: "Environment"):
env["RANLIB"] = compiler_path + "/llvm-ranlib"
env["AS"] = compiler_path + "/clang"
- # Disable exceptions and rtti on non-tools (template) builds
- if env.editor_build:
- env.Append(CXXFLAGS=["-frtti"])
- elif env["builtin_icu"]:
- env.Append(CXXFLAGS=["-frtti", "-fno-exceptions"])
- else:
- env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
- # Don't use dynamic_cast, necessary with no-rtti.
- env.Append(CPPDEFINES=["NO_SAFE_CAST"])
+ # Disable exceptions on template builds
+ if not env.editor_build:
+ env.Append(CXXFLAGS=["-fno-exceptions"])
env.Append(
CCFLAGS=(
"-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split()
)
)
- env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"])
+ env.Append(CPPDEFINES=["GLES_ENABLED"])
if get_min_sdk_version(env["ndk_platform"]) >= 24:
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
@@ -193,7 +187,7 @@ def configure(env: "Environment"):
env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so")
env.Prepend(CPPPATH=["#platform/android"])
- env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED", "NO_FCNTL"])
+ env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
env.Append(LIBS=["OpenSLES", "EGL", "GLESv2", "android", "log", "z", "dl"])
if env["vulkan"]:
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index d3bce12de1..08369e735d 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -440,8 +440,8 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
}
@@ -463,7 +463,7 @@ void DisplayServerAndroid::reset_window() {
context_vulkan->window_destroy(MAIN_WINDOW_ID);
Size2i display_size = OS_Android::get_singleton()->get_display_size();
- if (context_vulkan->window_create(native_window, last_vsync_mode, display_size.width, display_size.height) == -1) {
+ if (context_vulkan->window_create(native_window, last_vsync_mode, display_size.width, display_size.height) != OK) {
memdelete(context_vulkan);
context_vulkan = nullptr;
ERR_FAIL_MSG("Failed to reset Vulkan window.");
@@ -485,7 +485,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) {
rect_changed_callback.callp(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce);
}
-DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
// TODO: rendering_driver is broken, change when different drivers are supported again
@@ -529,7 +529,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
}
Size2i display_size = OS_Android::get_singleton()->get_display_size();
- if (context_vulkan->window_create(native_window, p_vsync_mode, display_size.width, display_size.height) == -1) {
+ if (context_vulkan->window_create(native_window, p_vsync_mode, display_size.width, display_size.height) != OK) {
memdelete(context_vulkan);
context_vulkan = nullptr;
ERR_FAIL_MSG("Failed to create Vulkan window.");
@@ -580,6 +580,9 @@ void DisplayServerAndroid::process_gyroscope(const Vector3 &p_gyroscope) {
}
void DisplayServerAndroid::mouse_set_mode(MouseMode p_mode) {
+ if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon() || !OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_capture_pointer()) {
+ return;
+ }
if (mouse_mode == p_mode) {
return;
}
@@ -612,6 +615,9 @@ MouseButton DisplayServerAndroid::mouse_get_button_state() const {
}
void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
+ if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon()) {
+ return;
+ }
if (cursor_shape == p_shape) {
return;
}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 6e14ba3e23..a6bc88e048 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -194,7 +194,7 @@ public:
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_android_driver();
@@ -204,7 +204,7 @@ public:
virtual Point2i mouse_get_position() const override;
virtual MouseButton mouse_get_button_state() const override;
- DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerAndroid();
};
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 366bd1c48c..3bfdd3b881 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -401,7 +401,7 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
}
}
- if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) {
+ if (EDITOR_GET("export/android/shutdown_adb_on_exit")) {
String adb = get_adb_path();
if (!FileAccess::exists(adb)) {
return; //adb not configured
@@ -419,7 +419,7 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const
if (!p_name.is_empty()) {
aname = p_name;
} else {
- aname = ProjectSettings::get_singleton()->get("application/config/name");
+ aname = GLOBAL_GET("application/config/name");
}
if (aname.is_empty()) {
@@ -431,7 +431,7 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const
String EditorExportPlatformAndroid::get_package_name(const String &p_package) const {
String pname = p_package;
- String basename = ProjectSettings::get_singleton()->get("application/config/name");
+ String basename = GLOBAL_GET("application/config/name");
basename = basename.to_lower();
String name;
@@ -1395,7 +1395,7 @@ void EditorExportPlatformAndroid::_fix_resources(const Ref<EditorExportPreset> &
Vector<String> string_table;
String package_name = p_preset->get("package/name");
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
for (uint32_t i = 0; i < string_count; i++) {
uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]);
@@ -1505,9 +1505,9 @@ void EditorExportPlatformAndroid::_process_launcher_icons(const String &p_file_n
}
String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, Ref<Image> &splash_bg_color_image) {
- bool scale_splash = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
- bool apply_filter = ProjectSettings::get_singleton()->get("application/boot_splash/use_filter");
- String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ bool scale_splash = GLOBAL_GET("application/boot_splash/fullsize");
+ bool apply_filter = GLOBAL_GET("application/boot_splash/use_filter");
+ String project_splash_path = GLOBAL_GET("application/boot_splash/image");
if (!project_splash_path.is_empty()) {
splash_image.instantiate();
@@ -1528,7 +1528,7 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
}
if (scale_splash) {
- Size2 screen_size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
int width, height;
if (screen_size.width > screen_size.height) {
// scale horizontally
@@ -1551,7 +1551,7 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
print_verbose("Creating splash background color image.");
splash_bg_color_image.instantiate();
- splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
+ splash_bg_color_image->initialize_data(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format());
splash_bg_color_image->fill(bg_color);
String processed_splash_config_xml = vformat(SPLASH_CONFIG_XML_CONTENT, bool_to_string(apply_filter));
@@ -1559,7 +1559,7 @@ String EditorExportPlatformAndroid::load_splash_refs(Ref<Image> &splash_image, R
}
void EditorExportPlatformAndroid::load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) {
- String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+ String project_icon_path = GLOBAL_GET("application/config/icon");
icon.instantiate();
foreground.instantiate();
@@ -1920,7 +1920,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
print_verbose(output);
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
- int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+ int dbg_port = EDITOR_GET("network/debug/remote_port");
args.clear();
args.push_back("-s");
args.push_back(devices[p_device].id);
@@ -1935,7 +1935,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
}
if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) {
- int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port");
+ int fs_port = EDITOR_GET("filesystem/file_server/port");
args.clear();
args.push_back("-s");
@@ -1965,7 +1965,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
args.push_back("shell");
args.push_back("am");
args.push_back("start");
- if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
+ if ((bool)EDITOR_GET("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17
args.push_back("--user");
args.push_back("0");
}
@@ -1995,7 +1995,7 @@ String EditorExportPlatformAndroid::get_adb_path() {
if (OS::get_singleton()->get_name() == "Windows") {
exe_ext = ".exe";
}
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
return sdk_path.path_join("platform-tools/adb" + exe_ext);
}
@@ -2005,7 +2005,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
exe_ext = ".bat";
}
String apksigner_command_name = "apksigner" + exe_ext;
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
String apksigner_path = "";
Error errn;
@@ -2099,7 +2099,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
}
if (!FileAccess::exists(dk)) {
- dk = EditorSettings::get_singleton()->get("export/android/debug_keystore");
+ dk = EDITOR_GET("export/android/debug_keystore");
if (!FileAccess::exists(dk)) {
valid = false;
err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n";
@@ -2120,7 +2120,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
err += TTR("Release keystore incorrectly configured in the export preset.") + "\n";
}
- String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
+ String sdk_path = EDITOR_GET("export/android/android_sdk_path");
if (sdk_path.is_empty()) {
err += TTR("A valid Android SDK path is required in Editor Settings.") + "\n";
valid = false;
@@ -2394,9 +2394,9 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre
user = p_preset->get("keystore/debug_user");
if (keystore.is_empty()) {
- keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ keystore = EDITOR_GET("export/android/debug_keystore");
+ password = EDITOR_GET("export/android/debug_keystore_pass");
+ user = EDITOR_GET("export/android/debug_keystore_user");
}
if (ep.step(vformat(TTR("Signing debug %s..."), export_label), 104)) {
@@ -2639,8 +2639,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
if (user_data.libs.size() > 0) {
Ref<FileAccess> fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE);
- JSON json;
- fa->store_string(json.stringify(user_data.libs, "\t"));
+ fa->store_string(JSON::stringify(user_data.libs, "\t"));
}
} else {
print_verbose("Saving apk expansion file..");
@@ -2729,9 +2728,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String debug_user = p_preset->get("keystore/debug_user");
if (debug_keystore.is_empty()) {
- debug_keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore");
- debug_password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass");
- debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
+ debug_keystore = EDITOR_GET("export/android/debug_keystore");
+ debug_password = EDITOR_GET("export/android/debug_keystore_pass");
+ debug_user = EDITOR_GET("export/android/debug_keystore_user");
}
if (debug_keystore.is_relative_path()) {
debug_keystore = OS::get_singleton()->get_resource_dir().path_join(debug_keystore).simplify_path();
@@ -2902,20 +2901,22 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
_load_image_data(splash_bg_color_image, data);
}
- for (int i = 0; i < icon_densities_count; ++i) {
- if (main_image.is_valid() && !main_image->is_empty()) {
- if (file == launcher_icons[i].export_path) {
- _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ if (file.ends_with(".png") && file.contains("mipmap")) {
+ for (int i = 0; i < icon_densities_count; ++i) {
+ if (main_image.is_valid() && !main_image->is_empty()) {
+ if (file == launcher_icons[i].export_path) {
+ _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data);
+ }
}
- }
- if (foreground.is_valid() && !foreground->is_empty()) {
- if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
- _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ if (foreground.is_valid() && !foreground->is_empty()) {
+ if (file == launcher_adaptive_icon_foregrounds[i].export_path) {
+ _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data);
+ }
}
- }
- if (background.is_valid() && !background->is_empty()) {
- if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
- _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ if (background.is_valid() && !background->is_empty()) {
+ if (file == launcher_adaptive_icon_backgrounds[i].export_path) {
+ _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data);
+ }
}
}
}
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 2f53942f76..8d016d3fac 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -158,7 +158,7 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset
return ERR_CANT_OPEN;
}
da->list_dir_begin();
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
while (true) {
String file = da->get_next();
if (file.is_empty()) {
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 81c7130c03..5a91e5ce32 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -29,8 +29,13 @@ allprojects {
ext {
supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"]
- supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"]
supportedFlavors = ["editor", "template"]
+ supportedFlavorsBuildTypes = [
+ // The editor can't be used with target=release as debugging tools are then not
+ // included, and it would crash on errors instead of reporting them.
+ "editor": ["dev", "debug"],
+ "template": ["dev", "debug", "release"]
+ ]
// Used by gradle to specify which architecture to build for by default when running
// `./gradlew build` (this command is usually used by Android Studio).
@@ -88,7 +93,7 @@ task copyDebugAARToAppModule(type: Copy) {
dependsOn ':lib:assembleTemplateDebug'
from('lib/build/outputs/aar')
into('app/libs/debug')
- include('godot-lib.debug.aar')
+ include('godot-lib.template_debug.aar')
}
/**
@@ -99,7 +104,7 @@ task copyDebugAARToBin(type: Copy) {
dependsOn ':lib:assembleTemplateDebug'
from('lib/build/outputs/aar')
into(binDir)
- include('godot-lib.debug.aar')
+ include('godot-lib.template_debug.aar')
}
/**
@@ -110,7 +115,7 @@ task copyDevAARToAppModule(type: Copy) {
dependsOn ':lib:assembleTemplateDev'
from('lib/build/outputs/aar')
into('app/libs/dev')
- include('godot-lib.dev.aar')
+ include('godot-lib.template_debug.dev.aar')
}
/**
@@ -121,7 +126,7 @@ task copyDevAARToBin(type: Copy) {
dependsOn ':lib:assembleTemplateDev'
from('lib/build/outputs/aar')
into(binDir)
- include('godot-lib.dev.aar')
+ include('godot-lib.template_debug.dev.aar')
}
/**
@@ -132,7 +137,7 @@ task copyReleaseAARToAppModule(type: Copy) {
dependsOn ':lib:assembleTemplateRelease'
from('lib/build/outputs/aar')
into('app/libs/release')
- include('godot-lib.release.aar')
+ include('godot-lib.template_release.aar')
}
/**
@@ -143,7 +148,7 @@ task copyReleaseAARToBin(type: Copy) {
dependsOn ':lib:assembleTemplateRelease'
from('lib/build/outputs/aar')
into(binDir)
- include('godot-lib.release.aar')
+ include('godot-lib.template_release.aar')
}
/**
@@ -168,13 +173,8 @@ def templateExcludedBuildTask() {
if (!isAndroidStudio()) {
logger.lifecycle("Excluding Android studio build tasks")
for (String flavor : supportedFlavors) {
- for (String buildType : supportedTargetsMap.keySet()) {
- if (buildType == "release" && flavor == "editor") {
- // The editor can't be used with target=release as debugging tools are then not
- // included, and it would crash on errors instead of reporting them.
- continue
- }
-
+ String[] supportedBuildTypes = supportedFlavorsBuildTypes[flavor]
+ for (String buildType : supportedBuildTypes) {
for (String abi : selectedAbis) {
excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi)
}
@@ -188,7 +188,7 @@ def templateBuildTasks() {
def tasks = []
// Only build the apks and aar files for which we have native shared libraries.
- for (String target : supportedTargetsMap.keySet()) {
+ for (String target : supportedFlavorsBuildTypes["template"]) {
File targetLibs = new File("lib/libs/" + target)
if (targetLibs != null
&& targetLibs.isDirectory()
@@ -240,12 +240,7 @@ task generateGodotEditor {
def tasks = []
- for (String target : supportedTargetsMap.keySet()) {
- if (target == "release") {
- // The editor can't be used with target=release as debugging tools are then not
- // included, and it would crash on errors instead of reporting them.
- continue
- }
+ for (String target : supportedFlavorsBuildTypes["editor"]) {
File targetLibs = new File("lib/libs/tools/" + target)
if (targetLibs != null
&& targetLibs.isDirectory()
@@ -281,6 +276,11 @@ task generateDevTemplate {
finalizedBy 'zipCustomBuild'
}
+task clean(type: Delete) {
+ dependsOn 'cleanGodotEditor'
+ dependsOn 'cleanGodotTemplates'
+}
+
/**
* Clean the generated editor artifacts.
*/
@@ -297,8 +297,6 @@ task cleanGodotEditor(type: Delete) {
// Delete the Godot editor apks in the Godot bin directory
delete("$binDir/android_editor.apk")
delete("$binDir/android_editor_dev.apk")
-
- finalizedBy getTasksByName("clean", true)
}
/**
@@ -322,9 +320,12 @@ task cleanGodotTemplates(type: Delete) {
delete("$binDir/android_dev.apk")
delete("$binDir/android_release.apk")
delete("$binDir/android_source.zip")
+ delete("$binDir/godot-lib.template_debug.aar")
+ delete("$binDir/godot-lib.template_debug.dev.aar")
+ delete("$binDir/godot-lib.template_release.aar")
+
+ // Cover deletion for the libs using the previous naming scheme
delete("$binDir/godot-lib.debug.aar")
delete("$binDir/godot-lib.dev.aar")
delete("$binDir/godot-lib.release.aar")
-
- finalizedBy getTasksByName("clean", true)
}
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 318ae1143f..c9e2a5d7d2 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -100,25 +100,34 @@ android {
throw new GradleException("Invalid product flavor: $flavorName")
}
- boolean toolsFlag = flavorName == "editor"
-
def buildType = variant.buildType.name
- if (buildType == null || buildType == "" || !supportedTargetsMap.containsKey(buildType)) {
+ if (buildType == null || buildType == "" || !supportedFlavorsBuildTypes[flavorName].contains(buildType)) {
throw new GradleException("Invalid build type: $buildType")
}
- def sconsTarget = supportedTargetsMap[buildType]
- if (sconsTarget == null || sconsTarget == "") {
- throw new GradleException("Invalid scons target: $sconsTarget")
+ boolean devBuild = buildType == "dev"
+
+ def sconsTarget = flavorName
+ if (sconsTarget == "template") {
+ switch (buildType) {
+ case "release":
+ sconsTarget += "_release"
+ break
+ case "debug":
+ case "dev":
+ default:
+ sconsTarget += "_debug"
+ break;
+ }
}
// Update the name of the generated library
- def outputSuffix = "${buildType}.aar"
- if (toolsFlag) {
- outputSuffix = "tools.$outputSuffix"
+ def outputSuffix = "${sconsTarget}"
+ if (devBuild) {
+ outputSuffix = "${outputSuffix}.dev"
}
variant.outputs.all { output ->
- output.outputFileName = "godot-lib.${outputSuffix}"
+ output.outputFileName = "godot-lib.${outputSuffix}.aar"
}
// Find scons' executable path
@@ -159,7 +168,7 @@ android {
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
tasks.create(name: taskName, type: Exec) {
executable sconsExecutableFile.absolutePath
- args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
+ args "--directory=${pathToRootDir}", "platform=android", "dev_mode=${devBuild}", "dev_build=${devBuild}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
}
// Schedule the tasks so the generated libs are present before the aar file is packaged.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
index 513021f1d1..3dfc37f6b0 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java
@@ -74,7 +74,6 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
private final Godot godot;
private final GodotInputHandler inputHandler;
private final GodotRenderer godotRenderer;
- private PointerIcon pointerIcon;
public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) {
super(context);
@@ -84,7 +83,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
this.inputHandler = new GodotInputHandler(this);
this.godotRenderer = new GodotRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
+ setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
}
init(xrMode, false);
}
@@ -175,13 +174,16 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
@Keep
public void setPointerIcon(int pointerType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
+ setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType));
}
}
@Override
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
- return pointerIcon;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return getPointerIcon();
+ }
+ return super.onResolvePointerIcon(me, pointerIndex);
}
private void init(XRMode xrMode, boolean translucent) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 26aad867b1..33896ecb95 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -110,7 +110,7 @@ public class GodotLib {
/**
* Forward touch events.
*/
- public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions);
+ public static native void dispatchTouchEvent(int event, int pointer, int pointerCount, float[] positions, boolean doubleTap);
/**
* Dispatch mouse events
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
index fa6c3280b9..0becf00d93 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java
@@ -48,7 +48,6 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
private final Godot godot;
private final GodotInputHandler mInputHandler;
private final VkRenderer mRenderer;
- private PointerIcon pointerIcon;
public GodotVulkanRenderView(Context context, Godot godot) {
super(context);
@@ -57,7 +56,7 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
mInputHandler = new GodotInputHandler(this);
mRenderer = new VkRenderer();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- pointerIcon = PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT);
+ setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
}
setFocusableInTouchMode(true);
startRenderer(mRenderer);
@@ -149,13 +148,16 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
@Keep
public void setPointerIcon(int pointerType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
+ setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType));
}
}
@Override
public PointerIcon onResolvePointerIcon(MotionEvent me, int pointerIndex) {
- return pointerIcon;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return getPointerIcon();
+ }
+ return super.onResolvePointerIcon(me, pointerIndex);
}
@Override
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 9715c31fc1..a7a57621de 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -55,18 +55,15 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
*/
var panningAndScalingEnabled = false
- private var doubleTapInProgress = false
+ private var nextDownIsDoubleTap = false
private var dragInProgress = false
private var scaleInProgress = false
private var contextClickInProgress = false
private var pointerCaptureInProgress = false
override fun onDown(event: MotionEvent): Boolean {
- // Don't send / register a down event while we're in the middle of a double-tap
- if (!doubleTapInProgress) {
- // Send the down event
- GodotInputHandler.handleMotionEvent(event)
- }
+ GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
+ nextDownIsDoubleTap = false
return true
}
@@ -209,24 +206,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
override fun onDoubleTapEvent(event: MotionEvent): Boolean {
if (event.actionMasked == MotionEvent.ACTION_UP) {
- doubleTapInProgress = false
+ nextDownIsDoubleTap = false
+ GodotInputHandler.handleMotionEvent(event)
}
return true
}
override fun onDoubleTap(event: MotionEvent): Boolean {
- doubleTapInProgress = true
- val x = event.x
- val y = event.y
- val buttonMask =
- if (GodotInputHandler.isMouseEvent(event)) {
- event.buttonState
- } else {
- MotionEvent.BUTTON_PRIMARY
- }
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_DOWN, buttonMask, x, y, true)
- GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, 0, x, y, false)
-
+ nextDownIsDoubleTap = true
return true
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 03cb8034fa..d2f3c5aed2 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -438,15 +438,19 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0);
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false);
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY) {
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) {
+ return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap);
+ }
+
+ static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) {
if (isMouseEvent(eventSource)) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, false, false);
+ return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
}
- return handleTouchEvent(eventAction, x, y);
+ return handleTouchEvent(eventAction, x, y, doubleTap);
}
static boolean handleMouseEvent(final MotionEvent event) {
@@ -468,10 +472,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
}
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, boolean doubleClick) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, doubleClick, false);
- }
-
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
@@ -508,14 +508,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final int action = event.getActionMasked();
final int actionPointerId = event.getPointerId(event.getActionIndex());
- return handleTouchEvent(action, actionPointerId, pointerCount, positions);
+ return handleTouchEvent(action, actionPointerId, pointerCount, positions, false);
}
- static boolean handleTouchEvent(int eventAction, float x, float y) {
- return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y });
+ static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) {
+ return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap);
}
- static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions) {
+ static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) {
switch (eventAction) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
@@ -523,7 +523,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions);
+ GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap);
return true;
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index c959b5f28c..01ad5ee415 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -122,7 +122,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
- if (mEdit == pTextView && isFullScreenEdit()) {
+ if (mEdit == pTextView && isFullScreenEdit() && pKeyEvent != null) {
final String characters = pKeyEvent.getCharacters();
for (int i = 0; i < characters.length(); i++) {
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 04b69d5b86..b5cb9d341d 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -265,7 +265,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JN
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray position, jboolean p_double_tap) {
if (step.get() <= 0) {
return;
}
@@ -280,7 +280,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JN
points.push_back(tp);
}
- input_handler->process_touch_event(ev, pointer, points);
+ input_handler->process_touch_event(ev, pointer, points, p_double_tap);
}
// Called on the UI thread
@@ -409,7 +409,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env,
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path) {
String js = jstring_to_string(path, env);
- return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
+ return env->NewStringUTF(GLOBAL_GET(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 09fed15690..f3f2646bfb 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -46,7 +46,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jboolean p_double_tap);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
diff --git a/platform/android/java_godot_view_wrapper.cpp b/platform/android/java_godot_view_wrapper.cpp
index 0153ba96fc..762840a4b1 100644
--- a/platform/android/java_godot_view_wrapper.cpp
+++ b/platform/android/java_godot_view_wrapper.cpp
@@ -40,13 +40,24 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
_cls = (jclass)env->NewGlobalRef(env->GetObjectClass(godot_view));
- if (android_get_device_api_level() >= __ANDROID_API_O__) {
+ int android_device_api_level = android_get_device_api_level();
+ if (android_device_api_level >= __ANDROID_API_N__) {
+ _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
+ }
+ if (android_device_api_level >= __ANDROID_API_O__) {
_request_pointer_capture = env->GetMethodID(_cls, "requestPointerCapture", "()V");
_release_pointer_capture = env->GetMethodID(_cls, "releasePointerCapture", "()V");
- _set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
}
}
+bool GodotJavaViewWrapper::can_update_pointer_icon() const {
+ return _set_pointer_icon != nullptr;
+}
+
+bool GodotJavaViewWrapper::can_capture_pointer() const {
+ return _request_pointer_capture != nullptr && _release_pointer_capture != nullptr;
+}
+
void GodotJavaViewWrapper::request_pointer_capture() {
if (_request_pointer_capture != nullptr) {
JNIEnv *env = get_jni_env();
diff --git a/platform/android/java_godot_view_wrapper.h b/platform/android/java_godot_view_wrapper.h
index c52f459d64..b398c73cac 100644
--- a/platform/android/java_godot_view_wrapper.h
+++ b/platform/android/java_godot_view_wrapper.h
@@ -50,6 +50,9 @@ private:
public:
GodotJavaViewWrapper(jobject godot_view);
+ bool can_update_pointer_icon() const;
+ bool can_capture_pointer() const;
+
void request_pointer_capture();
void release_pointer_capture();
void set_pointer_icon(int pointer_type);
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 07b0d75921..416b98c895 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -78,13 +78,23 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
_on_godot_setup_completed = p_env->GetMethodID(godot_class, "onGodotSetupCompleted", "()V");
_on_godot_main_loop_started = p_env->GetMethodID(godot_class, "onGodotMainLoopStarted", "()V");
_create_new_godot_instance = p_env->GetMethodID(godot_class, "createNewGodotInstance", "([Ljava/lang/String;)V");
+ _get_render_view = p_env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
// get some Activity method pointers...
_get_class_loader = p_env->GetMethodID(activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
}
GodotJavaWrapper::~GodotJavaWrapper() {
- // nothing to do here for now
+ if (godot_view) {
+ delete godot_view;
+ }
+
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL(env);
+ env->DeleteGlobalRef(godot_instance);
+ env->DeleteGlobalRef(godot_class);
+ env->DeleteGlobalRef(activity);
+ env->DeleteGlobalRef(activity_class);
}
jobject GodotJavaWrapper::get_activity() {
@@ -115,14 +125,18 @@ jobject GodotJavaWrapper::get_class_loader() {
}
GodotJavaViewWrapper *GodotJavaWrapper::get_godot_view() {
- if (_godot_view != nullptr) {
- return _godot_view;
+ if (godot_view != nullptr) {
+ return godot_view;
}
- JNIEnv *env = get_jni_env();
- ERR_FAIL_NULL_V(env, nullptr);
- jmethodID godot_view_getter = env->GetMethodID(godot_class, "getRenderView", "()Lorg/godotengine/godot/GodotRenderView;");
- _godot_view = new GodotJavaViewWrapper(env->CallObjectMethod(godot_instance, godot_view_getter));
- return _godot_view;
+ if (_get_render_view) {
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_NULL_V(env, nullptr);
+ jobject godot_render_view = env->CallObjectMethod(godot_instance, _get_render_view);
+ if (!env->IsSameObject(godot_render_view, nullptr)) {
+ godot_view = new GodotJavaViewWrapper(godot_render_view);
+ }
+ }
+ return godot_view;
}
bool GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 0e96a4e1f3..fb9c4c77fc 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -46,7 +46,7 @@ private:
jclass godot_class;
jclass activity_class;
- GodotJavaViewWrapper *_godot_view = nullptr;
+ GodotJavaViewWrapper *godot_view = nullptr;
jmethodID _on_video_init = nullptr;
jmethodID _restart = nullptr;
@@ -69,6 +69,7 @@ private:
jmethodID _on_godot_main_loop_started = nullptr;
jmethodID _get_class_loader = nullptr;
jmethodID _create_new_godot_instance = nullptr;
+ jmethodID _get_render_view = nullptr;
public:
GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_godot_instance);
diff --git a/platform/android/jni_utils.cpp b/platform/android/jni_utils.cpp
index 193ef61264..2b0ee50570 100644
--- a/platform/android/jni_utils.cpp
+++ b/platform/android/jni_utils.cpp
@@ -167,9 +167,8 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_a
v.obj = arr;
} break;
-#ifndef _MSC_VER
-#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
-#endif
+
+ // TODO: This is missing 64 bits arrays, I have no idea how to do it in JNI.
default: {
v.val.i = 0;
@@ -266,33 +265,33 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
if (name == "[D") {
jdoubleArray arr = (jdoubleArray)obj;
int fCount = env->GetArrayLength(arr);
- PackedFloat32Array sarr;
- sarr.resize(fCount);
+ PackedFloat64Array packed_array;
+ packed_array.resize(fCount);
- real_t *w = sarr.ptrw();
+ double *w = packed_array.ptrw();
for (int i = 0; i < fCount; i++) {
double n;
env->GetDoubleArrayRegion(arr, i, 1, &n);
w[i] = n;
}
- return sarr;
+ return packed_array;
}
if (name == "[F") {
jfloatArray arr = (jfloatArray)obj;
int fCount = env->GetArrayLength(arr);
- PackedFloat32Array sarr;
- sarr.resize(fCount);
+ PackedFloat32Array packed_array;
+ packed_array.resize(fCount);
- real_t *w = sarr.ptrw();
+ float *w = packed_array.ptrw();
for (int i = 0; i < fCount; i++) {
float n;
env->GetFloatArrayRegion(arr, i, 1, &n);
w[i] = n;
}
- return sarr;
+ return packed_array;
}
if (name == "[Ljava.lang.Object;") {
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
index 7a39e2003d..498977ad49 100644
--- a/platform/android/plugin/godot_plugin_jni.cpp
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -137,7 +137,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegis
// Retrieve the current list of gdnative libraries.
Array singletons = Array();
if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
- singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ singletons = GLOBAL_GET("gdnative/singletons");
}
// Insert the libraries provided by the plugin
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index 61b471866f..9f87303341 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -63,7 +63,7 @@ static void term_thread() {
void init_thread_jandroid(JavaVM *p_jvm, JNIEnv *p_env) {
java_vm = p_jvm;
env = p_env;
- Thread::_set_platform_funcs(nullptr, nullptr, &init_thread, &term_thread);
+ Thread::_set_platform_functions({ .init = init_thread, .term = &term_thread });
}
void setup_android_thread() {
diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp
index 5945421e17..948292c3af 100644
--- a/platform/android/vulkan/vulkan_context_android.cpp
+++ b/platform/android/vulkan/vulkan_context_android.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_android.h"
#ifdef USE_VOLK
@@ -40,7 +42,7 @@ const char *VulkanContextAndroid::_get_platform_surface_extension() const {
return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
}
-int VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height) {
+Error VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height) {
VkAndroidSurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
@@ -50,7 +52,7 @@ int VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::
VkSurfaceKHR surface;
VkResult err = vkCreateAndroidSurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
if (err != VK_SUCCESS) {
- ERR_FAIL_V_MSG(-1, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkCreateAndroidSurfaceKHR failed with error " + itos(err));
}
return _window_create(DisplayServer::MAIN_WINDOW_ID, p_vsync_mode, surface, p_width, p_height);
@@ -63,3 +65,5 @@ bool VulkanContextAndroid::_use_validation_layers() {
// On Android, we use validation layers automatically if they were explicitly linked with the app.
return count > 0;
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h
index 43b5d62598..fe9a033e1c 100644
--- a/platform/android/vulkan/vulkan_context_android.h
+++ b/platform/android/vulkan/vulkan_context_android.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_ANDROID_H
#define VULKAN_CONTEXT_ANDROID_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
struct ANativeWindow;
@@ -39,7 +41,7 @@ class VulkanContextAndroid : public VulkanContext {
virtual const char *_get_platform_surface_extension() const override;
public:
- int window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height);
+ Error window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height);
VulkanContextAndroid() = default;
~VulkanContextAndroid() override = default;
@@ -48,4 +50,6 @@ protected:
bool _use_validation_layers() override;
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_ANDROID_H
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index f3624f24ab..447f919139 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -40,7 +40,6 @@
#include "vulkan_context_ios.h"
-#import <QuartzCore/CAMetalLayer.h>
#ifdef USE_VOLK
#include <volk.h>
#else
@@ -48,6 +47,9 @@
#endif
#endif
+#import <Foundation/Foundation.h>
+#import <QuartzCore/CAMetalLayer.h>
+
class DisplayServerIOS : public DisplayServer {
GDCLASS(DisplayServerIOS, DisplayServer)
@@ -73,7 +75,7 @@ class DisplayServerIOS : public DisplayServer {
void perform_event(const Ref<InputEvent> &p_event);
- DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerIOS(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerIOS();
public:
@@ -82,7 +84,7 @@ public:
static DisplayServerIOS *get_singleton();
static void register_ios_driver();
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
// MARK: - Events
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index d3a0f38463..8808d8e842 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -41,7 +41,6 @@
#include "tts_ios.h"
#import "view_controller.h"
-#import <Foundation/Foundation.h>
#import <sys/utsname.h>
static const float kDisplayServerIOSAcceleration = 1.f;
@@ -50,7 +49,7 @@ DisplayServerIOS *DisplayServerIOS::get_singleton() {
return (DisplayServerIOS *)DisplayServer::get_singleton();
}
-DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
rendering_driver = p_rendering_driver;
// Init TTS
@@ -152,8 +151,8 @@ DisplayServerIOS::~DisplayServerIOS() {
#endif
}
-DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerIOS::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerIOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
}
Vector<String> DisplayServerIOS::get_rendering_drivers_func() {
@@ -235,6 +234,7 @@ void DisplayServerIOS::touch_press(int p_idx, int p_x, int p_y, bool p_pressed,
ev->set_index(p_idx);
ev->set_pressed(p_pressed);
ev->set_position(Vector2(p_x, p_y));
+ ev->set_double_tap(p_double_click);
perform_event(ev);
}
}
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 74a57dc614..8e4d91ac50 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -358,8 +358,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
switch (image_scale_mode) {
case 0: {
- String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ String logo_path = GLOBAL_GET("application/boot_splash/image");
+ bool is_on = GLOBAL_GET("application/boot_splash/fullsize");
// If custom logo is not specified, Godot does not scale default one, so we should do the same.
value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center";
} break;
@@ -371,7 +371,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
} else if (lines[i].find("$launch_screen_background_color") != -1) {
bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
- Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
+ Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : GLOBAL_GET("application/boot_splash/bg_color");
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
Dictionary value_dictionary;
@@ -384,7 +384,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
} else if (lines[i].find("$pbx_locale_file_reference") != -1) {
String locale_files;
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
HashSet<String> languages;
for (const String &E : translations) {
@@ -403,7 +403,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$pbx_locale_file_reference", locale_files);
} else if (lines[i].find("$pbx_locale_build_reference") != -1) {
String locale_files;
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
HashSet<String> languages;
for (const String &E : translations) {
@@ -574,7 +574,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
String icon_path = p_preset->get(info.preset_key);
if (icon_path.length() == 0) {
// Resize main app icon
- icon_path = ProjectSettings::get_singleton()->get("application/config/icon");
+ icon_path = GLOBAL_GET("application/config/icon");
Ref<Image> img = memnew(Image);
Error err = ImageLoader::load_image(icon_path, img);
if (err != OK) {
@@ -677,7 +677,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
} else {
Ref<Image> splash;
- const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ const String splash_path = GLOBAL_GET("application/boot_splash/image");
if (!splash_path.is_empty()) {
splash.instantiate();
@@ -718,9 +718,9 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
LoadingScreenInfo info = loading_screen_infos[i];
String loading_screen_file = p_preset->get(info.preset_key);
- Color boot_bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color");
- String boot_logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image");
- bool boot_logo_scale = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize");
+ Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
+ String boot_logo_path = GLOBAL_GET("application/boot_splash/image");
+ bool boot_logo_scale = GLOBAL_GET("application/boot_splash/fullsize");
if (loading_screen_file.size() > 0) {
// Load custom loading screens, and resize if required.
@@ -740,8 +740,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
img->resize(info.width, info.width / aspect_ratio);
}
}
- Ref<Image> new_img = memnew(Image);
- new_img->create(info.width, info.height, false, Image::FORMAT_RGBA8);
+ Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
new_img->fill(boot_bg_color);
_blend_and_rotate(new_img, img, false);
err = new_img->save_png(p_dest_dir + info.export_name);
@@ -755,8 +754,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp
}
} else {
// Generate loading screen from the splash screen
- Ref<Image> img = memnew(Image);
- img->create(info.width, info.height, false, Image::FORMAT_RGBA8);
+ Ref<Image> img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
img->fill(boot_bg_color);
Ref<Image> img_bs;
@@ -1496,8 +1494,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
print_line("Static framework: " + library_to_use);
String pkg_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ pkg_name = String(GLOBAL_GET("application/config/name"));
} else {
pkg_name = "Unnamed";
}
@@ -1646,12 +1644,12 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return ERR_FILE_NOT_FOUND;
}
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
Dictionary photolibrary_usage_descriptions = p_preset->get("privacy/photolibrary_usage_description_localized");
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
{
String fname = dest_dir + binary_name + "/en.lproj";
@@ -1659,7 +1657,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */");
f->store_line("");
- f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";");
+ f->store_line("CFBundleDisplayName = \"" + GLOBAL_GET("application/config/name").operator String() + "\";");
f->store_line("NSCameraUsageDescription = \"" + p_preset->get("privacy/camera_usage_description").operator String() + "\";");
f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";");
f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";");
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index ff90c05b1d..4537dc2985 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -30,6 +30,7 @@
#import "godot_view.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "core/string/ustring.h"
#import "display_layer.h"
@@ -205,16 +206,16 @@ static const float earth_gravity = 9.80665;
if (self.useCADisplayLink) {
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
- // Approximate frame rate
- // assumes device refreshes at 60 fps
- int displayFPS = (NSInteger)(1.0 / self.renderingInterval);
-
- self.displayLink.preferredFramesPerSecond = displayFPS;
+ if (GLOBAL_GET("display/window/ios/allow_high_refresh_rate")) {
+ self.displayLink.preferredFramesPerSecond = 120;
+ } else {
+ self.displayLink.preferredFramesPerSecond = 60;
+ }
// Setup DisplayLink in main thread
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
} else {
- self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:self.renderingInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+ self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0 / 60) target:self selector:@selector(drawView) userInfo:nil repeats:YES];
}
}
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index a674498620..b6b94d2f5e 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -396,7 +396,14 @@ void OS_IOS::vibrate_handheld(int p_duration_ms) {
}
bool OS_IOS::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "mobile";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "mobile") {
+ return true;
+ }
+
+ return false;
}
void OS_IOS::on_focus_out() {
diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm
index 43669d3f94..53c5d3d0b4 100644
--- a/platform/ios/view_controller.mm
+++ b/platform/ios/view_controller.mm
@@ -164,7 +164,11 @@
// MARK: Orientation
- (UIRectEdge)preferredScreenEdgesDeferringSystemGestures {
- return UIRectEdgeAll;
+ if (GLOBAL_GET("display/window/ios/suppress_ui_gesture")) {
+ return UIRectEdgeAll;
+ } else {
+ return UIRectEdgeNone;
+ }
}
- (BOOL)shouldAutorotate {
@@ -206,7 +210,11 @@
}
- (BOOL)prefersStatusBarHidden {
- return YES;
+ if (GLOBAL_GET("display/window/ios/hide_status_bar")) {
+ return YES;
+ } else {
+ return NO;
+ }
}
- (BOOL)prefersHomeIndicatorAutoHidden {
diff --git a/platform/ios/vulkan_context_ios.h b/platform/ios/vulkan_context_ios.h
index e9c09e087a..3849c8ba8a 100644
--- a/platform/ios/vulkan_context_ios.h
+++ b/platform/ios/vulkan_context_ios.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_IOS_H
#define VULKAN_CONTEXT_IOS_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#import <UIKit/UIKit.h>
@@ -45,4 +47,6 @@ public:
~VulkanContextIOS();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_IOS_H
diff --git a/platform/ios/vulkan_context_ios.mm b/platform/ios/vulkan_context_ios.mm
index 09cd369aa5..81b021e758 100644
--- a/platform/ios/vulkan_context_ios.mm
+++ b/platform/ios/vulkan_context_ios.mm
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_ios.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +59,5 @@ Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, Displ
VulkanContextIOS::VulkanContextIOS() {}
VulkanContextIOS::~VulkanContextIOS() {}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index 33da094860..8c8c8588b8 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -89,7 +89,7 @@ static void handle_crash(int sig) {
// Try to demangle the function name to provide a more readable one
if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
if (info.dli_sname[0] == '_') {
- int status;
+ int status = 0;
char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (status == 0 && demangled) {
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index dfde0d249c..ac69f3806b 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -363,7 +363,10 @@ def configure(env: "Environment"):
if platform.system() == "Linux":
env.Append(LIBS=["dl"])
- if platform.system().find("BSD") >= 0:
+ if not env["execinfo"] and platform.libc_ver()[0] != "glibc":
+ # The default crash handler depends on glibc, so if the host uses
+ # a different libc (BSD libc, musl), fall back to libexecinfo.
+ print("Note: Using `execinfo=yes` for the crash handler as required on platforms where glibc is missing.")
env["execinfo"] = True
if env["execinfo"]:
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 81fc941608..88c6500e10 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -49,10 +49,14 @@
#include "drivers/gles3/rasterizer_gles3.h"
#endif
+#include <dlfcn.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
@@ -66,17 +70,6 @@
#define _NET_WM_STATE_REMOVE 0L // remove/unset property
#define _NET_WM_STATE_ADD 1L // add/set property
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-//stupid linux.h
-#ifdef KEY_TAB
-#undef KEY_TAB
-#endif
-
#undef CursorShape
#include <X11/XKBlib.h>
@@ -133,7 +126,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const {
case FEATURE_WINDOW_TRANSPARENCY:
//case FEATURE_HIDPI:
case FEATURE_ICON:
- case FEATURE_NATIVE_ICON:
+ //case FEATURE_NATIVE_ICON:
case FEATURE_SWAP_BUFFERS:
#ifdef DBUS_ENABLED
case FEATURE_KEEP_SCREEN_ON:
@@ -1209,16 +1202,6 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
return SCREEN_REFRESH_RATE_FALLBACK;
}
-bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
- _THREAD_SAFE_METHOD_
-
-#ifndef _MSC_VER
-#warning Need to get from proper window
-#endif
-
- return DisplayServer::screen_is_touchscreen(p_screen);
-}
-
#ifdef DBUS_ENABLED
void DisplayServerX11::screen_set_keep_on(bool p_enable) {
if (screen_is_kept_on() == p_enable) {
@@ -1746,6 +1729,18 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) {
usleep(10000);
}
+
+ // Keep rendering context window size in sync
+#if defined(VULKAN_ENABLED)
+ if (context_vulkan) {
+ context_vulkan->window_resize(p_window, xwa.width, xwa.height);
+ }
+#endif
+#if defined(GLES3_ENABLED)
+ if (gl_manager) {
+ gl_manager->window_resize(p_window, xwa.width, xwa.height);
+ }
+#endif
}
Size2i DisplayServerX11::window_get_size(WindowID p_window) const {
@@ -3149,7 +3144,7 @@ void DisplayServerX11::_window_changed(XEvent *event) {
{
//the position in xconfigure is not useful here, obtain it manually
- int x, y;
+ int x = 0, y = 0;
Window child;
XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child);
new_rect.position.x = x;
@@ -3312,7 +3307,7 @@ void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) {
XFlush(x11_display);
// Non-blocking wait for next event and remove it from the queue.
- XEvent ev;
+ XEvent ev = {};
while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
// Check if the input manager wants to process the event.
if (XFilterEvent(&ev, None)) {
@@ -4437,13 +4432,24 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
@@ -4687,7 +4693,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
return id;
}
-DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
@@ -4914,6 +4920,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
+
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
if (main_window == INVALID_WINDOW_ID) {
r_error = ERR_CANT_CREATE;
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index a5fa7613bc..9ef8f71c05 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -349,7 +349,6 @@ public:
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
#if defined(DBUS_ENABLED)
virtual void screen_set_keep_on(bool p_enable) override;
@@ -445,12 +444,12 @@ public:
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_x11_driver();
- DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerX11();
};
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
index 4d45d3ba12..8277bb1505 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -56,8 +56,8 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
}
String app_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ app_name = String(GLOBAL_GET("application/config/name"));
} else {
app_name = "Unnamed";
}
diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp
index fa3f7fbfea..88ec37c456 100644
--- a/platform/linuxbsd/freedesktop_screensaver.cpp
+++ b/platform/linuxbsd/freedesktop_screensaver.cpp
@@ -55,7 +55,7 @@ void FreeDesktopScreenSaver::inhibit() {
return;
}
- String app_name_string = ProjectSettings::get_singleton()->get("application/config/name");
+ String app_name_string = GLOBAL_GET("application/config/name");
CharString app_name_utf8 = app_name_string.utf8();
const char *app_name = app_name_string.is_empty() ? "Godot Engine" : app_name_utf8.get_data();
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
index 91a260182e..fa5e20891c 100644
--- a/platform/linuxbsd/godot_linuxbsd.cpp
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -69,6 +69,7 @@ int main(int argc, char *argv[]) {
}
if (Main::start()) {
+ os.set_exit_code(EXIT_SUCCESS);
os.run(); // it is actually the OS that decides how to run
}
Main::cleanup();
diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp
index 047ee74671..f774c99d99 100644
--- a/platform/linuxbsd/key_mapping_x11.cpp
+++ b/platform/linuxbsd/key_mapping_x11.cpp
@@ -108,17 +108,21 @@ static _XTranslatePair _xkeysym_to_keycode[] = {
{ XK_KP_7, Key::KP_7 },
{ XK_KP_8, Key::KP_8 },
{ XK_KP_9, Key::KP_9 },
- // same but with numlock
- { XK_KP_Insert, Key::KP_0 },
- { XK_KP_End, Key::KP_1 },
- { XK_KP_Down, Key::KP_2 },
- { XK_KP_Page_Down, Key::KP_3 },
- { XK_KP_Left, Key::KP_4 },
- { XK_KP_Begin, Key::KP_5 },
- { XK_KP_Right, Key::KP_6 },
- { XK_KP_Home, Key::KP_7 },
- { XK_KP_Up, Key::KP_8 },
- { XK_KP_Page_Up, Key::KP_9 },
+ // same keys but with numlock off
+ { XK_KP_Insert, Key::INSERT },
+ { XK_KP_End, Key::END },
+ { XK_KP_Down, Key::DOWN },
+ { XK_KP_Page_Down, Key::PAGEDOWN },
+ { XK_KP_Left, Key::LEFT },
+ // X11 documents this (numpad 5) as "begin of line" but no toolkit
+ // seems to interpret it this way.
+ // On Windows this is emitting Key::Clear so for consistency it
+ // will be mapped to Key::Clear
+ { XK_KP_Begin, Key::CLEAR },
+ { XK_KP_Right, Key::RIGHT },
+ { XK_KP_Home, Key::HOME },
+ { XK_KP_Up, Key::UP },
+ { XK_KP_Page_Up, Key::PAGEUP },
{ XK_F1, Key::F1 },
{ XK_F2, Key::F2 },
{ XK_F3, Key::F3 },
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index f4e94f1a91..db9b3ed77f 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -34,6 +34,11 @@
#include "main/main.h"
#include "servers/display_server.h"
+#include "modules/modules_enabled.gen.h" // For regex.
+#ifdef MODULE_REGEX_ENABLED
+#include "modules/regex/regex.h"
+#endif
+
#ifdef X11_ENABLED
#include "display_server_x11.h"
#endif
@@ -42,12 +47,10 @@
#include <mntent.h>
#endif
+#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-
-#include <dlfcn.h>
-#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/utsname.h>
@@ -242,6 +245,204 @@ String OS_LinuxBSD::get_version() const {
return uts.version;
}
+Vector<String> OS_LinuxBSD::get_video_adapter_driver_info() const {
+ if (RenderingServer::get_singleton()->get_rendering_device() == nullptr) {
+ return Vector<String>();
+ }
+
+ const String rendering_device_name = RenderingServer::get_singleton()->get_rendering_device()->get_device_name(); // e.g. `NVIDIA GeForce GTX 970`
+ const String rendering_device_vendor = RenderingServer::get_singleton()->get_rendering_device()->get_device_vendor_name(); // e.g. `NVIDIA`
+ const String card_name = rendering_device_name.trim_prefix(rendering_device_vendor).strip_edges(); // -> `GeForce GTX 970`
+
+ String vendor_device_id_mappings;
+ List<String> lspci_args;
+ lspci_args.push_back("-n");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", lspci_args, &vendor_device_id_mappings);
+ if (err != OK || vendor_device_id_mappings.is_empty()) {
+ return Vector<String>();
+ }
+
+ // Usually found under "VGA", but for example NVIDIA mobile/laptop adapters are often listed under "3D" and some AMD adapters are under "Display".
+ const String dc_vga = "0300"; // VGA compatible controller
+ const String dc_display = "0302"; // Display controller
+ const String dc_3d = "0380"; // 3D controller
+
+ // splitting results by device class allows prioritizing, if multiple devices are found.
+ Vector<String> class_vga_device_candidates;
+ Vector<String> class_display_device_candidates;
+ Vector<String> class_3d_device_candidates;
+
+#ifdef MODULE_REGEX_ENABLED
+ RegEx regex_id_format = RegEx();
+ regex_id_format.compile("^[a-f0-9]{4}:[a-f0-9]{4}$"); // e.g. `10de:13c2`; IDs are always in hexadecimal
+#endif
+
+ Vector<String> value_lines = vendor_device_id_mappings.split("\n", false); // example: `02:00.0 0300: 10de:13c2 (rev a1)`
+ for (const String &line : value_lines) {
+ Vector<String> columns = line.split(" ", false);
+ if (columns.size() < 3) {
+ continue;
+ }
+ String device_class = columns[1].trim_suffix(":");
+ String vendor_device_id_mapping = columns[2];
+
+#ifdef MODULE_REGEX_ENABLED
+ if (regex_id_format.search(vendor_device_id_mapping).is_null()) {
+ continue;
+ }
+#endif
+
+ if (device_class == dc_vga) {
+ class_vga_device_candidates.push_back(vendor_device_id_mapping);
+ } else if (device_class == dc_display) {
+ class_display_device_candidates.push_back(vendor_device_id_mapping);
+ } else if (device_class == dc_3d) {
+ class_3d_device_candidates.push_back(vendor_device_id_mapping);
+ }
+ }
+
+ // Check results against currently used device (`card_name`), in case the user has multiple graphics cards.
+ const String device_lit = "Device"; // line of interest
+ class_vga_device_candidates = OS_LinuxBSD::lspci_device_filter(class_vga_device_candidates, dc_vga, device_lit, card_name);
+ class_display_device_candidates = OS_LinuxBSD::lspci_device_filter(class_display_device_candidates, dc_display, device_lit, card_name);
+ class_3d_device_candidates = OS_LinuxBSD::lspci_device_filter(class_3d_device_candidates, dc_3d, device_lit, card_name);
+
+ // Get driver names and filter out invalid ones, because some adapters are dummys used only for passthrough.
+ // And they have no indicator besides certain driver names.
+ const String kernel_lit = "Kernel driver in use"; // line of interest
+ const String dummys = "vfio"; // for e.g. pci passthrough dummy kernel driver `vfio-pci`
+ Vector<String> class_vga_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_vga_device_candidates, kernel_lit, dummys);
+ Vector<String> class_display_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_display_device_candidates, kernel_lit, dummys);
+ Vector<String> class_3d_device_drivers = OS_LinuxBSD::lspci_get_device_value(class_3d_device_candidates, kernel_lit, dummys);
+
+ static String driver_name;
+ static String driver_version;
+
+ // Use first valid value:
+ for (const String &driver : class_3d_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ if (driver_name.is_empty()) {
+ for (const String &driver : class_display_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ }
+ if (driver_name.is_empty()) {
+ for (const String &driver : class_vga_device_drivers) {
+ driver_name = driver;
+ break;
+ }
+ }
+
+ Vector<String> info;
+ info.push_back(driver_name);
+
+ String modinfo;
+ List<String> modinfo_args;
+ modinfo_args.push_back(driver_name);
+ err = const_cast<OS_LinuxBSD *>(this)->execute("modinfo", modinfo_args, &modinfo);
+ if (err != OK || modinfo.is_empty()) {
+ info.push_back(""); // So that this method always either returns an empty array, or an array of length 2.
+ return info;
+ }
+ Vector<String> lines = modinfo.split("\n", false);
+ for (const String &line : lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == "version") {
+ driver_version = columns[1].strip_edges(); // example value: `510.85.02` on Linux/BSD
+ break;
+ }
+ }
+
+ info.push_back(driver_version);
+
+ return info;
+}
+
+Vector<String> OS_LinuxBSD::lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const {
+ // NOTE: whitelist can be changed to `Vector<String>`, if the need arises.
+ const String sep = ":";
+ Vector<String> devices;
+ for (const String &mapping : vendor_device_id_mapping) {
+ String device;
+ List<String> d_args;
+ d_args.push_back("-d");
+ d_args.push_back(mapping + sep + class_suffix);
+ d_args.push_back("-vmm");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", d_args, &device); // e.g. `lspci -d 10de:13c2:0300 -vmm`
+ if (err != OK) {
+ return Vector<String>();
+ } else if (device.is_empty()) {
+ continue;
+ }
+
+ Vector<String> device_lines = device.split("\n", false);
+ for (const String &line : device_lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == check_column) {
+ // for `column[0] == "Device"` this may contain `GM204 [GeForce GTX 970]`
+ bool is_valid = true;
+ if (!whitelist.is_empty()) {
+ is_valid = columns[1].strip_edges().contains(whitelist);
+ }
+ if (is_valid) {
+ devices.push_back(mapping);
+ }
+ break;
+ }
+ }
+ }
+ return devices;
+}
+
+Vector<String> OS_LinuxBSD::lspci_get_device_value(Vector<String> vendor_device_id_mapping, String check_column, String blacklist) const {
+ // NOTE: blacklist can be changed to `Vector<String>`, if the need arises.
+ const String sep = ":";
+ Vector<String> values;
+ for (const String &mapping : vendor_device_id_mapping) {
+ String device;
+ List<String> d_args;
+ d_args.push_back("-d");
+ d_args.push_back(mapping);
+ d_args.push_back("-k");
+ Error err = const_cast<OS_LinuxBSD *>(this)->execute("lspci", d_args, &device); // e.g. `lspci -d 10de:13c2 -k`
+ if (err != OK) {
+ return Vector<String>();
+ } else if (device.is_empty()) {
+ continue;
+ }
+
+ Vector<String> device_lines = device.split("\n", false);
+ for (const String &line : device_lines) {
+ Vector<String> columns = line.split(":", false, 1);
+ if (columns.size() < 2) {
+ continue;
+ }
+ if (columns[0].strip_edges() == check_column) {
+ // for `column[0] == "Kernel driver in use"` this may contain `nvidia`
+ bool is_valid = true;
+ const String value = columns[1].strip_edges();
+ if (!blacklist.is_empty()) {
+ is_valid = !value.contains(blacklist);
+ }
+ if (is_valid) {
+ values.push_back(value);
+ }
+ break;
+ }
+ }
+ }
+ return values;
+}
+
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
int err_code;
@@ -280,7 +481,16 @@ Error OS_LinuxBSD::shell_open(String p_uri) {
}
bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+#ifdef FONTCONFIG_ENABLED
+ if (p_feature == "system_fonts") {
+ return font_config_initialized;
+ }
+#endif
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
uint64_t OS_LinuxBSD::get_embedded_pck_offset() const {
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 722d83ba19..aea04c1363 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -69,6 +69,9 @@ class OS_LinuxBSD : public OS_Unix {
String get_systemd_os_release_info_value(const String &key) const;
+ Vector<String> lspci_device_filter(Vector<String> vendor_device_id_mapping, String class_suffix, String check_column, String whitelist) const;
+ Vector<String> lspci_get_device_value(Vector<String> vendor_device_id_mapping, String check_column, String blacklist) const;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
@@ -82,6 +85,8 @@ public:
virtual String get_distribution_name() const override;
virtual String get_version() const override;
+ virtual Vector<String> get_video_adapter_driver_info() const override;
+
virtual MainLoop *get_main_loop() const override;
virtual uint64_t get_embedded_pck_offset() const override;
diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp
index b4f585726f..92aaf33b05 100644
--- a/platform/linuxbsd/vulkan_context_x11.cpp
+++ b/platform/linuxbsd/vulkan_context_x11.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
+
#include "vulkan_context_x11.h"
#ifdef USE_VOLK
@@ -59,3 +61,5 @@ VulkanContextX11::VulkanContextX11() {
VulkanContextX11::~VulkanContextX11() {
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h
index 0c4a6cd278..0adb50ef44 100644
--- a/platform/linuxbsd/vulkan_context_x11.h
+++ b/platform/linuxbsd/vulkan_context_x11.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_X11_H
#define VULKAN_CONTEXT_X11_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#include <X11/Xlib.h>
@@ -44,4 +46,6 @@ public:
~VulkanContextX11();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_X11_H
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 511286d52b..e73c5322ea 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -223,6 +223,8 @@ def configure(env: "Environment"):
"AVFoundation",
"-framework",
"CoreMedia",
+ "-framework",
+ "QuartzCore",
]
)
env.Append(LIBS=["pthread", "z"])
@@ -236,7 +238,7 @@ def configure(env: "Environment"):
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
- env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "QuartzCore", "-framework", "IOSurface"])
+ env.Append(LINKFLAGS=["-framework", "Metal", "-framework", "IOSurface"])
if not env["use_volk"]:
env.Append(LINKFLAGS=["-lMoltenVK"])
mvk_found = False
diff --git a/platform/macos/dir_access_macos.h b/platform/macos/dir_access_macos.h
index 920e69ef3e..c76b2835e8 100644
--- a/platform/macos/dir_access_macos.h
+++ b/platform/macos/dir_access_macos.h
@@ -31,16 +31,16 @@
#ifndef DIR_ACCESS_MACOS_H
#define DIR_ACCESS_MACOS_H
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
+
+#include "core/io/dir_access.h"
+#include "drivers/unix/dir_access_unix.h"
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
-#include "core/io/dir_access.h"
-#include "drivers/unix/dir_access_unix.h"
-
class DirAccessMacOS : public DirAccessUnix {
protected:
virtual String fix_unicode_name(const char *p_name) const override;
@@ -51,6 +51,6 @@ protected:
virtual bool is_hidden(const String &p_name) override;
};
-#endif // UNIX ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX ENABLED
#endif // DIR_ACCESS_MACOS_H
diff --git a/platform/macos/dir_access_macos.mm b/platform/macos/dir_access_macos.mm
index 3373cada1f..22ebac2db4 100644
--- a/platform/macos/dir_access_macos.mm
+++ b/platform/macos/dir_access_macos.mm
@@ -30,7 +30,7 @@
#include "dir_access_macos.h"
-#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+#if defined(UNIX_ENABLED)
#include <errno.h>
@@ -78,4 +78,4 @@ bool DirAccessMacOS::is_hidden(const String &p_name) {
return [hidden boolValue];
}
-#endif // UNIX_ENABLED || LIBC_FILEIO_ENABLED
+#endif // UNIX_ENABLED
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index e72273a681..618da6b388 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -401,7 +401,7 @@ public:
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 Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual Point2i ime_get_selection() const override;
virtual String ime_get_text() const override;
@@ -430,12 +430,12 @@ public:
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_macos_driver();
- DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerMacOS();
};
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 1914c5f35d..4478a635a8 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -586,7 +586,7 @@ void DisplayServerMacOS::send_event(NSEvent *p_event) {
// Special case handling of command-period, which is traditionally a special
// shortcut in macOS and doesn't arrive at our regular keyDown handler.
if ([p_event type] == NSEventTypeKeyDown) {
- if (([p_event modifierFlags] & NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) {
+ if ((([p_event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand) && [p_event keyCode] == 0x2f) {
Ref<InputEventKey> k;
k.instantiate();
@@ -2179,7 +2179,7 @@ void DisplayServerMacOS::screen_set_keep_on(bool p_enable) {
}
if (p_enable) {
- String app_name_string = ProjectSettings::get_singleton()->get("application/config/name");
+ String app_name_string = GLOBAL_GET("application/config/name");
NSString *name = [NSString stringWithUTF8String:(app_name_string.is_empty() ? "Godot Engine" : app_name_string.utf8().get_data())];
NSString *reason = @"Godot Engine running with display/window/energy_saving/keep_screen_on = true";
IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, (__bridge CFStringRef)name, (__bridge CFStringRef)reason, (__bridge CFStringRef)reason, nullptr, 0, nullptr, &screen_keep_on_assertion);
@@ -2655,25 +2655,33 @@ void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offs
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- wd.wb_offset = p_offset;
+ float scale = screen_get_max_scale();
+ wd.wb_offset = p_offset / scale;
+ wd.wb_offset.x = MAX(wd.wb_offset.x, 12);
+ wd.wb_offset.y = MAX(wd.wb_offset.y, 12);
+ if (wd.window_button_view) {
+ [wd.window_button_view setOffset:NSMakePoint(wd.wb_offset.x, wd.wb_offset.y)];
+ }
}
-Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const {
+Vector3i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!windows.has(p_window), Vector2i());
+ ERR_FAIL_COND_V(!windows.has(p_window), Vector3i());
const WindowData &wd = windows[p_window];
if (!wd.window_button_view) {
- return Vector2i();
+ return Vector3i();
}
- float max_x = wd.wb_offset.x + [wd.window_button_view frame].size.width;
+ float scale = screen_get_max_scale();
+ float max_x = [wd.window_button_view getOffset].x + [wd.window_button_view frame].size.width;
+ float max_y = [wd.window_button_view getOffset].y + [wd.window_button_view frame].size.height;
if ([wd.window_object windowTitlebarLayoutDirection] == NSUserInterfaceLayoutDirectionRightToLeft) {
- return Vector2i(0, max_x * screen_get_max_scale());
+ return Vector3i(0, max_x * scale, max_y * scale);
} else {
- return Vector2i(max_x * screen_get_max_scale(), 0);
+ return Vector3i(max_x * scale, 0, max_y * scale);
}
}
@@ -3397,10 +3405,29 @@ void DisplayServerMacOS::set_icon(const Ref<Image> &p_icon) {
[NSApp setApplicationIconImage:nsimg];
}
-DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerMacOS(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.", "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_command;
+ if (OS::get_singleton()->get_bundle_resource_dir() == OS::get_singleton()->get_executable_path().get_base_dir()) {
+ executable_command = vformat("%s --rendering-driver opengl3", OS::get_singleton()->get_executable_path());
+ } else {
+ executable_command = vformat("open %s --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path());
+ }
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command: '" +
+ executable_command + "'.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
@@ -3548,7 +3575,7 @@ bool DisplayServerMacOS::mouse_process_popups(bool p_close) {
return closed;
}
-DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
r_error = OK;
@@ -3657,6 +3684,11 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
Point2i window_position(
screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2,
screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2);
+
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution));
ERR_FAIL_COND(main_window == INVALID_WINDOW_ID);
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 070830c486..de6016cb9b 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -31,6 +31,8 @@
#include "export_plugin.h"
#include "codesign.h"
+#include "lipo.h"
+#include "macho.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
@@ -381,7 +383,7 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
if (lines[i].find("$binary") != -1) {
strnew += lines[i].replace("$binary", p_binary) + "\n";
} else if (lines[i].find("$name") != -1) {
- strnew += lines[i].replace("$name", ProjectSettings::get_singleton()->get("application/config/name")) + "\n";
+ strnew += lines[i].replace("$name", GLOBAL_GET("application/config/name")) + "\n";
} else if (lines[i].find("$bundle_identifier") != -1) {
strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
} else if (lines[i].find("$short_version") != -1) {
@@ -471,7 +473,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
case 1: { // "rcodesign"
print_verbose("using rcodesign notarization...");
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
return Error::FAILED;
@@ -634,7 +636,7 @@ Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_pre
case 2: { // "rcodesign"
print_verbose("using rcodesign codesign...");
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
return Error::FAILED;
@@ -754,6 +756,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
if (extensions_to_sign.is_empty()) {
extensions_to_sign.push_back("dylib");
extensions_to_sign.push_back("framework");
+ extensions_to_sign.push_back("");
}
Error dir_access_error;
@@ -778,6 +781,10 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
if (code_sign_error != OK) {
return code_sign_error;
}
+ if (is_executable(current_file_path)) {
+ // chmod with 0755 if the file is executable.
+ FileAccess::set_unix_permissions(current_file_path, 0755);
+ }
} else if (dir_access->current_is_dir()) {
Error code_sign_error{ _code_sign_directory(p_preset, current_file_path, p_ent_path, p_should_error_on_non_code) };
if (code_sign_error != OK) {
@@ -799,6 +806,14 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
const String &p_in_app_path, bool p_sign_enabled,
const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
bool p_should_error_on_non_code_sign) {
+ static Vector<String> extensions_to_sign;
+
+ if (extensions_to_sign.is_empty()) {
+ extensions_to_sign.push_back("dylib");
+ extensions_to_sign.push_back("framework");
+ extensions_to_sign.push_back("");
+ }
+
Error err{ OK };
if (dir_access->dir_exists(p_src_path)) {
#ifndef UNIX_ENABLED
@@ -818,7 +833,13 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
// If it is a directory, find and sign all dynamic libraries.
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
} else {
- err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
+ if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
+ err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
+ }
+ if (is_executable(p_in_app_path)) {
+ // chmod with 0755 if the file is executable.
+ FileAccess::set_unix_permissions(p_in_app_path, 0755);
+ }
}
}
return err;
@@ -877,6 +898,17 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str
return OK;
}
+bool EditorExportPlatformMacOS::is_shbang(const String &p_path) const {
+ Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("Can't open file: \"%s\".", p_path));
+ uint16_t magic = fb->get_16();
+ return (magic == 0x2123);
+}
+
+bool EditorExportPlatformMacOS::is_executable(const String &p_path) const {
+ return MachO::is_macho(p_path) || LipO::is_lipo(p_path) || is_shbang(p_path);
+}
+
Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
if (f.is_null()) {
@@ -950,8 +982,8 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String binary_to_use = "godot_macos_" + String(p_debug ? "debug" : "release") + "." + architecture;
String pkg_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ pkg_name = String(GLOBAL_GET("application/config/name"));
} else {
pkg_name = "Unnamed";
}
@@ -1041,7 +1073,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- Dictionary appnames = ProjectSettings::get_singleton()->get("application/config/name_localized");
+ Dictionary appnames = GLOBAL_GET("application/config/name_localized");
Dictionary microphone_usage_descriptions = p_preset->get("privacy/microphone_usage_description_localized");
Dictionary camera_usage_descriptions = p_preset->get("privacy/camera_usage_description_localized");
Dictionary location_usage_descriptions = p_preset->get("privacy/location_usage_description_localized");
@@ -1055,7 +1087,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
Dictionary removable_volumes_usage_descriptions = p_preset->get("privacy/removable_volumes_usage_description_localized");
Dictionary copyrights = p_preset->get("application/copyright_localized");
- Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
+ Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
{
String fname = tmp_app_path_name + "/Contents/Resources/en.lproj";
@@ -1063,7 +1095,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */");
f->store_line("");
- f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";");
+ f->store_line("CFBundleDisplayName = \"" + GLOBAL_GET("application/config/name").operator String() + "\";");
if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
f->store_line("NSMicrophoneUsageDescription = \"" + p_preset->get("privacy/microphone_usage_description").operator String() + "\";");
}
@@ -1158,11 +1190,8 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
// Now process our template.
bool found_binary = false;
- Vector<String> dylibs_found;
while (ret == UNZ_OK && err == OK) {
- bool is_execute = false;
-
// Get filename.
unz_file_info info;
char fname[16384];
@@ -1219,7 +1248,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
continue; // skip
}
found_binary = true;
- is_execute = true;
file = "Contents/MacOS/" + pkg_name;
}
@@ -1229,7 +1257,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (p_preset->get("application/icon") != "") {
iconpath = p_preset->get("application/icon");
} else {
- iconpath = ProjectSettings::get_singleton()->get("application/config/icon");
+ iconpath = GLOBAL_GET("application/config/icon");
}
if (!iconpath.is_empty()) {
@@ -1251,25 +1279,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
if (data.size() > 0) {
- if (file.find("/data.mono.macos.release_debug." + architecture + "/") != -1) {
- if (!p_debug) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; // skip
- }
- file = file.replace("/data.mono.macos.release_debug." + architecture + "/", "/GodotSharp/");
- }
- if (file.find("/data.mono.macos.release." + architecture + "/") != -1) {
- if (p_debug) {
- ret = unzGoToNextFile(src_pkg_zip);
- continue; // skip
- }
- file = file.replace("/data.mono.macos.release." + architecture + "/", "/GodotSharp/");
- }
-
- if (file.ends_with(".dylib")) {
- dylibs_found.push_back(file);
- }
-
print_verbose("ADDING: " + file + " size: " + itos(data.size()));
// Write it into our application bundle.
@@ -1285,7 +1294,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
f.unref();
- if (is_execute) {
+ if (is_executable(file)) {
// chmod with 0755 if the file is executable.
FileAccess::set_unix_permissions(file, 0755);
}
@@ -1324,12 +1333,35 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
return ERR_SKIP;
}
+ // See if we can code sign our new package.
+ bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
+ bool ad_hoc = false;
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ ad_hoc = true;
+ } break;
+ case 2: { // "rcodesign"
+ ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ } break;
+#ifdef MACOS_ENABLED
+ case 3: { // "codesign"
+ ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+ } break;
+#endif
+ default: {
+ };
+ }
+
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
Vector<SharedObject> shared_objects;
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
- // See if we can code sign our new package.
- bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
+ bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
+ if (!shared_objects.is_empty() && sign_enabled && ad_hoc && !lib_validation) {
+ add_message(EXPORT_MESSAGE_INFO, TTR("Entitlements Modified"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
+ lib_validation = true;
+ }
String ent_path = p_preset->get("codesign/entitlements/custom_file");
String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
@@ -1365,7 +1397,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) {
+ if (lib_validation) {
ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>");
ent_f->store_line("<true/>");
}
@@ -1495,32 +1527,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- bool ad_hoc = false;
- int codesign_tool = p_preset->get("codesign/codesign");
- switch (codesign_tool) {
- case 1: { // built-in ad-hoc
- ad_hoc = true;
- } break;
- case 2: { // "rcodesign"
- ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
- } break;
-#ifdef MACOS_ENABLED
- case 3: { // "codesign"
- ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
- } break;
-#endif
- default: {
- };
- }
-
- if (err == OK) {
- bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
- if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
- err = ERR_CANT_CREATE;
- }
- }
-
if (err == OK) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
@@ -1529,8 +1535,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
} else {
- String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file());
- err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
+ String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target);
+ tmp_app_dir->make_dir_recursive(path_in_app);
+ err = _copy_and_sign_files(da, src_path, path_in_app.path_join(src_path.get_file()), sign_enabled, p_preset, ent_path, false);
}
if (err != OK) {
break;
@@ -1546,14 +1553,6 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- if (sign_enabled) {
- for (int i = 0; i < dylibs_found.size(); i++) {
- if (err == OK) {
- err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path, false);
- }
- }
- }
-
if (err == OK && sign_enabled) {
if (ep.step(TTR("Code signing bundle"), 2)) {
return ERR_SKIP;
@@ -1683,8 +1682,6 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
} else if (da->current_is_dir()) {
_zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
} else {
- bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command");
-
OS::DateTime dt = OS::get_singleton()->get_datetime();
zip_fileinfo zipfi;
@@ -1698,7 +1695,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
// 0100000: regular file type
// 0000755: permissions rwxr-xr-x
// 0000644: permissions rw-r--r--
- uint32_t _mode = (is_executable ? 0100755 : 0100644);
+ uint32_t _mode = (is_executable(dir.path_join(f)) ? 0100755 : 0100644);
zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
zipfi.internal_fa = 0;
@@ -1855,7 +1852,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false;
}
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
@@ -1878,7 +1875,7 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false;
}
} else if (codesign_tool == 2) {
- String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Code signing: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 87790129d3..b6ad587caa 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -97,6 +97,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
return true;
}
+ bool is_shbang(const String &p_path) const;
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
@@ -108,6 +109,7 @@ public:
virtual String get_os_name() const override { return "macOS"; }
virtual Ref<Texture2D> get_logo() const override { return logo; }
+ virtual bool is_executable(const String &p_path) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override {
List<String> list;
if (use_dmg()) {
diff --git a/platform/macos/export/lipo.cpp b/platform/macos/export/lipo.cpp
index 82baf18c52..76d4eee418 100644
--- a/platform/macos/export/lipo.cpp
+++ b/platform/macos/export/lipo.cpp
@@ -28,12 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "modules/modules_enabled.gen.h" // For regex.
-
#include "lipo.h"
-#ifdef MODULE_REGEX_ENABLED
-
bool LipO::is_lipo(const String &p_path) {
Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path));
@@ -232,5 +228,3 @@ void LipO::close() {
LipO::~LipO() {
close();
}
-
-#endif // MODULE_REGEX_ENABLED
diff --git a/platform/macos/export/lipo.h b/platform/macos/export/lipo.h
index 6378f9899c..bd8b7f6f2c 100644
--- a/platform/macos/export/lipo.h
+++ b/platform/macos/export/lipo.h
@@ -35,12 +35,9 @@
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
-#include "modules/modules_enabled.gen.h" // For regex.
#include "macho.h"
-#ifdef MODULE_REGEX_ENABLED
-
class LipO : public RefCounted {
struct FatArch {
uint32_t cputype;
@@ -71,6 +68,4 @@ public:
~LipO();
};
-#endif // MODULE_REGEX_ENABLED
-
#endif // MACOS_LIPO_H
diff --git a/platform/macos/export/macho.cpp b/platform/macos/export/macho.cpp
index e6e67eff06..642d99e098 100644
--- a/platform/macos/export/macho.cpp
+++ b/platform/macos/export/macho.cpp
@@ -28,24 +28,20 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "modules/modules_enabled.gen.h" // For regex.
-
#include "macho.h"
-#ifdef MODULE_REGEX_ENABLED
-
uint32_t MachO::seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max) {
- uint32_t align = p_max;
+ uint32_t salign = p_max;
if (p_vmaddr != 0) {
uint64_t seg_align = 1;
- align = 0;
+ salign = 0;
while ((seg_align & p_vmaddr) == 0) {
seg_align = seg_align << 1;
- align++;
+ salign++;
}
- align = CLAMP(align, p_min, p_max);
+ salign = CLAMP(salign, p_min, p_max);
}
- return align;
+ return salign;
}
bool MachO::alloc_signature(uint64_t p_size) {
@@ -544,5 +540,3 @@ bool MachO::set_signature_size(uint64_t p_size) {
}
return true;
}
-
-#endif // MODULE_REGEX_ENABLED
diff --git a/platform/macos/export/macho.h b/platform/macos/export/macho.h
index 0d42a7013f..0c954e66b1 100644
--- a/platform/macos/export/macho.h
+++ b/platform/macos/export/macho.h
@@ -37,9 +37,6 @@
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
-#include "modules/modules_enabled.gen.h" // For regex.
-
-#ifdef MODULE_REGEX_ENABLED
class MachO : public RefCounted {
struct MachHeader {
@@ -210,6 +207,4 @@ public:
bool set_signature_size(uint64_t p_size);
};
-#endif // MODULE_REGEX_ENABLED
-
#endif // MACOS_MACHO_H
diff --git a/platform/macos/export/plist.cpp b/platform/macos/export/plist.cpp
index 36de9dd34b..cad014e65b 100644
--- a/platform/macos/export/plist.cpp
+++ b/platform/macos/export/plist.cpp
@@ -28,12 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "modules/modules_enabled.gen.h" // For regex.
-
#include "plist.h"
-#ifdef MODULE_REGEX_ENABLED
-
Ref<PListNode> PListNode::new_array() {
Ref<PListNode> node = memnew(PListNode());
ERR_FAIL_COND_V(node.is_null(), Ref<PListNode>());
@@ -566,5 +562,3 @@ String PList::save_text() const {
Ref<PListNode> PList::get_root() {
return root;
}
-
-#endif // MODULE_REGEX_ENABLED
diff --git a/platform/macos/export/plist.h b/platform/macos/export/plist.h
index b3c51a9635..97331a3629 100644
--- a/platform/macos/export/plist.h
+++ b/platform/macos/export/plist.h
@@ -35,9 +35,6 @@
#include "core/crypto/crypto_core.h"
#include "core/io/file_access.h"
-#include "modules/modules_enabled.gen.h" // For regex.
-
-#ifdef MODULE_REGEX_ENABLED
class PListNode;
@@ -111,6 +108,4 @@ public:
~PListNode() {}
};
-#endif // MODULE_REGEX_ENABLED
-
#endif // MACOS_PLIST_H
diff --git a/platform/macos/godot_button_view.h b/platform/macos/godot_button_view.h
index e7627a9e9b..ef1d5fe412 100644
--- a/platform/macos/godot_button_view.h
+++ b/platform/macos/godot_button_view.h
@@ -42,10 +42,15 @@
CGFloat spacing;
bool mouse_in_group;
bool rtl;
+ NSButton *close_button;
+ NSButton *miniaturize_button;
+ NSButton *zoom_button;
}
- (void)initButtons:(CGFloat)button_spacing offset:(NSPoint)button_offset rtl:(bool)is_rtl;
- (void)displayButtons;
+- (void)setOffset:(NSPoint)button_offset;
+- (NSPoint)getOffset;
@end
diff --git a/platform/macos/godot_button_view.mm b/platform/macos/godot_button_view.mm
index 9106f0b0db..7d380cbe11 100644
--- a/platform/macos/godot_button_view.mm
+++ b/platform/macos/godot_button_view.mm
@@ -40,6 +40,9 @@
spacing = 20;
mouse_in_group = false;
rtl = false;
+ close_button = nullptr;
+ miniaturize_button = nullptr;
+ zoom_button = nullptr;
return self;
}
@@ -48,15 +51,15 @@
spacing = button_spacing;
rtl = is_rtl;
- NSButton *close_button = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:NSWindowStyleMaskTitled];
+ 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 = [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 = [NSWindow standardWindowButton:NSWindowZoomButton forStyleMask:NSWindowStyleMaskTitled];
[zoom_button setFrameOrigin:NSMakePoint(rtl ? 0 : spacing * 2, 0)];
[self addSubview:zoom_button];
@@ -71,6 +74,19 @@
[self displayButtons];
}
+- (void)setOffset:(NSPoint)button_offset {
+ if (zoom_button) {
+ offset.y = button_offset.y - zoom_button.frame.size.height / 2;
+ offset.x = button_offset.x - zoom_button.frame.size.width / 2;
+
+ [self viewDidMoveToWindow];
+ }
+}
+
+- (NSPoint)getOffset {
+ return offset;
+}
+
- (void)viewDidMoveToWindow {
if (!self.window) {
return;
diff --git a/platform/macos/joypad_macos.h b/platform/macos/joypad_macos.h
index 4b14fed6d5..8743fc91a9 100644
--- a/platform/macos/joypad_macos.h
+++ b/platform/macos/joypad_macos.h
@@ -31,14 +31,10 @@
#ifndef JOYPAD_MACOS_H
#define JOYPAD_MACOS_H
-#ifdef MACOS_10_0_4
-#import <IOKit/hidsystem/IOHIDUsageTables.h>
-#else
-#import <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
-#endif
#import <ForceFeedback/ForceFeedback.h>
#import <ForceFeedback/ForceFeedbackConstants.h>
#import <IOKit/hid/IOHIDLib.h>
+#import <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
#include "core/input/input.h"
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index ae8534f6ab..e620b058d3 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -148,9 +148,11 @@ void OS_MacOS::alert(const String &p_alert, const String &p_title) {
NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
NSString *ns_alert = [NSString stringWithUTF8String:p_alert.utf8().get_data()];
+ NSTextField *text_field = [NSTextField labelWithString:ns_alert];
+ [text_field setAlignment:NSTextAlignmentCenter];
[window addButtonWithTitle:@"OK"];
[window setMessageText:ns_title];
- [window setInformativeText:ns_alert];
+ [window setAccessoryView:text_field];
[window setAlertStyle:NSAlertStyleWarning];
id key_window = [[NSApplication sharedApplication] keyWindow];
@@ -497,7 +499,14 @@ String OS_MacOS::get_unique_id() const {
}
bool OS_MacOS::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
void OS_MacOS::disable_crash_handler() {
diff --git a/platform/macos/vulkan_context_macos.h b/platform/macos/vulkan_context_macos.h
index 579c42b042..2a81336994 100644
--- a/platform/macos/vulkan_context_macos.h
+++ b/platform/macos/vulkan_context_macos.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_MACOS_H
#define VULKAN_CONTEXT_MACOS_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#import <AppKit/AppKit.h>
@@ -44,4 +46,6 @@ public:
~VulkanContextMacOS();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_MACOS_H
diff --git a/platform/macos/vulkan_context_macos.mm b/platform/macos/vulkan_context_macos.mm
index cf317f3c68..1df6b3ed18 100644
--- a/platform/macos/vulkan_context_macos.mm
+++ b/platform/macos/vulkan_context_macos.mm
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifdef VULKAN_ENABLED
#include "vulkan_context_macos.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +58,5 @@ VulkanContextMacOS::VulkanContextMacOS() {
VulkanContextMacOS::~VulkanContextMacOS() {
}
+
+#endif // VULKAN_ENABLED
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 4e4afb9704..ab0b20762f 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -442,7 +442,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
#ifdef WINDOWS_ENABLED
// Sign with signtool
- String signtool_path = EditorSettings::get_singleton()->get("export/uwp/signtool");
+ String signtool_path = EDITOR_GET("export/uwp/signtool");
if (signtool_path.is_empty()) {
return OK;
}
@@ -454,9 +454,9 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
static String algs[] = { "MD5", "SHA1", "SHA256" };
- String cert_path = EditorSettings::get_singleton()->get("export/uwp/debug_certificate");
- String cert_pass = EditorSettings::get_singleton()->get("export/uwp/debug_password");
- int cert_alg = EditorSettings::get_singleton()->get("export/uwp/debug_algorithm");
+ String cert_path = EDITOR_GET("export/uwp/debug_certificate");
+ String cert_pass = EDITOR_GET("export/uwp/debug_password");
+ int cert_alg = EDITOR_GET("export/uwp/debug_algorithm");
if (!p_debug) {
cert_path = p_preset->get("signing/certificate");
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index b0427d1a65..74b9ab4875 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -213,7 +213,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
String architecture = arch == "arm32" ? "arm" : (arch == "x86_32" ? "x86" : "x64");
result = result.replace("$architecture$", architecture);
- result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)ProjectSettings::get_singleton()->get("application/config/name") : String(p_preset->get("package/display_name")));
+ result = result.replace("$display_name$", String(p_preset->get("package/display_name")).is_empty() ? (String)GLOBAL_GET("application/config/name") : String(p_preset->get("package/display_name")));
result = result.replace("$publisher_display_name$", p_preset->get("package/publisher_display_name"));
result = result.replace("$app_description$", p_preset->get("package/description"));
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 8050d299f0..141c28c713 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -159,7 +159,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
outside = true;
// FIXME: Hardcoded for now, add Vulkan support.
- p_video_driver = VIDEO_DRIVER_OPENGL;
+ p_video_driver = RENDERING_DRIVER_OPENGL3;
ContextEGL_UWP::Driver opengl_api_type = ContextEGL_UWP::GLES_2_0;
bool gl_initialization_error = false;
@@ -826,10 +826,6 @@ OS_UWP::OS_UWP() {
pressrc = 0;
old_invalid = true;
mouse_mode = MOUSE_MODE_VISIBLE;
-#ifdef STDOUT_FILE
- stdo = fopen("stdout.txt", "wb");
-#endif
-
gl_context = nullptr;
display_request = ref new Windows::System::Display::DisplayRequest();
@@ -847,7 +843,4 @@ OS_UWP::OS_UWP() {
}
OS_UWP::~OS_UWP() {
-#ifdef STDOUT_FILE
- fclose(stdo);
-#endif
}
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 0c1c4a793a..c1df7827cd 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -42,9 +42,9 @@
#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
-#include <fcntl.h>
#include <io.h>
#include <stdio.h>
+
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
diff --git a/platform/web/.eslintrc.html.js b/platform/web/.eslintrc.html.js
new file mode 100644
index 0000000000..5cb8de360a
--- /dev/null
+++ b/platform/web/.eslintrc.html.js
@@ -0,0 +1,19 @@
+module.exports = {
+ "plugins": [
+ "html",
+ "@html-eslint",
+ ],
+ "parser": "@html-eslint/parser",
+ "extends": ["plugin:@html-eslint/recommended", "./.eslintrc.js"],
+ "rules": {
+ "no-alert": "off",
+ "no-console": "off",
+ "@html-eslint/require-closing-tags": ["error", { "selfClosing": "never" }],
+ "@html-eslint/indent": ["error", "tab"],
+ },
+ "globals": {
+ "Godot": true,
+ "Engine": true,
+ "$GODOT_CONFIG": true,
+ },
+};
diff --git a/platform/web/SCsub b/platform/web/SCsub
index 013b734be2..077024507a 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -2,6 +2,20 @@
Import("env")
+# The HTTP server "targets". Run with "scons p=web serve", or "scons p=web run"
+if "serve" in COMMAND_LINE_TARGETS or "run" in COMMAND_LINE_TARGETS:
+ from serve import serve
+ import os
+
+ port = os.environ.get("GODOT_WEB_TEST_PORT", 8060)
+ try:
+ port = int(port)
+ except Exception:
+ print("GODOT_WEB_TEST_PORT must be a valid integer")
+ sys.exit(255)
+ serve(env.Dir("#bin/.web_zip").abspath, port, "run" in COMMAND_LINE_TARGETS)
+ sys.exit(0)
+
web_files = [
"audio_driver_web.cpp",
"display_server_web.cpp",
@@ -21,6 +35,7 @@ sys_env.AddJSLibraries(
"js/libs/library_godot_os.js",
"js/libs/library_godot_runtime.js",
"js/libs/library_godot_input.js",
+ "js/libs/library_godot_webgl2.js",
]
)
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index f6a61b18e4..10ed8b8343 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -738,11 +738,11 @@ void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
}
}
-DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
- return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
}
-DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
+DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error) {
r_error = OK; // Always succeeds for now.
// Ensure the canvas ID.
@@ -773,6 +773,9 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
if (emscripten_webgl_make_context_current(webgl_ctx) != EMSCRIPTEN_RESULT_SUCCESS) {
webgl2_init_failed = true;
} else {
+ if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
+ // @todo Should we log this?
+ }
RasterizerGLES3::make_current();
}
}
diff --git a/platform/web/display_server_web.h b/platform/web/display_server_web.h
index 85076b906f..3222e2483e 100644
--- a/platform/web/display_server_web.h
+++ b/platform/web/display_server_web.h
@@ -96,7 +96,7 @@ private:
static void _js_utterance_callback(int p_event, int p_id, int p_pos);
static Vector<String> get_rendering_drivers_func();
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static void _dispatch_input_event(const Ref<InputEvent> &p_event);
@@ -221,7 +221,7 @@ public:
virtual void swap_buffers() override;
static void register_web_driver();
- DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error);
+ DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Point2i *p_position, const Size2i &p_resolution, Error &r_error);
~DisplayServerWeb();
};
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 1c327fe4b2..f59ac54f20 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -485,6 +485,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
}
html.resize(f->get_length());
f->get_buffer(html.ptrw(), html.size());
+ f.unref(); // close file.
// Generate HTML file with replaced strings.
_fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
diff --git a/platform/web/godot_webgl2.h b/platform/web/godot_webgl2.h
index 968b70f84b..ae6b23ae18 100644
--- a/platform/web/godot_webgl2.h
+++ b/platform/web/godot_webgl2.h
@@ -34,4 +34,21 @@
#include "GLES3/gl3.h"
#include "webgl/webgl2.h"
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void godot_webgl2_glFramebufferTextureMultiviewOVR(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+
+#define glFramebufferTextureMultiviewOVR godot_webgl2_glFramebufferTextureMultiviewOVR
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // GODOT_WEBGL2_H
diff --git a/platform/web/js/libs/library_godot_display.js b/platform/web/js/libs/library_godot_display.js
index 91cb8e728a..39c8569655 100644
--- a/platform/web/js/libs/library_godot_display.js
+++ b/platform/web/js/libs/library_godot_display.js
@@ -174,7 +174,7 @@ const GodotDisplayCursor = {
$GodotDisplayCursor__deps: ['$GodotOS', '$GodotConfig'],
$GodotDisplayCursor__postset: 'GodotOS.atexit(function(resolve, reject) { GodotDisplayCursor.clear(); resolve(); });',
$GodotDisplayCursor: {
- shape: 'auto',
+ shape: 'default',
visible: true,
cursors: {},
set_style: function (style) {
@@ -185,7 +185,7 @@ const GodotDisplayCursor = {
let css = shape;
if (shape in GodotDisplayCursor.cursors) {
const c = GodotDisplayCursor.cursors[shape];
- css = `url("${c.url}") ${c.x} ${c.y}, auto`;
+ css = `url("${c.url}") ${c.x} ${c.y}, default`;
}
if (GodotDisplayCursor.visible) {
GodotDisplayCursor.set_style(css);
@@ -193,7 +193,7 @@ const GodotDisplayCursor = {
},
clear: function () {
GodotDisplayCursor.set_style('');
- GodotDisplayCursor.shape = 'auto';
+ GodotDisplayCursor.shape = 'default';
GodotDisplayCursor.visible = true;
Object.keys(GodotDisplayCursor.cursors).forEach(function (key) {
URL.revokeObjectURL(GodotDisplayCursor.cursors[key]);
diff --git a/platform/web/js/libs/library_godot_javascript_singleton.js b/platform/web/js/libs/library_godot_javascript_singleton.js
index 692f27676a..c86cbbae45 100644
--- a/platform/web/js/libs/library_godot_javascript_singleton.js
+++ b/platform/web/js/libs/library_godot_javascript_singleton.js
@@ -88,7 +88,7 @@ const GodotJSWrapper = {
return GodotRuntime.getHeapValue(val, 'double');
case 4:
return GodotRuntime.parseString(GodotRuntime.getHeapValue(val, '*'));
- case 21: // OBJECT
+ case 24: // OBJECT
return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val, 'i64'));
default:
return undefined;
@@ -117,7 +117,7 @@ const GodotJSWrapper = {
}
const id = GodotJSWrapper.get_proxied(p_val);
GodotRuntime.setHeapValue(p_exchange, id, 'i64');
- return 21;
+ return 24; // OBJECT
},
},
diff --git a/platform/web/js/libs/library_godot_webgl2.js b/platform/web/js/libs/library_godot_webgl2.js
new file mode 100644
index 0000000000..365f712be7
--- /dev/null
+++ b/platform/web/js/libs/library_godot_webgl2.js
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* library_godot_webgl2.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+const GodotWebGL2 = {
+ $GodotWebGL2__deps: ['$GL', '$GodotRuntime'],
+ $GodotWebGL2: {},
+
+ godot_webgl2_glFramebufferTextureMultiviewOVR__deps: ['emscripten_webgl_get_current_context'],
+ godot_webgl2_glFramebufferTextureMultiviewOVR__proxy: 'sync',
+ godot_webgl2_glFramebufferTextureMultiviewOVR__sig: 'viiiiii',
+ godot_webgl2_glFramebufferTextureMultiviewOVR: function (target, attachment, texture, level, base_view_index, num_views) {
+ const context = GL.currentContext;
+ if (typeof context.multiviewExt === 'undefined') {
+ const ext = context.GLctx.getExtension('OVR_multiview2');
+ if (!ext) {
+ console.error('Trying to call glFramebufferTextureMultiviewOVR() without the OVR_multiview2 extension');
+ return;
+ }
+ context.multiviewExt = ext;
+ }
+ context.multiviewExt.framebufferTextureMultiviewOVR(target, attachment, GL.textures[texture], level, base_view_index, num_views);
+ },
+};
+
+autoAddDeps(GodotWebGL2, '$GodotWebGL2');
+mergeInto(LibraryManager.library, GodotWebGL2);
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index c263ee094b..07c53e51d0 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -37,9 +37,6 @@
#include "platform/web/display_server_web.h"
#include "modules/modules_enabled.gen.h" // For websocket.
-#ifdef MODULE_WEBSOCKET_ENABLED
-#include "modules/websocket/remote_debugger_peer_websocket.h"
-#endif
#include <dlfcn.h>
#include <emscripten.h>
@@ -56,11 +53,6 @@ void OS_Web::alert(const String &p_alert, const String &p_title) {
void OS_Web::initialize() {
OS_Unix::initialize_core();
DisplayServerWeb::register_web_driver();
-
-#ifdef MODULE_WEBSOCKET_ENABLED
- EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create);
- EngineDebugger::register_uri_handler("wss://", RemoteDebuggerPeerWebSocket::create);
-#endif
}
void OS_Web::resume_audio() {
diff --git a/platform/web/package-lock.json b/platform/web/package-lock.json
index f8c67b206f..e1428546c6 100644
--- a/platform/web/package-lock.json
+++ b/platform/web/package-lock.json
@@ -8,12 +8,16 @@
"name": "godot",
"version": "1.0.0",
"license": "MIT",
+ "dependencies": {
+ "eslint-plugin-html": "^7.1.0"
+ },
"devDependencies": {
- "eslint": "^7.28.0",
+ "@html-eslint/eslint-plugin": "^0.15.0",
+ "@html-eslint/parser": "^0.15.0",
+ "eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.23.4",
- "jsdoc": "^3.6.7",
- "serve": "^13.0.2"
+ "jsdoc": "^3.6.7"
}
},
"node_modules/@babel/code-frame": {
@@ -84,9 +88,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz",
- "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
+ "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -103,6 +107,47 @@
"node": "^10.12.0 || >=12.0.0"
}
},
+ "node_modules/@html-eslint/eslint-plugin": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.15.0.tgz",
+ "integrity": "sha512-6DUb2ZN1PUlzlNzNj4aBhoObBp3Kl/+YbZ6CnkgFAsQSW0tSFAu7p8WwESkz9RZLZZN9gCUlcaYKJnQjTkmnDA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/@html-eslint/parser": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.15.0.tgz",
+ "integrity": "sha512-fA+HQtWnODhOIK6j1p4XWqltINx7hM0WNNTM2RvlH/2glzeRDCcYq3vEmeQhnytvGocidu4ofTzNk80cLnnyiw==",
+ "dev": true,
+ "dependencies": {
+ "es-html-parser": "^0.0.8"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
+ "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.0",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -131,25 +176,6 @@
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
"dev": true
},
- "node_modules/@zeit/schemas": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz",
- "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==",
- "dev": true
- },
- "node_modules/accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
- "dev": true,
- "dependencies": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/acorn": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
@@ -163,9 +189,9 @@
}
},
"node_modules/acorn-jsx": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
- "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
@@ -187,15 +213,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/ansi-align": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
- "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.1.0"
- }
- },
"node_modules/ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -226,32 +243,6 @@
"node": ">=4"
}
},
- "node_modules/arch": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
- "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/arg": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
- "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==",
- "dev": true
- },
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -318,28 +309,6 @@
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
- "node_modules/boxen": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
- "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
- "dev": true,
- "dependencies": {
- "ansi-align": "^3.0.0",
- "camelcase": "^6.2.0",
- "chalk": "^4.1.0",
- "cli-boxes": "^2.2.1",
- "string-width": "^4.2.2",
- "type-fest": "^0.20.2",
- "widest-line": "^3.1.0",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -350,15 +319,6 @@
"concat-map": "0.0.1"
}
},
- "node_modules/bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
- "dev": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -381,18 +341,6 @@
"node": ">=6"
}
},
- "node_modules/camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/catharsis": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
@@ -475,32 +423,6 @@
"node": ">=8"
}
},
- "node_modules/cli-boxes": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
- "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/clipboardy": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz",
- "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==",
- "dev": true,
- "dependencies": {
- "arch": "^2.1.1",
- "execa": "^1.0.0",
- "is-wsl": "^2.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -516,51 +438,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
- "node_modules/compressible": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
- "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
- "dev": true,
- "dependencies": {
- "mime-db": ">= 1.43.0 < 2"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/compression": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz",
- "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==",
- "dev": true,
- "dependencies": {
- "accepts": "~1.3.5",
- "bytes": "3.0.0",
- "compressible": "~2.0.14",
- "debug": "2.6.9",
- "on-headers": "~1.0.1",
- "safe-buffer": "5.1.2",
- "vary": "~1.1.2"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/compression/node_modules/debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "dependencies": {
- "ms": "2.0.0"
- }
- },
- "node_modules/compression/node_modules/ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -573,15 +450,6 @@
"integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==",
"dev": true
},
- "node_modules/content-disposition": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
- "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -597,9 +465,9 @@
}
},
"node_modules/debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@@ -613,15 +481,6 @@
}
}
},
- "node_modules/deep-extend": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
- "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
- "dev": true,
- "engines": {
- "node": ">=4.0.0"
- }
- },
"node_modules/deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -652,21 +511,74 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/dom-serializer/node_modules/entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ]
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+ "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
- "node_modules/end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dev": true,
- "dependencies": {
- "once": "^1.4.0"
- }
- },
"node_modules/enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
@@ -727,6 +639,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/es-html-parser": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/es-html-parser/-/es-html-parser-0.0.8.tgz",
+ "integrity": "sha512-kjMH23xhvTBw/7Ve1Dtb/7yZdFajfvwOpdsgRHmnyt8yvTsDJnkFjUgEEaMZFW+e1OhN/eoZrvF9wehq+waTGg==",
+ "dev": true
+ },
"node_modules/es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -757,13 +675,14 @@
}
},
"node_modules/eslint": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
- "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
+ "version": "7.32.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
+ "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
"dev": true,
"dependencies": {
"@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.2",
+ "@eslint/eslintrc": "^0.4.3",
+ "@humanwhocodes/config-array": "^0.5.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -877,6 +796,14 @@
"ms": "^2.1.1"
}
},
+ "node_modules/eslint-plugin-html": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz",
+ "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==",
+ "dependencies": {
+ "htmlparser2": "^8.0.1"
+ }
+ },
"node_modules/eslint-plugin-import": {
"version": "2.23.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz",
@@ -1075,91 +1002,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/execa/node_modules/cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
- "dev": true,
- "dependencies": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- },
- "engines": {
- "node": ">=4.8"
- }
- },
- "node_modules/execa/node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/execa/node_modules/semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true,
- "bin": {
- "semver": "bin/semver"
- }
- },
- "node_modules/execa/node_modules/shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/execa/node_modules/shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/execa/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "which": "bin/which"
- }
- },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -1178,21 +1020,6 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
- "node_modules/fast-url-parser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
- "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
- "dev": true,
- "dependencies": {
- "punycode": "^1.3.2"
- }
- },
- "node_modules/fast-url-parser/node_modules/punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "dev": true
- },
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -1268,18 +1095,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/get-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
- "dev": true,
- "dependencies": {
- "pump": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/glob": {
"version": "7.1.7",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
@@ -1313,9 +1128,9 @@
}
},
"node_modules/globals": {
- "version": "13.9.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
- "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
+ "version": "13.17.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+ "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -1381,6 +1196,35 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "node_modules/htmlparser2": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+ "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "entities": "^4.3.0"
+ }
+ },
+ "node_modules/htmlparser2/node_modules/entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -1431,12 +1275,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
- "node_modules/ini": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
- "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
- "dev": true
- },
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -1503,21 +1341,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-docker": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
- "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
- "dev": true,
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -1588,15 +1411,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/is-string": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
@@ -1624,18 +1438,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "dev": true,
- "dependencies": {
- "is-docker": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1883,31 +1685,10 @@
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
"dev": true
},
- "node_modules/mime-db": {
- "version": "1.51.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
- "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/mime-types": {
- "version": "2.1.34",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
- "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
- "dev": true,
- "dependencies": {
- "mime-db": "1.51.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
@@ -1946,21 +1727,6 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
- "node_modules/negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
- "dev": true
- },
"node_modules/normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -1982,27 +1748,6 @@
"semver": "bin/semver"
}
},
- "node_modules/npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
- "dev": true,
- "dependencies": {
- "path-key": "^2.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/npm-run-path/node_modules/path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/object-inspect": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
@@ -2070,15 +1815,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
- "dev": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -2105,15 +1841,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@@ -2190,12 +1917,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/path-is-inside": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
- "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
- "dev": true
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -2211,12 +1932,6 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
- "node_modules/path-to-regexp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
- "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
- "dev": true
- },
"node_modules/path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
@@ -2280,16 +1995,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "dev": true,
- "dependencies": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -2299,39 +2004,6 @@
"node": ">=6"
}
},
- "node_modules/range-parser": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
- "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/rc": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
- "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
- "dev": true,
- "dependencies": {
- "deep-extend": "^0.6.0",
- "ini": "~1.3.0",
- "minimist": "^1.2.0",
- "strip-json-comments": "~2.0.1"
- },
- "bin": {
- "rc": "cli.js"
- }
- },
- "node_modules/rc/node_modules/strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -2371,28 +2043,6 @@
"url": "https://github.com/sponsors/mysticatea"
}
},
- "node_modules/registry-auth-token": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
- "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
- "dev": true,
- "dependencies": {
- "rc": "^1.1.6",
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/registry-url": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
- "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
- "dev": true,
- "dependencies": {
- "rc": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -2448,12 +2098,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
"node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
@@ -2469,86 +2113,6 @@
"node": ">=10"
}
},
- "node_modules/serve": {
- "version": "13.0.2",
- "resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz",
- "integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==",
- "dev": true,
- "dependencies": {
- "@zeit/schemas": "2.6.0",
- "ajv": "6.12.6",
- "arg": "2.0.0",
- "boxen": "5.1.2",
- "chalk": "2.4.1",
- "clipboardy": "2.3.0",
- "compression": "1.7.3",
- "serve-handler": "6.1.3",
- "update-check": "1.5.2"
- },
- "bin": {
- "serve": "bin/serve.js"
- }
- },
- "node_modules/serve-handler": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
- "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
- "dev": true,
- "dependencies": {
- "bytes": "3.0.0",
- "content-disposition": "0.5.2",
- "fast-url-parser": "1.1.3",
- "mime-types": "2.1.18",
- "minimatch": "3.0.4",
- "path-is-inside": "1.0.2",
- "path-to-regexp": "2.2.1",
- "range-parser": "1.2.0"
- }
- },
- "node_modules/serve-handler/node_modules/mime-db": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
- "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/serve-handler/node_modules/mime-types": {
- "version": "2.1.18",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
- "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
- "dev": true,
- "dependencies": {
- "mime-db": "~1.33.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/serve/node_modules/chalk": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
- "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/serve/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -2570,12 +2134,6 @@
"node": ">=8"
}
},
- "node_modules/signal-exit": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
- "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
- "dev": true
- },
"node_modules/slice-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
@@ -2661,7 +2219,7 @@
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"node_modules/string-width": {
@@ -2725,15 +2283,6 @@
"node": ">=4"
}
},
- "node_modules/strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -2872,16 +2421,6 @@
"integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==",
"dev": true
},
- "node_modules/update-check": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz",
- "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==",
- "dev": true,
- "dependencies": {
- "registry-auth-token": "3.3.2",
- "registry-url": "3.1.0"
- }
- },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2907,15 +2446,6 @@
"spdx-expression-parse": "^3.0.0"
}
},
- "node_modules/vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
- "dev": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2947,18 +2477,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/widest-line": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
- "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -2968,56 +2486,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/wrap-ansi/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/wrap-ansi/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/wrap-ansi/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -3090,9 +2558,9 @@
"dev": true
},
"@eslint/eslintrc": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz",
- "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
+ "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
@@ -3106,6 +2574,38 @@
"strip-json-comments": "^3.1.1"
}
},
+ "@html-eslint/eslint-plugin": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.15.0.tgz",
+ "integrity": "sha512-6DUb2ZN1PUlzlNzNj4aBhoObBp3Kl/+YbZ6CnkgFAsQSW0tSFAu7p8WwESkz9RZLZZN9gCUlcaYKJnQjTkmnDA==",
+ "dev": true
+ },
+ "@html-eslint/parser": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.15.0.tgz",
+ "integrity": "sha512-fA+HQtWnODhOIK6j1p4XWqltINx7hM0WNNTM2RvlH/2glzeRDCcYq3vEmeQhnytvGocidu4ofTzNk80cLnnyiw==",
+ "dev": true,
+ "requires": {
+ "es-html-parser": "^0.0.8"
+ }
+ },
+ "@humanwhocodes/config-array": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
+ "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+ "dev": true,
+ "requires": {
+ "@humanwhocodes/object-schema": "^1.2.0",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.4"
+ }
+ },
+ "@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "dev": true
+ },
"@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -3134,22 +2634,6 @@
"integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==",
"dev": true
},
- "@zeit/schemas": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.6.0.tgz",
- "integrity": "sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==",
- "dev": true
- },
- "accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
- "dev": true,
- "requires": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
- }
- },
"acorn": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
@@ -3157,9 +2641,9 @@
"dev": true
},
"acorn-jsx": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
- "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
"dev": true,
"requires": {}
},
@@ -3175,15 +2659,6 @@
"uri-js": "^4.2.2"
}
},
- "ansi-align": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
- "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
- "dev": true,
- "requires": {
- "string-width": "^4.1.0"
- }
- },
"ansi-colors": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -3205,18 +2680,6 @@
"color-convert": "^1.9.0"
}
},
- "arch": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
- "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
- "dev": true
- },
- "arg": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/arg/-/arg-2.0.0.tgz",
- "integrity": "sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==",
- "dev": true
- },
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -3268,22 +2731,6 @@
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
- "boxen": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
- "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
- "dev": true,
- "requires": {
- "ansi-align": "^3.0.0",
- "camelcase": "^6.2.0",
- "chalk": "^4.1.0",
- "cli-boxes": "^2.2.1",
- "string-width": "^4.2.2",
- "type-fest": "^0.20.2",
- "widest-line": "^3.1.0",
- "wrap-ansi": "^7.0.0"
- }
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -3294,12 +2741,6 @@
"concat-map": "0.0.1"
}
},
- "bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
- "dev": true
- },
"call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
@@ -3316,12 +2757,6 @@
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true
},
- "camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true
- },
"catharsis": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz",
@@ -3382,23 +2817,6 @@
}
}
},
- "cli-boxes": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
- "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
- "dev": true
- },
- "clipboardy": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz",
- "integrity": "sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==",
- "dev": true,
- "requires": {
- "arch": "^2.1.1",
- "execa": "^1.0.0",
- "is-wsl": "^2.1.1"
- }
- },
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3414,47 +2832,6 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
- "compressible": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
- "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
- "dev": true,
- "requires": {
- "mime-db": ">= 1.43.0 < 2"
- }
- },
- "compression": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.3.tgz",
- "integrity": "sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==",
- "dev": true,
- "requires": {
- "accepts": "~1.3.5",
- "bytes": "3.0.0",
- "compressible": "~2.0.14",
- "debug": "2.6.9",
- "on-headers": "~1.0.1",
- "safe-buffer": "5.1.2",
- "vary": "~1.1.2"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
- }
- },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3467,12 +2844,6 @@
"integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==",
"dev": true
},
- "content-disposition": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
- "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=",
- "dev": true
- },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -3485,20 +2856,14 @@
}
},
"debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
- "deep-extend": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
- "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
- "dev": true
- },
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -3523,21 +2888,52 @@
"esutils": "^2.0.2"
}
},
+ "dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "requires": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
+ }
+ }
+ },
+ "domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="
+ },
+ "domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "requires": {
+ "domelementtype": "^2.3.0"
+ }
+ },
+ "domutils": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz",
+ "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==",
+ "requires": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.1"
+ }
+ },
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
- "end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dev": true,
- "requires": {
- "once": "^1.4.0"
- }
- },
"enquirer": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
@@ -3586,6 +2982,12 @@
"unbox-primitive": "^1.0.1"
}
},
+ "es-html-parser": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/es-html-parser/-/es-html-parser-0.0.8.tgz",
+ "integrity": "sha512-kjMH23xhvTBw/7Ve1Dtb/7yZdFajfvwOpdsgRHmnyt8yvTsDJnkFjUgEEaMZFW+e1OhN/eoZrvF9wehq+waTGg==",
+ "dev": true
+ },
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -3604,13 +3006,14 @@
"dev": true
},
"eslint": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz",
- "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==",
+ "version": "7.32.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
+ "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
"dev": true,
"requires": {
"@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.4.2",
+ "@eslint/eslintrc": "^0.4.3",
+ "@humanwhocodes/config-array": "^0.5.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
@@ -3709,6 +3112,14 @@
}
}
},
+ "eslint-plugin-html": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz",
+ "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==",
+ "requires": {
+ "htmlparser2": "^8.0.1"
+ }
+ },
"eslint-plugin-import": {
"version": "2.23.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz",
@@ -3862,72 +3273,6 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
- "execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
- "dev": true,
- "requires": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- },
- "path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
- "dev": true
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
- "dev": true
- },
- "shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
- "dev": true,
- "requires": {
- "shebang-regex": "^1.0.0"
- }
- },
- "shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
- "dev": true
- },
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "requires": {
- "isexe": "^2.0.0"
- }
- }
- }
- },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -3946,23 +3291,6 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
- "fast-url-parser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
- "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
- "dev": true,
- "requires": {
- "punycode": "^1.3.2"
- },
- "dependencies": {
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
- "dev": true
- }
- }
- },
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -4026,15 +3354,6 @@
"has-symbols": "^1.0.1"
}
},
- "get-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
- "dev": true,
- "requires": {
- "pump": "^3.0.0"
- }
- },
"glob": {
"version": "7.1.7",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
@@ -4059,9 +3378,9 @@
}
},
"globals": {
- "version": "13.9.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz",
- "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==",
+ "version": "13.17.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+ "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@@ -4106,6 +3425,24 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
+ "htmlparser2": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz",
+ "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==",
+ "requires": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "entities": "^4.3.0"
+ },
+ "dependencies": {
+ "entities": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+ "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA=="
+ }
+ }
+ },
"ignore": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
@@ -4144,12 +3481,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
- "ini": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
- "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
- "dev": true
- },
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -4192,12 +3523,6 @@
"integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==",
"dev": true
},
- "is-docker": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
- "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
- "dev": true
- },
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -4241,12 +3566,6 @@
"has-symbols": "^1.0.2"
}
},
- "is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
- "dev": true
- },
"is-string": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
@@ -4262,15 +3581,6 @@
"has-symbols": "^1.0.2"
}
},
- "is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "dev": true,
- "requires": {
- "is-docker": "^2.0.0"
- }
- },
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -4480,25 +3790,10 @@
"integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
"dev": true
},
- "mime-db": {
- "version": "1.51.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
- "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.34",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
- "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
- "dev": true,
- "requires": {
- "mime-db": "1.51.0"
- }
- },
"minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
@@ -4528,18 +3823,6 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
- "negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
- "dev": true
- },
- "nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
- "dev": true
- },
"normalize-package-data": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -4560,23 +3843,6 @@
}
}
},
- "npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
- "dev": true,
- "requires": {
- "path-key": "^2.0.0"
- },
- "dependencies": {
- "path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
- "dev": true
- }
- }
- },
"object-inspect": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
@@ -4623,12 +3889,6 @@
"es-abstract": "^1.18.2"
}
},
- "on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
- "dev": true
- },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -4652,12 +3912,6 @@
"word-wrap": "^1.2.3"
}
},
- "p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
- "dev": true
- },
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
@@ -4713,12 +3967,6 @@
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
- "path-is-inside": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
- "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
- "dev": true
- },
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -4731,12 +3979,6 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
- "path-to-regexp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
- "integrity": "sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==",
- "dev": true
- },
"path-type": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
@@ -4782,48 +4024,12 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
- "pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "dev": true,
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"dev": true
},
- "range-parser": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
- "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
- "dev": true
- },
- "rc": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
- "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
- "dev": true,
- "requires": {
- "deep-extend": "^0.6.0",
- "ini": "~1.3.0",
- "minimist": "^1.2.0",
- "strip-json-comments": "~2.0.1"
- },
- "dependencies": {
- "strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
- "dev": true
- }
- }
- },
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -4851,25 +4057,6 @@
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
"dev": true
},
- "registry-auth-token": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz",
- "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==",
- "dev": true,
- "requires": {
- "rc": "^1.1.6",
- "safe-buffer": "^5.0.1"
- }
- },
- "registry-url": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
- "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
- "dev": true,
- "requires": {
- "rc": "^1.0.1"
- }
- },
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -4910,12 +4097,6 @@
"glob": "^7.1.3"
}
},
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
@@ -4925,75 +4106,6 @@
"lru-cache": "^6.0.0"
}
},
- "serve": {
- "version": "13.0.2",
- "resolved": "https://registry.npmjs.org/serve/-/serve-13.0.2.tgz",
- "integrity": "sha512-71R6fKvNgKrqARAag6lYJNnxDzpH7DCNrMuvPY5PLVaC2PDhJsGTj/34o4o4tPWhTuLgEXqvgnAWbATQ9zGZTQ==",
- "dev": true,
- "requires": {
- "@zeit/schemas": "2.6.0",
- "ajv": "6.12.6",
- "arg": "2.0.0",
- "boxen": "5.1.2",
- "chalk": "2.4.1",
- "clipboardy": "2.3.0",
- "compression": "1.7.3",
- "serve-handler": "6.1.3",
- "update-check": "1.5.2"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
- "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
- "dev": true
- }
- }
- },
- "serve-handler": {
- "version": "6.1.3",
- "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
- "integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
- "dev": true,
- "requires": {
- "bytes": "3.0.0",
- "content-disposition": "0.5.2",
- "fast-url-parser": "1.1.3",
- "mime-types": "2.1.18",
- "minimatch": "3.0.4",
- "path-is-inside": "1.0.2",
- "path-to-regexp": "2.2.1",
- "range-parser": "1.2.0"
- },
- "dependencies": {
- "mime-db": {
- "version": "1.33.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
- "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.18",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
- "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
- "dev": true,
- "requires": {
- "mime-db": "~1.33.0"
- }
- }
- }
- },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -5009,12 +4121,6 @@
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
- "signal-exit": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
- "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
- "dev": true
- },
"slice-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
@@ -5087,7 +4193,7 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"string-width": {
@@ -5136,12 +4242,6 @@
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
},
- "strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
- "dev": true
- },
"strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -5254,16 +4354,6 @@
"integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==",
"dev": true
},
- "update-check": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.2.tgz",
- "integrity": "sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==",
- "dev": true,
- "requires": {
- "registry-auth-token": "3.3.2",
- "registry-url": "3.1.0"
- }
- },
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -5289,12 +4379,6 @@
"spdx-expression-parse": "^3.0.0"
}
},
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
- "dev": true
- },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5317,58 +4401,12 @@
"is-symbol": "^1.0.3"
}
},
- "widest-line": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
- "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
- "dev": true,
- "requires": {
- "string-width": "^4.0.0"
- }
- },
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"dev": true
},
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- }
- }
- },
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
diff --git a/platform/web/package.json b/platform/web/package.json
index 0a8d9e4334..e1dd7b1a22 100644
--- a/platform/web/package.json
+++ b/platform/web/package.json
@@ -5,25 +5,30 @@
"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 js/engine/features.js --destination ''",
- "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools",
+ "lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools && npm run lint:html",
"lint:engine": "eslint \"js/engine/*.js\" --no-eslintrc -c .eslintrc.engine.js",
"lint:libs": "eslint \"js/libs/*.js\" --no-eslintrc -c .eslintrc.libs.js",
"lint:modules": "eslint \"../../modules/**/*.js\" --no-eslintrc -c .eslintrc.libs.js",
"lint:tools": "eslint \"js/jsdoc2rst/**/*.js\" --no-eslintrc -c .eslintrc.engine.js",
- "format": "npm run format:engine && npm run format:libs && npm run format:modules && npm run format:tools",
+ "lint:html": "eslint \"../../misc/dist/html/*.html\" --no-eslintrc -c .eslintrc.html.js",
+ "format": "npm run format:engine && npm run format:libs && npm run format:modules && npm run format:tools && npm run format:html",
"format:engine": "npm run lint:engine -- --fix",
"format:libs": "npm run lint:libs -- --fix",
"format:modules": "npm run lint:modules -- --fix",
"format:tools": "npm run lint:tools -- --fix",
- "serve": "serve"
+ "format:html": "npm run lint:html -- --fix"
},
"author": "Godot Engine contributors",
"license": "MIT",
"devDependencies": {
- "eslint": "^7.28.0",
+ "@html-eslint/eslint-plugin": "^0.15.0",
+ "@html-eslint/parser": "^0.15.0",
+ "eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.23.4",
- "jsdoc": "^3.6.7",
- "serve": "^13.0.2"
+ "jsdoc": "^3.6.7"
+ },
+ "dependencies": {
+ "eslint-plugin-html": "^7.1.0"
}
}
diff --git a/platform/web/serve.json b/platform/web/serve.json
deleted file mode 100644
index f2ef24751f..0000000000
--- a/platform/web/serve.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "public": "../../bin",
- "headers": [{
- "source": "**/*",
- "headers": [
- {
- "key": "Cross-Origin-Embedder-Policy",
- "value": "require-corp"
- }, {
- "key": "Cross-Origin-Opener-Policy",
- "value": "same-origin"
- }, {
- "key": "Access-Control-Allow-Origin",
- "value": "*"
- }, {
- "key": "Cache-Control",
- "value": "no-store, max-age=0"
- }
- ]
- }]
-}
diff --git a/platform/web/serve.py b/platform/web/serve.py
new file mode 100755
index 0000000000..6a3efcc463
--- /dev/null
+++ b/platform/web/serve.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+
+from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
+from pathlib import Path
+import os
+import sys
+import argparse
+import subprocess
+
+
+class CORSRequestHandler(SimpleHTTPRequestHandler):
+ def end_headers(self):
+ self.send_header("Cross-Origin-Opener-Policy", "same-origin")
+ self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
+ self.send_header("Access-Control-Allow-Origin", "*")
+ super().end_headers()
+
+
+def shell_open(url):
+ if sys.platform == "win32":
+ os.startfile(url)
+ else:
+ opener = "open" if sys.platform == "darwin" else "xdg-open"
+ subprocess.call([opener, url])
+
+
+def serve(root, port, run_browser):
+ os.chdir(root)
+
+ if run_browser:
+ # Open the served page in the user's default browser.
+ print("Opening the served URL in the default browser (use `--no-browser` or `-n` to disable this).")
+ shell_open(f"http://127.0.0.1:{port}")
+
+ test(CORSRequestHandler, HTTPServer, port=port)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-p", "--port", help="port to listen on", default=8060, type=int)
+ parser.add_argument(
+ "-r", "--root", help="path to serve as root (relative to `platform/web/`)", default="../../bin", type=Path
+ )
+ browser_parser = parser.add_mutually_exclusive_group(required=False)
+ browser_parser.add_argument(
+ "-n", "--no-browser", help="don't open default web browser automatically", dest="browser", action="store_false"
+ )
+ parser.set_defaults(browser=True)
+ args = parser.parse_args()
+
+ # Change to the directory where the script is located,
+ # so that the script can be run from any location.
+ os.chdir(Path(__file__).resolve().parent)
+
+ serve(args.root, args.port, args.browser)
diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp
index 287fe48c4d..a76b98f4e9 100644
--- a/platform/web/web_main.cpp
+++ b/platform/web/web_main.cpp
@@ -77,14 +77,14 @@ void main_loop_callback() {
return; // Skip frame.
}
- int target_fps = Engine::get_singleton()->get_target_fps();
- if (target_fps > 0) {
+ int max_fps = Engine::get_singleton()->get_max_fps();
+ if (max_fps > 0) {
if (current_ticks - target_ticks > 1000000) {
// When the window loses focus, we stop getting updates and accumulate delay.
// For this reason, if the difference is too big, we reset target ticks to the current ticks.
target_ticks = current_ticks;
}
- target_ticks += (uint64_t)(1000000 / target_fps);
+ target_ticks += (uint64_t)(1000000 / max_fps);
}
if (os->main_loop_iterate()) {
emscripten_cancel_main_loop(); // Cancel current loop and wait for cleanup_after_sync.
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index a5d8d0344b..705e83dace 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -401,6 +401,7 @@ def configure_msvc(env, vcvars_msvc_config):
"Avrt",
"dwmapi",
"dwrite",
+ "wbemuuid",
]
if env["vulkan"]:
@@ -577,15 +578,18 @@ def configure_mingw(env):
"uuid",
"dwmapi",
"dwrite",
+ "wbemuuid",
]
)
- env.Append(CPPDEFINES=["VULKAN_ENABLED"])
- if not env["use_volk"]:
- env.Append(LIBS=["vulkan"])
+ if env["vulkan"]:
+ env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["use_volk"]:
+ env.Append(LIBS=["vulkan"])
- env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LIBS=["opengl32"])
+ if env["opengl3"]:
+ env.Append(CPPDEFINES=["GLES3_ENABLED"])
+ env.Append(LIBS=["opengl32"])
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 77b20dd924..9d0a2578fb 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -561,20 +561,6 @@ float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
return data.rate;
}
-bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const {
-#ifndef _MSC_VER
-#warning touchscreen not working
-#endif
- return false;
-}
-
-void DisplayServerWindows::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) {
-}
-
-DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(int p_screen) const {
- return SCREEN_LANDSCAPE;
-}
-
void DisplayServerWindows::screen_set_keep_on(bool p_enable) {
if (keep_screen_on == p_enable) {
return;
@@ -1361,7 +1347,8 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
if (p_enabled) {
//enable per-pixel alpha
- DWM_BLURBEHIND bb = { 0 };
+ DWM_BLURBEHIND bb;
+ ZeroMemory(&bb, sizeof(bb));
HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = hRgn;
@@ -1373,7 +1360,8 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
//disable per-pixel alpha
wd.layered_window = false;
- DWM_BLURBEHIND bb = { 0 };
+ DWM_BLURBEHIND bb;
+ ZeroMemory(&bb, sizeof(bb));
HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = hRgn;
@@ -1390,7 +1378,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
wd.is_popup = p_enabled;
} break;
- case WINDOW_FLAG_MAX:
+ default:
break;
}
}
@@ -1419,7 +1407,7 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
- case WINDOW_FLAG_MAX:
+ default:
break;
}
@@ -2456,10 +2444,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0; // Jump back.
}
case WM_MOUSELEAVE: {
- old_invalid = true;
- windows[window_id].mouse_outside = true;
+ if (window_mouseover_id == window_id) {
+ old_invalid = true;
+ window_mouseover_id = INVALID_WINDOW_ID;
- _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
} break;
case WM_INPUT: {
@@ -2690,17 +2680,21 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (windows[window_id].mouse_outside) {
+ if (window_mouseover_id != window_id) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
+ if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // Leave previous window.
+ _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
}
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- windows[window_id].mouse_outside = false;
+ window_mouseover_id = window_id;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2791,17 +2785,29 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- if (windows[window_id].mouse_outside) {
+ DisplayServer::WindowID over_id = get_window_at_screen_position(mouse_get_position());
+ if (!Rect2(window_get_position(over_id), Point2(windows[over_id].width, windows[over_id].height)).has_point(mouse_get_position())) {
+ // Don't consider the windowborder as part of the window.
+ over_id = INVALID_WINDOW_ID;
+ }
+ if (window_mouseover_id != over_id) {
// Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
- _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
+ if (window_mouseover_id != INVALID_WINDOW_ID) {
+ // Leave previous window.
+ _send_window_event(windows[window_mouseover_id], WINDOW_EVENT_MOUSE_EXIT);
+ }
+
+ if (over_id != INVALID_WINDOW_ID) {
+ _send_window_event(windows[over_id], WINDOW_EVENT_MOUSE_ENTER);
+ }
}
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
cursor_set_shape(c);
- windows[window_id].mouse_outside = false;
+ window_mouseover_id = over_id;
// Once-off notification, must call again.
track_mouse_leave_event(hWnd);
@@ -2812,9 +2818,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
+ DisplayServer::WindowID receiving_window_id = _get_focused_window_or_popup();
+ if (receiving_window_id == INVALID_WINDOW_ID) {
+ receiving_window_id = window_id;
+ }
Ref<InputEventMouseMotion> mm;
mm.instantiate();
- mm->set_window_id(window_id);
+ mm->set_window_id(receiving_window_id);
mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0);
mm->set_shift_pressed((wParam & MK_SHIFT) != 0);
mm->set_alt_pressed(alt_mem);
@@ -2871,9 +2881,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
old_x = mm->get_position().x;
old_y = mm->get_position().y;
- if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) {
- Input::get_singleton()->parse_input_event(mm);
+
+ if (!windows[receiving_window_id].window_has_focus) {
+ // In case of unfocused Popups, adjust event position.
+ Point2i pos = mm->get_position() - window_get_position(receiving_window_id) + window_get_position(window_id);
+ mm->set_position(pos);
+ mm->set_global_position(pos);
}
+ Input::get_singleton()->parse_input_event(mm);
} break;
case WM_LBUTTONDOWN:
@@ -3099,7 +3114,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
rect_changed = true;
}
#if defined(VULKAN_ENABLED)
- if (context_vulkan && window_created) {
+ if (context_vulkan && window.context_created) {
// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
context_vulkan->window_resize(window_id, window.width, window.height);
}
@@ -3553,21 +3568,19 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
#ifdef VULKAN_ENABLED
if (context_vulkan) {
- if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
+ if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
memdelete(context_vulkan);
context_vulkan = nullptr;
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Vulkan Window.");
}
+ wd.context_created = true;
}
#endif
#ifdef GLES3_ENABLED
if (gl_manager) {
- Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
-
- // shut down OpenGL, to mirror behavior of Vulkan code
- if (err != OK) {
+ if (gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
memdelete(gl_manager);
gl_manager = nullptr;
windows.erase(id);
@@ -3718,7 +3731,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) {
}
}
-DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
drop_events = false;
key_event_pos = 0;
@@ -3870,6 +3883,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
+ if (p_position != nullptr) {
+ window_position = *p_position;
+ }
+
WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
@@ -3933,12 +3950,24 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
return drivers;
}
-DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
- DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
+ DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n"
- "Please update your drivers or if you have a very old or integrated GPU upgrade it.",
- "Unable to initialize Video driver");
+ if (p_rendering_driver == "vulkan") {
+ String executable_name = OS::get_singleton()->get_executable_path().get_file();
+ OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
+ "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'./" +
+ executable_name + " --rendering-driver opengl3'.\n "
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ } else {
+ OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
+ "Please try updating your GPU driver.\n"
+ "If you have updated your graphics drivers recently, try rebooting.",
+ "Unable to initialize Video driver");
+ }
}
return ds;
}
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index d85d6364bd..8ac0086d69 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -61,9 +61,9 @@
#include "gl_manager_windows.h"
#endif
-#include <fcntl.h>
#include <io.h>
#include <stdio.h>
+
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
@@ -323,6 +323,8 @@ class DisplayServerWindows : public DisplayServer {
LPARAM lParam;
};
+ WindowID window_mouseover_id = INVALID_WINDOW_ID;
+
KeyEvent key_event_buffer[KEY_EVENT_BUFFER_SIZE];
int key_event_pos;
@@ -369,6 +371,7 @@ class DisplayServerWindows : public DisplayServer {
bool no_focus = false;
bool window_has_focus = false;
bool exclusive = false;
+ bool context_created = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
@@ -397,7 +400,6 @@ class DisplayServerWindows : public DisplayServer {
Size2 window_rect;
Point2 last_pos;
- bool mouse_outside = true;
ObjectID instance_id;
@@ -516,10 +518,6 @@ public:
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
-
- virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override;
- virtual ScreenOrientation screen_get_orientation(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual void screen_set_keep_on(bool p_enable) override; //disable screensaver
virtual bool screen_is_kept_on() const override;
@@ -626,11 +624,11 @@ public:
virtual void set_context(Context p_context) override;
- static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
static Vector<String> get_rendering_drivers_func();
static void register_windows_driver();
- DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
~DisplayServerWindows();
};
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 016d201f2c..f7b8e84618 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -82,8 +82,8 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
String app_name;
- if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
- app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ if (String(GLOBAL_GET("application/config/name")) != "") {
+ app_name = String(GLOBAL_GET("application/config/name"));
} else {
app_name = "Unnamed";
}
@@ -147,7 +147,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
}
Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (rcedit_path != String() && !FileAccess::exists(rcedit_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find rcedit executable at \"%s\"."), rcedit_path));
@@ -160,7 +160,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
#ifndef WINDOWS_ENABLED
// On non-Windows we need WINE to run rcedit
- String wine_path = EditorSettings::get_singleton()->get("export/windows/wine");
+ String wine_path = EDITOR_GET("export/windows/wine");
if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("Could not find wine executable at \"%s\"."), wine_path));
@@ -248,7 +248,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
List<String> args;
#ifdef WINDOWS_ENABLED
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool");
+ String signtool_path = EDITOR_GET("export/windows/signtool");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find signtool executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -257,7 +257,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
signtool_path = "signtool"; // try to run signtool from PATH
}
#else
- String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode");
+ String signtool_path = EDITOR_GET("export/windows/osslsigncode");
if (!signtool_path.is_empty() && !FileAccess::exists(signtool_path)) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Could not find osslsigncode executable at \"%s\"."), signtool_path));
return ERR_FILE_NOT_FOUND;
@@ -420,7 +420,7 @@ bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<Edito
String err = "";
bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates);
- String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
+ String rcedit_path = EDITOR_GET("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
}
diff --git a/platform/windows/joypad_windows.h b/platform/windows/joypad_windows.h
index d239471a5c..56a9f3e9c9 100644
--- a/platform/windows/joypad_windows.h
+++ b/platform/windows/joypad_windows.h
@@ -85,6 +85,8 @@ private:
last_pad = -1;
attached = false;
confirmed = false;
+ di_joy = nullptr;
+ guid = {};
for (int i = 0; i < MAX_JOY_BUTTONS; i++) {
last_buttons[i] = false;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 1978ec5ab6..36fd86c4f5 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -53,6 +53,7 @@
#include <process.h>
#include <regstr.h>
#include <shlobj.h>
+#include <wbemcli.h>
extern "C" {
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
@@ -295,11 +296,12 @@ String OS_Windows::get_distribution_name() const {
}
String OS_Windows::get_version() const {
- typedef LONG NTSTATUS, *PNTSTATUS;
+ typedef LONG NTSTATUS;
typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
if (version_ptr != nullptr) {
- RTL_OSVERSIONINFOW fow = { 0 };
+ RTL_OSVERSIONINFOW fow;
+ ZeroMemory(&fow, sizeof(fow));
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);
@@ -308,6 +310,103 @@ String OS_Windows::get_version() const {
return "";
}
+Vector<String> OS_Windows::get_video_adapter_driver_info() const {
+ if (RenderingServer::get_singleton()->get_rendering_device() == nullptr) {
+ return Vector<String>();
+ }
+
+ REFCLSID clsid = CLSID_WbemLocator; // Unmarshaler CLSID
+ REFIID uuid = IID_IWbemLocator; // Interface UUID
+ IWbemLocator *wbemLocator = NULL; // to get the services
+ IWbemServices *wbemServices = NULL; // to get the class
+ IEnumWbemClassObject *iter = NULL;
+ IWbemClassObject *pnpSDriverObject[1]; // contains driver name, version, etc.
+ static String driver_name;
+ static String driver_version;
+
+ const String device_name = RenderingServer::get_singleton()->get_rendering_device()->get_device_name();
+ if (device_name.is_empty()) {
+ return Vector<String>();
+ }
+
+ CoInitialize(nullptr);
+
+ HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator);
+ if (hr != S_OK) {
+ return Vector<String>();
+ }
+ BSTR resource_name = SysAllocString(L"root\\CIMV2");
+ hr = wbemLocator->ConnectServer(resource_name, NULL, NULL, NULL, 0, NULL, NULL, &wbemServices);
+ SysFreeString(resource_name);
+
+ SAFE_RELEASE(wbemLocator) // from now on, use `wbemServices`
+ if (hr != S_OK) {
+ SAFE_RELEASE(wbemServices)
+ return Vector<String>();
+ }
+
+ const String gpu_device_class_query = vformat("SELECT * FROM Win32_PnPSignedDriver WHERE DeviceName = \"%s\"", device_name);
+ BSTR query = SysAllocString((const WCHAR *)gpu_device_class_query.utf16().get_data());
+ BSTR query_lang = SysAllocString(L"WQL");
+ hr = wbemServices->ExecQuery(query_lang, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &iter);
+ SysFreeString(query_lang);
+ SysFreeString(query);
+ if (hr == S_OK) {
+ ULONG resultCount;
+ hr = iter->Next(5000, 1, pnpSDriverObject, &resultCount); // Get exactly 1. Wait max 5 seconds.
+
+ if (hr == S_OK && resultCount > 0) {
+ VARIANT dn;
+ VariantInit(&dn);
+
+ BSTR object_name = SysAllocString(L"DriverName");
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ SysFreeString(object_name);
+ if (hr == S_OK) {
+ String d_name = String(V_BSTR(&dn));
+ if (d_name.is_empty()) {
+ object_name = SysAllocString(L"DriverProviderName");
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ SysFreeString(object_name);
+ if (hr == S_OK) {
+ driver_name = String(V_BSTR(&dn));
+ }
+ } else {
+ driver_name = d_name;
+ }
+ } else {
+ object_name = SysAllocString(L"DriverProviderName");
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dn, NULL, NULL);
+ SysFreeString(object_name);
+ if (hr == S_OK) {
+ driver_name = String(V_BSTR(&dn));
+ }
+ }
+
+ VARIANT dv;
+ VariantInit(&dv);
+ object_name = SysAllocString(L"DriverVersion");
+ hr = pnpSDriverObject[0]->Get(object_name, 0, &dv, NULL, NULL);
+ SysFreeString(object_name);
+ if (hr == S_OK) {
+ driver_version = String(V_BSTR(&dv));
+ }
+ for (ULONG i = 0; i < resultCount; i++) {
+ SAFE_RELEASE(pnpSDriverObject[i])
+ }
+ }
+ }
+
+ SAFE_RELEASE(wbemServices)
+ SAFE_RELEASE(iter)
+
+ Vector<String> info;
+ info.push_back(driver_name);
+ info.push_back(driver_version);
+
+ return info;
+}
+
OS::DateTime OS_Windows::get_datetime(bool p_utc) const {
SYSTEMTIME systemtime;
if (p_utc) {
@@ -870,17 +969,6 @@ BOOL is_wow64() {
return wow64;
}
-int OS_Windows::get_processor_count() const {
- SYSTEM_INFO sysinfo;
- if (is_wow64()) {
- GetNativeSystemInfo(&sysinfo);
- } else {
- GetSystemInfo(&sysinfo);
- }
-
- return sysinfo.dwNumberOfProcessors;
-}
-
String OS_Windows::get_processor_name() const {
const String id = "Hardware\\Description\\System\\CentralProcessor\\0";
@@ -1069,11 +1157,11 @@ String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
}
String OS_Windows::get_user_data_dir() const {
- String appname = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/name"));
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
if (!appname.is_empty()) {
- bool use_custom_dir = ProjectSettings::get_singleton()->get("application/config/use_custom_user_dir");
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
if (use_custom_dir) {
- String custom_dir = get_safe_dir_name(ProjectSettings::get_singleton()->get("application/config/custom_user_dir_name"), true);
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
if (custom_dir.is_empty()) {
custom_dir = appname;
}
@@ -1093,7 +1181,14 @@ String OS_Windows::get_unique_id() const {
}
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "pc";
+ if (p_feature == "system_fonts") {
+ return true;
+ }
+ if (p_feature == "pc") {
+ return true;
+ }
+
+ return false;
}
void OS_Windows::disable_crash_handler() {
@@ -1133,15 +1228,7 @@ Error OS_Windows::move_to_trash(const String &p_path) {
}
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
- ticks_per_second = 0;
- ticks_start = 0;
- main_loop = nullptr;
- process_map = nullptr;
-
hInstance = _hInstance;
-#ifdef STDOUT_FILE
- stdo = fopen("stdout.txt", "wb");
-#endif
#ifdef WASAPI_ENABLED
AudioDriverManager::add_driver(&driver_wasapi);
@@ -1157,11 +1244,8 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
//
// NOTE: The engine does not use ANSI escape codes to color error/warning messages; it uses Windows API calls instead.
// Therefore, error/warning messages are still colored on Windows versions older than 10.
- HANDLE stdoutHandle;
- stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
- DWORD outMode = 0;
- outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
-
+ HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ DWORD outMode = ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(stdoutHandle, outMode)) {
// Windows 8.1 or below, or Windows 10 prior to Anniversary Update.
print_verbose("Can't set the ENABLE_VIRTUAL_TERMINAL_PROCESSING Windows console mode. `print_rich()` will not work as expected.");
@@ -1173,7 +1257,4 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
}
OS_Windows::~OS_Windows() {
-#ifdef STDOUT_FILE
- fclose(stdo);
-#endif
}
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 491de2266f..bf934bce64 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -40,6 +40,7 @@
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "key_mapping_windows.h"
#include "servers/audio_server.h"
+
#ifdef XAUDIO2_ENABLED
#include "drivers/xaudio2/audio_driver_xaudio2.h"
#endif
@@ -49,10 +50,10 @@
#include "platform/windows/vulkan_context_win.h"
#endif
-#include <fcntl.h>
#include <io.h>
#include <shellapi.h>
#include <stdio.h>
+
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
@@ -83,13 +84,10 @@ public:
};
class JoypadWindows;
-class OS_Windows : public OS {
-#ifdef STDOUT_FILE
- FILE *stdo = nullptr;
-#endif
- uint64_t ticks_start;
- uint64_t ticks_per_second;
+class OS_Windows : public OS {
+ uint64_t ticks_start = 0;
+ uint64_t ticks_per_second = 0;
HINSTANCE hInstance;
MainLoop *main_loop = nullptr;
@@ -129,7 +127,7 @@ protected:
STARTUPINFO si;
PROCESS_INFORMATION pi;
};
- HashMap<ProcessID, ProcessInfo> *process_map;
+ HashMap<ProcessID, ProcessInfo> *process_map = nullptr;
public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
@@ -146,6 +144,8 @@ public:
virtual String get_distribution_name() const override;
virtual String get_version() const override;
+ virtual Vector<String> get_video_adapter_driver_info() const override;
+
virtual void initialize_joypads() override {}
virtual DateTime get_datetime(bool p_utc) const override;
@@ -174,7 +174,6 @@ public:
virtual String get_locale() const override;
- virtual int get_processor_count() const override;
virtual String get_processor_name() const override;
virtual uint64_t get_embedded_pck_offset() const override;
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp
index e62c6c1dc8..ff9318e47e 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/platform/windows/vulkan_context_win.cpp
@@ -41,7 +41,7 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const {
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
}
-int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
+Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) {
VkWin32SurfaceCreateInfoKHR createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = nullptr;
@@ -50,7 +50,7 @@ int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, Dis
createInfo.hwnd = p_window;
VkSurfaceKHR surface;
VkResult err = vkCreateWin32SurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, -1);
+ ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
}
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h
index d5950a129a..9dedcabb2b 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/vulkan_context_win.h
@@ -31,6 +31,8 @@
#ifndef VULKAN_CONTEXT_WIN_H
#define VULKAN_CONTEXT_WIN_H
+#ifdef VULKAN_ENABLED
+
#include "drivers/vulkan/vulkan_context.h"
#define WIN32_LEAN_AND_MEAN
@@ -40,10 +42,12 @@ class VulkanContextWindows : public VulkanContext {
virtual const char *_get_platform_surface_extension() const;
public:
- int window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
+ Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height);
VulkanContextWindows();
~VulkanContextWindows();
};
+#endif // VULKAN_ENABLED
+
#endif // VULKAN_CONTEXT_WIN_H
diff --git a/scene/2d/audio_listener_2d.cpp b/scene/2d/audio_listener_2d.cpp
index f7dd20d7c0..3cc64b2170 100644
--- a/scene/2d/audio_listener_2d.cpp
+++ b/scene/2d/audio_listener_2d.cpp
@@ -103,7 +103,6 @@ bool AudioListener2D::is_current() const {
} else {
return current;
}
- return false;
}
void AudioListener2D::_bind_methods() {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 85ec745aee..9ac3083718 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -477,7 +477,7 @@ void AudioStreamPlayer2D::_bind_methods() {
AudioStreamPlayer2D::AudioStreamPlayer2D() {
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed));
- cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/2d_panning_strength");
+ cached_global_panning_strength = GLOBAL_GET("audio/general/2d_panning_strength");
}
AudioStreamPlayer2D::~AudioStreamPlayer2D() {
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index e120aa871b..4b31bbddac 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -155,11 +155,11 @@ Transform2D Camera2D::get_camera_transform() {
}
}
- if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
- real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
+ if (follow_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
+ real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
- //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
+ //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed;
} else {
ret_camera_pos = smoothed_camera_pos = camera_pos;
}
@@ -171,14 +171,19 @@ 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 (!ignore_rotation) {
- screen_offset = screen_offset.rotated(angle);
+ if (rotation_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
+ real_t step = rotation_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time());
+ camera_angle = Math::lerp_angle(camera_angle, get_global_rotation(), step);
+ } else {
+ camera_angle = get_global_rotation();
+ }
+ screen_offset = screen_offset.rotated(camera_angle);
}
Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom_scale);
- if (!smoothing_enabled || !limit_smoothing_enabled) {
+ if (!follow_smoothing_enabled || !limit_smoothing_enabled) {
if (screen_rect.position.x < limit[SIDE_LEFT]) {
screen_rect.position.x = limit[SIDE_LEFT];
}
@@ -205,7 +210,7 @@ Transform2D Camera2D::get_camera_transform() {
Transform2D xform;
xform.scale_basis(zoom_scale);
if (!ignore_rotation) {
- xform.set_rotation(angle);
+ xform.set_rotation(camera_angle);
}
xform.set_origin(screen_rect.position);
@@ -366,6 +371,12 @@ Camera2D::AnchorMode Camera2D::get_anchor_mode() const {
void Camera2D::set_ignore_rotation(bool p_ignore) {
ignore_rotation = p_ignore;
Point2 old_smoothed_camera_pos = smoothed_camera_pos;
+
+ // Reset back to zero so it matches the camera rotation when ignore_rotation is enabled.
+ if (ignore_rotation) {
+ camera_angle = 0.0;
+ }
+
_update_scroll();
smoothed_camera_pos = old_smoothed_camera_pos;
}
@@ -415,6 +426,14 @@ void Camera2D::set_current(bool p_current) {
}
}
+void Camera2D::_update_process_internal_for_smoothing() {
+ bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
+ bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
+
+ bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor;
+ set_process_internal(enabled);
+}
+
bool Camera2D::is_current() const {
return current;
}
@@ -506,17 +525,31 @@ void Camera2D::align() {
_update_scroll();
}
-void Camera2D::set_follow_smoothing(real_t p_speed) {
- smoothing = p_speed;
- if (smoothing > 0 && !(is_inside_tree() && Engine::get_singleton()->is_editor_hint())) {
- set_process_internal(true);
- } else {
- set_process_internal(false);
- }
+void Camera2D::set_position_smoothing_speed(real_t p_speed) {
+ position_smoothing_speed = p_speed;
+ _update_process_internal_for_smoothing();
+}
+
+real_t Camera2D::get_position_smoothing_speed() const {
+ return position_smoothing_speed;
+}
+
+void Camera2D::set_rotation_smoothing_speed(real_t p_speed) {
+ rotation_smoothing_speed = p_speed;
+ _update_process_internal_for_smoothing();
}
-real_t Camera2D::get_follow_smoothing() const {
- return smoothing;
+real_t Camera2D::get_rotation_smoothing_speed() const {
+ return rotation_smoothing_speed;
+}
+
+void Camera2D::set_rotation_smoothing_enabled(bool p_enabled) {
+ rotation_smoothing_enabled = p_enabled;
+ notify_property_list_changed();
+}
+
+bool Camera2D::is_rotation_smoothing_enabled() const {
+ return rotation_smoothing_enabled;
}
Point2 Camera2D::get_camera_screen_center() const {
@@ -526,7 +559,7 @@ Point2 Camera2D::get_camera_screen_center() const {
Size2 Camera2D::_get_camera_screen_size() const {
// special case if the camera2D is in the root viewport
if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
- return Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
}
return get_viewport_rect().size;
}
@@ -574,18 +607,18 @@ real_t Camera2D::get_drag_horizontal_offset() const {
void Camera2D::_set_old_smoothing(real_t p_enable) {
//compatibility
if (p_enable > 0) {
- smoothing_enabled = true;
- set_follow_smoothing(p_enable);
+ follow_smoothing_enabled = true;
+ set_position_smoothing_speed(p_enable);
}
}
-void Camera2D::set_enable_follow_smoothing(bool p_enabled) {
- smoothing_enabled = p_enabled;
+void Camera2D::set_position_smoothing_enabled(bool p_enabled) {
+ follow_smoothing_enabled = p_enabled;
notify_property_list_changed();
}
-bool Camera2D::is_follow_smoothing_enabled() const {
- return smoothing_enabled;
+bool Camera2D::is_position_smoothing_enabled() const {
+ return follow_smoothing_enabled;
}
void Camera2D::set_custom_viewport(Node *p_viewport) {
@@ -656,7 +689,10 @@ bool Camera2D::is_margin_drawing_enabled() const {
}
void Camera2D::_validate_property(PropertyInfo &p_property) const {
- if (!smoothing_enabled && p_property.name == "smoothing_speed") {
+ if (!follow_smoothing_enabled && p_property.name == "smoothing_speed") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ if (!rotation_smoothing_enabled && p_property.name == "rotation_smoothing_speed") {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -710,11 +746,17 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &Camera2D::set_custom_viewport);
ClassDB::bind_method(D_METHOD("get_custom_viewport"), &Camera2D::get_custom_viewport);
- ClassDB::bind_method(D_METHOD("set_follow_smoothing", "follow_smoothing"), &Camera2D::set_follow_smoothing);
- ClassDB::bind_method(D_METHOD("get_follow_smoothing"), &Camera2D::get_follow_smoothing);
+ ClassDB::bind_method(D_METHOD("set_position_smoothing_speed", "position_smoothing_speed"), &Camera2D::set_position_smoothing_speed);
+ ClassDB::bind_method(D_METHOD("get_position_smoothing_speed"), &Camera2D::get_position_smoothing_speed);
- ClassDB::bind_method(D_METHOD("set_enable_follow_smoothing", "follow_smoothing"), &Camera2D::set_enable_follow_smoothing);
- ClassDB::bind_method(D_METHOD("is_follow_smoothing_enabled"), &Camera2D::is_follow_smoothing_enabled);
+ ClassDB::bind_method(D_METHOD("set_position_smoothing_enabled", "position_smoothing_speed"), &Camera2D::set_position_smoothing_enabled);
+ ClassDB::bind_method(D_METHOD("is_position_smoothing_enabled"), &Camera2D::is_position_smoothing_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_rotation_smoothing_enabled", "enabled"), &Camera2D::set_rotation_smoothing_enabled);
+ ClassDB::bind_method(D_METHOD("is_rotation_smoothing_enabled"), &Camera2D::is_rotation_smoothing_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_rotation_smoothing_speed", "speed"), &Camera2D::set_rotation_smoothing_speed);
+ ClassDB::bind_method(D_METHOD("get_rotation_smoothing_speed"), &Camera2D::get_rotation_smoothing_speed);
ClassDB::bind_method(D_METHOD("force_update_scroll"), &Camera2D::force_update_scroll);
ClassDB::bind_method(D_METHOD("reset_smoothing"), &Camera2D::reset_smoothing);
@@ -746,9 +788,13 @@ void Camera2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_BOTTOM);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_smoothed"), "set_limit_smoothing_enabled", "is_limit_smoothing_enabled");
- ADD_GROUP("Smoothing", "smoothing_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_follow_smoothing", "get_follow_smoothing");
+ ADD_GROUP("Follow Smoothing", "follow_smoothing_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "position_smoothing_enabled"), "set_position_smoothing_enabled", "is_position_smoothing_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "position_smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_position_smoothing_speed", "get_position_smoothing_speed");
+
+ ADD_GROUP("Rotation Smoothing", "rotation_smoothing_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotation_smoothing_enabled"), "set_rotation_smoothing_enabled", "is_rotation_smoothing_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_smoothing_speed"), "set_rotation_smoothing_speed", "get_rotation_smoothing_speed");
ADD_GROUP("Drag", "drag_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_horizontal_enabled"), "set_drag_horizontal_enabled", "is_drag_horizontal_enabled");
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 1ce622388c..ae172f47b1 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -65,8 +65,13 @@ protected:
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool ignore_rotation = true;
bool current = false;
- real_t smoothing = 5.0;
- bool smoothing_enabled = false;
+ real_t position_smoothing_speed = 5.0;
+ bool follow_smoothing_enabled = false;
+
+ real_t camera_angle = 0.0;
+ real_t rotation_smoothing_speed = 5.0;
+ bool rotation_smoothing_enabled = false;
+
int limit[4];
bool limit_smoothing_enabled = false;
@@ -87,6 +92,8 @@ protected:
void _set_old_smoothing(real_t p_enable);
+ void _update_process_internal_for_smoothing();
+
bool screen_drawing_enabled = true;
bool limit_drawing_enabled = false;
bool margin_drawing_enabled = false;
@@ -133,11 +140,17 @@ public:
void set_drag_vertical_offset(real_t p_offset);
real_t get_drag_vertical_offset() const;
- void set_enable_follow_smoothing(bool p_enabled);
- bool is_follow_smoothing_enabled() const;
+ void set_position_smoothing_enabled(bool p_enabled);
+ bool is_position_smoothing_enabled() const;
+
+ void set_position_smoothing_speed(real_t p_speed);
+ real_t get_position_smoothing_speed() const;
+
+ void set_rotation_smoothing_speed(real_t p_speed);
+ real_t get_rotation_smoothing_speed() const;
- void set_follow_smoothing(real_t p_speed);
- real_t get_follow_smoothing() const;
+ void set_rotation_smoothing_enabled(bool p_enabled);
+ bool is_rotation_smoothing_enabled() const;
void set_process_callback(Camera2DProcessCallback p_mode);
Camera2DProcessCallback get_process_callback() const;
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 23948c2fd3..df75d34e0f 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -36,12 +36,12 @@
void CollisionObject2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- Transform2D global_transform = get_global_transform();
+ Transform2D gl_transform = get_global_transform();
if (area) {
- PhysicsServer2D::get_singleton()->area_set_transform(rid, global_transform);
+ PhysicsServer2D::get_singleton()->area_set_transform(rid, gl_transform);
} else {
- PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, gl_transform);
}
bool disabled = !is_enabled();
@@ -81,12 +81,12 @@ void CollisionObject2D::_notification(int p_what) {
return;
}
- Transform2D global_transform = get_global_transform();
+ Transform2D gl_transform = get_global_transform();
if (area) {
- PhysicsServer2D::get_singleton()->area_set_transform(rid, global_transform);
+ PhysicsServer2D::get_singleton()->area_set_transform(rid, gl_transform);
} else {
- PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform);
+ PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, gl_transform);
}
} break;
@@ -153,13 +153,13 @@ uint32_t CollisionObject2D::get_collision_mask() const {
void CollisionObject2D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t collision_layer = get_collision_layer();
+ uint32_t collision_layer_new = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << (p_layer_number - 1);
+ collision_layer_new |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << (p_layer_number - 1));
+ collision_layer_new &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(collision_layer);
+ set_collision_layer(collision_layer_new);
}
bool CollisionObject2D::get_collision_layer_value(int p_layer_number) const {
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 7e167a3807..5fe05c4ddd 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -49,6 +49,11 @@ void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) {
parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin);
}
+Color CollisionShape2D::_get_default_debug_color() const {
+ SceneTree *st = SceneTree::get_singleton();
+ return st ? st->get_debug_collisions_color() : Color();
+}
+
void CollisionShape2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PARENTED: {
@@ -95,7 +100,7 @@ void CollisionShape2D::_notification(int p_what) {
rect = Rect2();
- Color draw_col = get_tree()->get_debug_collisions_color();
+ Color draw_col = debug_color;
if (disabled) {
float g = draw_col.get_v();
draw_col.r = g;
@@ -110,7 +115,7 @@ void CollisionShape2D::_notification(int p_what) {
if (one_way_collision) {
// Draw an arrow indicating the one-way collision direction
- draw_col = get_tree()->get_debug_collisions_color().inverted();
+ draw_col = debug_color.inverted();
if (disabled) {
draw_col = draw_col.darkened(0.25);
}
@@ -226,6 +231,40 @@ real_t CollisionShape2D::get_one_way_collision_margin() const {
return one_way_collision_margin;
}
+void CollisionShape2D::set_debug_color(const Color &p_color) {
+ debug_color = p_color;
+ queue_redraw();
+}
+
+Color CollisionShape2D::get_debug_color() const {
+ return debug_color;
+}
+
+bool CollisionShape2D::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "debug_color") {
+ return true;
+ }
+ return false;
+}
+
+bool CollisionShape2D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "debug_color") {
+ r_property = _get_default_debug_color();
+ return true;
+ }
+ return false;
+}
+
+void CollisionShape2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "debug_color") {
+ if (debug_color == _get_default_debug_color()) {
+ p_property.usage = PROPERTY_USAGE_DEFAULT & ~PROPERTY_USAGE_STORAGE;
+ } else {
+ p_property.usage = PROPERTY_USAGE_DEFAULT;
+ }
+ }
+}
+
void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape2D::get_shape);
@@ -235,13 +274,19 @@ void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("set_one_way_collision_margin", "margin"), &CollisionShape2D::set_one_way_collision_margin);
ClassDB::bind_method(D_METHOD("get_one_way_collision_margin"), &CollisionShape2D::get_one_way_collision_margin);
+ ClassDB::bind_method(D_METHOD("set_debug_color", "color"), &CollisionShape2D::set_debug_color);
+ ClassDB::bind_method(D_METHOD("get_debug_color"), &CollisionShape2D::get_debug_color);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "one_way_collision_margin", PROPERTY_HINT_RANGE, "0,128,0.1,suffix:px"), "set_one_way_collision_margin", "get_one_way_collision_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_color"), "set_debug_color", "get_debug_color");
+ // Default value depends on a project setting, override for doc generation purposes.
+ ADD_PROPERTY_DEFAULT("debug_color", Color());
}
CollisionShape2D::CollisionShape2D() {
set_notify_local_transform(true);
+ debug_color = _get_default_debug_color();
}
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 5e50420e00..b0b8a7cb0f 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -42,15 +42,20 @@ class CollisionShape2D : public Node2D {
Rect2 rect = Rect2(-Point2(10, 10), Point2(20, 20));
uint32_t owner_id = 0;
CollisionObject2D *parent = nullptr;
- void _shape_changed();
bool disabled = false;
bool one_way_collision = false;
real_t one_way_collision_margin = 1.0;
+ Color debug_color;
+ void _shape_changed();
void _update_in_shape_owner(bool p_xform_only = false);
+ Color _get_default_debug_color() const;
protected:
void _notification(int p_what);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -72,6 +77,9 @@ public:
void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const;
+ void set_debug_color(const Color &p_color);
+ Color get_debug_color() const;
+
PackedStringArray get_configuration_warnings() const override;
CollisionShape2D();
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index eece90190b..c6296f4732 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -1162,74 +1162,73 @@ void CPUParticles2D::_notification(int p_what) {
}
void CPUParticles2D::convert_from_particles(Node *p_particles) {
- GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(p_particles);
- ERR_FAIL_COND_MSG(!particles, "Only GPUParticles2D nodes can be converted to CPUParticles2D.");
-
- set_emitting(particles->is_emitting());
- set_amount(particles->get_amount());
- set_lifetime(particles->get_lifetime());
- set_one_shot(particles->get_one_shot());
- set_pre_process_time(particles->get_pre_process_time());
- set_explosiveness_ratio(particles->get_explosiveness_ratio());
- set_randomness_ratio(particles->get_randomness_ratio());
- set_use_local_coordinates(particles->get_use_local_coordinates());
- set_fixed_fps(particles->get_fixed_fps());
- set_fractional_delta(particles->get_fractional_delta());
- set_speed_scale(particles->get_speed_scale());
- set_draw_order(DrawOrder(particles->get_draw_order()));
- set_texture(particles->get_texture());
-
- Ref<Material> mat = particles->get_material();
+ GPUParticles2D *gpu_particles = Object::cast_to<GPUParticles2D>(p_particles);
+ ERR_FAIL_COND_MSG(!gpu_particles, "Only GPUParticles2D nodes can be converted to CPUParticles2D.");
+
+ set_emitting(gpu_particles->is_emitting());
+ set_amount(gpu_particles->get_amount());
+ set_lifetime(gpu_particles->get_lifetime());
+ set_one_shot(gpu_particles->get_one_shot());
+ set_pre_process_time(gpu_particles->get_pre_process_time());
+ set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio());
+ set_randomness_ratio(gpu_particles->get_randomness_ratio());
+ set_use_local_coordinates(gpu_particles->get_use_local_coordinates());
+ set_fixed_fps(gpu_particles->get_fixed_fps());
+ set_fractional_delta(gpu_particles->get_fractional_delta());
+ set_speed_scale(gpu_particles->get_speed_scale());
+ set_draw_order(DrawOrder(gpu_particles->get_draw_order()));
+ set_texture(gpu_particles->get_texture());
+
+ Ref<Material> mat = gpu_particles->get_material();
if (mat.is_valid()) {
set_material(mat);
}
- Ref<ParticleProcessMaterial> material = particles->get_process_material();
- if (material.is_null()) {
+ Ref<ParticleProcessMaterial> proc_mat = gpu_particles->get_process_material();
+ if (proc_mat.is_null()) {
return;
}
- Vector3 dir = material->get_direction();
+ Vector3 dir = proc_mat->get_direction();
set_direction(Vector2(dir.x, dir.y));
- set_spread(material->get_spread());
+ set_spread(proc_mat->get_spread());
- set_color(material->get_color());
+ set_color(proc_mat->get_color());
- Ref<GradientTexture1D> gt = material->get_color_ramp();
+ Ref<GradientTexture1D> gt = proc_mat->get_color_ramp();
if (gt.is_valid()) {
set_color_ramp(gt->get_gradient());
}
- Ref<GradientTexture1D> gti = material->get_color_initial_ramp();
+ Ref<GradientTexture1D> gti = proc_mat->get_color_initial_ramp();
if (gti.is_valid()) {
set_color_initial_ramp(gti->get_gradient());
}
- set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, proc_mat->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
- set_emission_shape(EmissionShape(material->get_emission_shape()));
- set_emission_sphere_radius(material->get_emission_sphere_radius());
- Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
+ set_emission_shape(EmissionShape(proc_mat->get_emission_shape()));
+ set_emission_sphere_radius(proc_mat->get_emission_sphere_radius());
+ Vector2 rect_extents = Vector2(proc_mat->get_emission_box_extents().x, proc_mat->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
- Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
+ Ref<CurveXYZTexture> scale3D = proc_mat->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
if (scale3D.is_valid()) {
split_scale = true;
scale_curve_x = scale3D->get_curve_x();
scale_curve_y = scale3D->get_curve_y();
}
- Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
- set_gravity(gravity);
- set_lifetime_randomness(material->get_lifetime_randomness());
+ set_gravity(Vector2(proc_mat->get_gravity().x, proc_mat->get_gravity().y));
+ set_lifetime_randomness(proc_mat->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
- set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \
+ set_param_min(m_param, proc_mat->get_param_min(ParticleProcessMaterial::m_param)); \
{ \
- Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \
+ Ref<CurveTexture> ctex = proc_mat->get_param_texture(ParticleProcessMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
- set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param));
+ set_param_max(m_param, proc_mat->get_param_max(ParticleProcessMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index ea735411a8..141e5f9139 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -152,8 +152,8 @@ private:
Vector2 direction = Vector2(1, 0);
real_t spread = 45.0;
- real_t parameters_min[PARAM_MAX];
- real_t parameters_max[PARAM_MAX];
+ real_t parameters_min[PARAM_MAX] = {};
+ real_t parameters_max[PARAM_MAX] = {};
Ref<Curve> curve_parameters[PARAM_MAX];
Color color;
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 18f709f241..9786b01058 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -353,13 +353,13 @@ void GPUParticles2D::_validate_property(PropertyInfo &p_property) const {
}
void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
- Transform3D transform;
- transform.basis.set_column(0, Vector3(p_transform2d.columns[0].x, p_transform2d.columns[0].y, 0));
- transform.basis.set_column(1, Vector3(p_transform2d.columns[1].x, p_transform2d.columns[1].y, 0));
- transform.set_origin(Vector3(p_transform2d.get_origin().x, p_transform2d.get_origin().y, 0));
+ Transform3D emit_transform;
+ emit_transform.basis.set_column(0, Vector3(p_transform2d.columns[0].x, p_transform2d.columns[0].y, 0));
+ emit_transform.basis.set_column(1, Vector3(p_transform2d.columns[1].x, p_transform2d.columns[1].y, 0));
+ emit_transform.set_origin(Vector3(p_transform2d.get_origin().x, p_transform2d.get_origin().y, 0));
Vector3 velocity = Vector3(p_velocity2d.x, p_velocity2d.y, 0);
- RS::get_singleton()->particles_emit(particles, transform, velocity, p_color, p_custom, p_emit_flags);
+ RS::get_singleton()->particles_emit(particles, emit_transform, velocity, p_color, p_custom, p_emit_flags);
}
void GPUParticles2D::_attach_sub_emitter() {
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 90402260ed..78b5199358 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -172,6 +172,7 @@ void Light2D::set_shadow_filter(ShadowFilter p_filter) {
ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX);
shadow_filter = p_filter;
RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter));
+ notify_property_list_changed();
}
Light2D::ShadowFilter Light2D::get_shadow_filter() const {
@@ -231,6 +232,10 @@ void Light2D::_validate_property(PropertyInfo &p_property) const {
if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+
+ if (shadow && p_property.name == "shadow_filter_smooth" && shadow_filter == SHADOW_FILTER_NONE) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Light2D::_bind_methods() {
@@ -454,7 +459,7 @@ void DirectionalLight2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance);
ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01,suffix:px"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater,suffix:px"), "set_max_distance", "get_max_distance");
}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index f077f7f5e6..1a62c9bb6c 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -75,6 +75,7 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent2D::set_target_location);
ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location);
+
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity);
@@ -88,6 +89,7 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done);
ADD_GROUP("Pathfinding", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_path_desired_distance", "get_path_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance");
@@ -104,7 +106,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
ADD_SIGNAL(MethodInfo("navigation_finished"));
- ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+ ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity")));
}
void NavigationAgent2D::_notification(int p_what) {
@@ -478,8 +480,8 @@ void NavigationAgent2D::_request_repath() {
void NavigationAgent2D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal(SNAME("target_reached"));
target_reached = true;
+ emit_signal(SNAME("target_reached"));
}
}
}
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index e46bb79551..cbec4db4c5 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -153,7 +153,7 @@ void NavigationObstacle2D::reevaluate_agent_radius() {
real_t NavigationObstacle2D::estimate_agent_radius() const {
if (parent_node2d && parent_node2d->is_inside_tree()) {
// Estimate the radius of this physics body
- real_t radius = 0.0;
+ real_t max_radius = 0.0;
for (int i(0); i < parent_node2d->get_child_count(); i++) {
// For each collision shape
CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(parent_node2d->get_child(i));
@@ -167,17 +167,17 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
Size2 s = cs->get_global_scale();
r *= MAX(s.x, s.y);
// Takes the biggest radius
- radius = MAX(radius, r);
+ max_radius = MAX(max_radius, r);
} else if (cs && !cs->is_inside_tree()) {
WARN_PRINT("A CollisionShape2D of the NavigationObstacle2D parent node was not inside the SceneTree when estimating the obstacle radius."
"\nMove the NavigationObstacle2D to a child position below any CollisionShape2D node of the parent node so the CollisionShape2D is already inside the SceneTree.");
}
}
Vector2 s = parent_node2d->get_global_scale();
- radius *= MAX(s.x, s.y);
+ max_radius *= MAX(s.x, s.y);
- if (radius > 0.0) {
- return radius;
+ if (max_radius > 0.0) {
+ return max_radius;
}
}
return 1.0; // Never a 0 radius
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 7765533016..2518069b78 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -437,7 +437,7 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,no_slider,suffix:px"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,hide_slider,suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index f1a28b7852..b7e6eb8ea5 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -71,29 +71,29 @@ void ParallaxBackground::_update_scroll() {
return;
}
- Vector2 ofs = base_offset + offset * base_scale;
+ Vector2 scroll_ofs = base_offset + offset * base_scale;
Size2 vps = get_viewport_size();
- ofs = -ofs;
+ scroll_ofs = -scroll_ofs;
if (limit_begin.x < limit_end.x) {
- if (ofs.x < limit_begin.x) {
- ofs.x = limit_begin.x;
- } else if (ofs.x + vps.x > limit_end.x) {
- ofs.x = limit_end.x - vps.x;
+ if (scroll_ofs.x < limit_begin.x) {
+ scroll_ofs.x = limit_begin.x;
+ } else if (scroll_ofs.x + vps.x > limit_end.x) {
+ scroll_ofs.x = limit_end.x - vps.x;
}
}
if (limit_begin.y < limit_end.y) {
- if (ofs.y < limit_begin.y) {
- ofs.y = limit_begin.y;
- } else if (ofs.y + vps.y > limit_end.y) {
- ofs.y = limit_end.y - vps.y;
+ if (scroll_ofs.y < limit_begin.y) {
+ scroll_ofs.y = limit_begin.y;
+ } else if (scroll_ofs.y + vps.y > limit_end.y) {
+ scroll_ofs.y = limit_end.y - vps.y;
}
}
- ofs = -ofs;
+ scroll_ofs = -scroll_ofs;
- final_offset = ofs;
+ final_offset = scroll_ofs;
for (int i = 0; i < get_child_count(); i++) {
ParallaxLayer *l = Object::cast_to<ParallaxLayer>(get_child(i));
@@ -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);
+ l->set_base_offset_and_scale((scroll_ofs + screen_offset * (scale - 1)) / scale, 1.0);
} else {
- l->set_base_offset_and_scale(ofs, scale);
+ l->set_base_offset_and_scale(scroll_ofs, scale);
}
}
}
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 01e4bf19f3..feb1fcd90c 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -37,9 +37,9 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
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);
+ Vector2 final_ofs = pb->get_final_offset();
+ real_t scroll_scale = pb->get_scroll_scale();
+ set_base_offset_and_scale(final_ofs, scroll_scale);
}
}
@@ -52,9 +52,9 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
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);
+ Vector2 final_ofs = pb->get_final_offset();
+ real_t scroll_scale = pb->get_scroll_scale();
+ set_base_offset_and_scale(final_ofs, scroll_scale);
}
}
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index c1044fdf5b..b5945a4562 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -175,51 +175,18 @@ void PathFollow2D::_update_transform() {
if (path_length == 0) {
return;
}
- Vector2 pos = c->sample_baked(progress, cubic);
if (rotates) {
- real_t ahead = progress + lookahead;
-
- if (loop && ahead >= path_length) {
- // If our lookahead will loop, we need to check if the path is closed.
- int point_count = c->get_point_count();
- if (point_count > 0) {
- Vector2 start_point = c->get_point_position(0);
- Vector2 end_point = c->get_point_position(point_count - 1);
- if (start_point == end_point) {
- // Since the path is closed we want to 'smooth off'
- // the corner at the start/end.
- // So we wrap the lookahead back round.
- ahead = Math::fmod(ahead, path_length);
- }
- }
- }
-
- Vector2 ahead_pos = c->sample_baked(ahead, cubic);
-
- Vector2 tangent_to_curve;
- if (ahead_pos == pos) {
- // This will happen at the end of non-looping or non-closed paths.
- // We'll try a look behind instead, in order to get a meaningful angle.
- tangent_to_curve =
- (pos - c->sample_baked(progress - lookahead, cubic)).normalized();
- } else {
- tangent_to_curve = (ahead_pos - pos).normalized();
- }
-
- Vector2 normal_of_curve = -tangent_to_curve.orthogonal();
-
- pos += tangent_to_curve * h_offset;
- pos += normal_of_curve * v_offset;
-
- set_rotation(tangent_to_curve.angle());
-
+ Transform2D xform = c->sample_baked_with_rotation(progress, cubic, loop, lookahead);
+ xform.translate_local(v_offset, h_offset);
+ set_rotation(xform[1].angle());
+ set_position(xform[2]);
} else {
+ Vector2 pos = c->sample_baked(progress, cubic);
pos.x += h_offset;
pos.y += v_offset;
+ set_position(pos);
}
-
- set_position(pos);
}
void PathFollow2D::_notification(int p_what) {
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 4e6b37a860..0f3e6c7529 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -471,28 +471,28 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
//put the ones to add
for (int i = 0; i < p_state->get_contact_count(); i++) {
- RID rid = p_state->get_contact_collider(i);
- ObjectID obj = p_state->get_contact_collider_id(i);
+ RID col_rid = p_state->get_contact_collider(i);
+ ObjectID col_obj = p_state->get_contact_collider_id(i);
int local_shape = p_state->get_contact_local_shape(i);
- int shape = p_state->get_contact_collider_shape(i);
+ int col_shape = p_state->get_contact_collider_shape(i);
- HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(obj);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj);
if (!E) {
- toadd[toadd_count].rid = rid;
+ toadd[toadd_count].rid = col_rid;
toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
+ toadd[toadd_count].id = col_obj;
+ toadd[toadd_count].shape = col_shape;
toadd_count++;
continue;
}
- ShapePair sp(shape, local_shape);
+ ShapePair sp(col_shape, local_shape);
int idx = E->value.shapes.find(sp);
if (idx == -1) {
- toadd[toadd_count].rid = rid;
+ toadd[toadd_count].rid = col_rid;
toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
+ toadd[toadd_count].id = col_obj;
+ toadd[toadd_count].shape = col_shape;
toadd_count++;
continue;
}
@@ -1134,6 +1134,7 @@ 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);
@@ -1192,6 +1193,7 @@ 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];
@@ -1348,6 +1350,7 @@ 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);
@@ -1394,7 +1397,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; // Report margin recovery as collision to improve floor detection.
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
@@ -1430,7 +1433,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; // Report margin recovery as collision to improve floor detection.
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result;
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index b5759c54f7..02d8e20ce8 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -146,9 +146,9 @@ void Bone2D::_notification(int p_what) {
queue_redraw();
if (get_parent()) {
- Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent());
- if (parent_bone) {
- parent_bone->queue_redraw();
+ Bone2D *p_bone = Object::cast_to<Bone2D>(get_parent());
+ if (p_bone) {
+ p_bone->queue_redraw();
}
}
#endif // TOOLS_ENABLED
@@ -192,10 +192,8 @@ void Bone2D::_notification(int p_what) {
cache_transform = tmp_trans;
} break;
- // Bone2D Editor gizmo drawing:
-#ifndef _MSC_VER
-#warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin
-#endif
+ // Bone2D Editor gizmo drawing.
+ // TODO: Bone2D gizmo drawing needs to be moved to an editor plugin.
case NOTIFICATION_DRAW: {
// Only draw the gizmo in the editor!
if (Engine::get_singleton()->is_editor_hint() == false) {
@@ -219,11 +217,11 @@ void Bone2D::_notification(int p_what) {
editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale());
RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans);
- Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1");
- Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2");
- Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
- Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color");
- Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color");
+ Color bone_color1 = EDITOR_GET("editors/2d/bone_color1");
+ Color bone_color2 = EDITOR_GET("editors/2d/bone_color2");
+ Color bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
+ Color bone_outline_color = EDITOR_GET("editors/2d/bone_outline_color");
+ Color bone_selected_color = EDITOR_GET("editors/2d/bone_selected_color");
bool Bone2D_found = false;
for (int i = 0; i < get_child_count(); i++) {
@@ -319,8 +317,8 @@ void Bone2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) {
- int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width");
- int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size");
+ int bone_width = EDITOR_GET("editors/2d/bone_width");
+ int bone_outline_width = EDITOR_GET("editors/2d/bone_outline_size");
if (!is_inside_tree()) {
return false; //may have been removed
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 0ecf8333a0..0784318442 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -309,9 +309,7 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const {
q.y = 1.0f - q.y;
}
q = q * src_rect.size + src_rect.position;
-#ifndef _MSC_VER
-#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that)
-#endif
+ // TODO: This need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that).
bool is_repeat = false;
bool is_mirrored_repeat = false;
if (is_repeat) {
@@ -446,7 +444,7 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index bdcd1f2f28..f7a66215b2 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -43,10 +43,10 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
ERR_FAIL_COND_V(is_center_bit(), output);
- Ref<TileSet> tile_set = tile_map->get_tileset();
- ERR_FAIL_COND_V(!tile_set.is_valid(), output);
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND_V(!ts.is_valid(), output);
- TileSet::TileShape shape = tile_set->get_tile_shape();
+ TileSet::TileShape shape = ts->get_tile_shape();
if (shape == TileSet::TILE_SHAPE_SQUARE) {
switch (bit) {
case 1:
@@ -87,7 +87,7 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
}
} else {
// Half offset shapes.
- TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis();
+ TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
switch (bit) {
case 1:
@@ -150,8 +150,8 @@ HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlap
TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const Vector2i &p_position, int p_terrain) {
tile_map = p_tile_map;
- Ref<TileSet> tile_set = tile_map->get_tileset();
- ERR_FAIL_COND(!tile_set.is_valid());
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND(!ts.is_valid());
bit = 0;
base_cell_coords = p_position;
@@ -162,10 +162,10 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
// The way we build the constraint make it easy to detect conflicting constraints.
tile_map = p_tile_map;
- Ref<TileSet> tile_set = tile_map->get_tileset();
- ERR_FAIL_COND(!tile_set.is_valid());
+ Ref<TileSet> ts = tile_map->get_tileset();
+ ERR_FAIL_COND(!ts.is_valid());
- TileSet::TileShape shape = tile_set->get_tile_shape();
+ TileSet::TileShape shape = ts->get_tile_shape();
if (shape == TileSet::TILE_SHAPE_SQUARE) {
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
@@ -244,7 +244,7 @@ TileMap::TerrainConstraint::TerrainConstraint(const TileMap *p_tile_map, const V
}
} else {
// Half-offset shapes
- TileSet::TileOffsetAxis offset_axis = tile_set->get_tile_offset_axis();
+ TileSet::TileOffsetAxis offset_axis = ts->get_tile_offset_axis();
if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
switch (p_bit) {
case TileSet::CELL_NEIGHBOR_RIGHT_SIDE:
@@ -758,12 +758,12 @@ void TileMap::set_y_sort_enabled(bool p_enable) {
}
Vector2i TileMap::_coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const {
- int quadrant_size = get_effective_quadrant_size(p_layer);
+ int quad_size = get_effective_quadrant_size(p_layer);
// Rounding down, instead of simply rounding towards zero (truncating)
return Vector2i(
- p_coords.x > 0 ? p_coords.x / quadrant_size : (p_coords.x - (quadrant_size - 1)) / quadrant_size,
- p_coords.y > 0 ? p_coords.y / quadrant_size : (p_coords.y - (quadrant_size - 1)) / quadrant_size);
+ p_coords.x > 0 ? p_coords.x / quad_size : (p_coords.x - (quad_size - 1)) / quad_size,
+ p_coords.y > 0 ? p_coords.y / quad_size : (p_coords.y - (quad_size - 1)) / quad_size);
}
HashMap<Vector2i, TileMapQuadrant>::Iterator TileMap::_create_quadrant(int p_layer, const Vector2i &p_qk) {
@@ -1007,8 +1007,24 @@ void TileMap::_recompute_rect_cache() {
void TileMap::_rendering_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_CANVAS: {
+ bool node_visible = is_visible_in_tree();
+ for (int layer = 0; layer < (int)layers.size(); layer++) {
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ Transform2D xform;
+ xform.set_origin(map_to_local(kv.key));
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, get_canvas());
+ RS::get_singleton()->canvas_light_occluder_set_transform(kv.value, get_global_transform() * xform);
+ RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
+ }
+ }
+ }
+ } break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
- bool visible = is_visible_in_tree();
+ bool node_visible = is_visible_in_tree();
for (int layer = 0; layer < (int)layers.size(); layer++) {
for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) {
TileMapQuadrant &q = E_quadrant.value;
@@ -1017,8 +1033,8 @@ void TileMap::_rendering_notification(int p_what) {
for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
Transform2D xform;
xform.set_origin(E_cell.key);
- for (const RID &occluder : q.occluders) {
- RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, visible);
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ RS::get_singleton()->canvas_light_occluder_set_enabled(kv.value, node_visible);
}
}
}
@@ -1034,12 +1050,10 @@ void TileMap::_rendering_notification(int p_what) {
TileMapQuadrant &q = E_quadrant.value;
// Update occluders transform.
- for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
Transform2D xform;
- xform.set_origin(E_cell.key);
- for (const RID &occluder : q.occluders) {
- RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform() * xform);
- }
+ xform.set_origin(map_to_local(kv.key));
+ RenderingServer::get_singleton()->canvas_light_occluder_set_transform(kv.value, get_global_transform() * xform);
}
}
}
@@ -1050,6 +1064,17 @@ void TileMap::_rendering_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled());
}
} break;
+
+ case NOTIFICATION_EXIT_CANVAS: {
+ for (int layer = 0; layer < (int)layers.size(); layer++) {
+ for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) {
+ TileMapQuadrant &q = E_quadrant.value;
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ RS::get_singleton()->canvas_light_occluder_attach_to_canvas(kv.value, RID());
+ }
+ }
+ }
+ } break;
}
}
@@ -1072,8 +1097,8 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled);
rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
rs->canvas_item_set_z_index(ci, layers[p_layer].z_index);
- rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
rs->canvas_item_set_light_mask(ci, get_light_mask());
}
@@ -1091,7 +1116,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!tile_set.is_valid());
- bool visible = is_visible_in_tree();
+ bool node_visible = is_visible_in_tree();
SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first();
while (q_list_element) {
@@ -1106,26 +1131,26 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
q.canvas_items.clear();
// Free the occluders.
- for (const RID &occluder : q.occluders) {
- rs->free(occluder);
+ for (const KeyValue<Vector2i, RID> &kv : q.occluders) {
+ rs->free(kv.value);
}
q.occluders.clear();
// Those allow to group cell per material or z-index.
Ref<Material> prev_material;
int prev_z_index = 0;
- RID prev_canvas_item;
+ RID prev_ci;
- Color modulate = get_self_modulate();
- modulate *= get_layer_modulate(q.layer);
+ Color tile_modulate = get_self_modulate();
+ tile_modulate *= get_layer_modulate(q.layer);
if (selected_layer >= 0) {
int z1 = get_layer_z_index(q.layer);
int z2 = get_layer_z_index(selected_layer);
if (z1 < z2 || (z1 == z2 && q.layer < selected_layer)) {
- modulate = modulate.darkened(0.5);
+ tile_modulate = tile_modulate.darkened(0.5);
} else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) {
- modulate = modulate.darkened(0.5);
- modulate.a *= 0.3;
+ tile_modulate = tile_modulate.darkened(0.5);
+ tile_modulate.a *= 0.3;
}
}
@@ -1152,53 +1177,53 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
Ref<Material> mat = tile_data->get_material();
- int z_index = tile_data->get_z_index();
+ int tile_z_index = tile_data->get_z_index();
// Quandrant pos.
- Vector2 position = map_to_local(q.coords * get_effective_quadrant_size(q.layer));
+ Vector2 tile_position = map_to_local(q.coords * get_effective_quadrant_size(q.layer));
if (is_y_sort_enabled() && layers[q.layer].y_sort_enabled) {
// When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem.
- position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin();
+ tile_position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin();
}
// --- CanvasItems ---
// Create two canvas items, for rendering and debug.
- RID canvas_item;
+ RID ci;
// Check if the material or the z_index changed.
- if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) {
+ if (prev_ci == RID() || prev_material != mat || prev_z_index != tile_z_index) {
// If so, create a new CanvasItem.
- canvas_item = rs->canvas_item_create();
+ ci = rs->canvas_item_create();
if (mat.is_valid()) {
- rs->canvas_item_set_material(canvas_item, mat->get_rid());
+ rs->canvas_item_set_material(ci, mat->get_rid());
}
- rs->canvas_item_set_parent(canvas_item, layers[q.layer].canvas_item);
- rs->canvas_item_set_use_parent_material(canvas_item, get_use_parent_material() || get_material().is_valid());
+ rs->canvas_item_set_parent(ci, layers[q.layer].canvas_item);
+ rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid());
Transform2D xform;
- xform.set_origin(position);
- rs->canvas_item_set_transform(canvas_item, xform);
+ xform.set_origin(tile_position);
+ rs->canvas_item_set_transform(ci, xform);
- rs->canvas_item_set_light_mask(canvas_item, get_light_mask());
- rs->canvas_item_set_z_as_relative_to_parent(canvas_item, true);
- rs->canvas_item_set_z_index(canvas_item, z_index);
+ rs->canvas_item_set_light_mask(ci, get_light_mask());
+ rs->canvas_item_set_z_as_relative_to_parent(ci, true);
+ rs->canvas_item_set_z_index(ci, tile_z_index);
- rs->canvas_item_set_default_texture_filter(canvas_item, RS::CanvasItemTextureFilter(get_texture_filter()));
- rs->canvas_item_set_default_texture_repeat(canvas_item, RS::CanvasItemTextureRepeat(get_texture_repeat()));
+ rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
+ rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
- q.canvas_items.push_back(canvas_item);
+ q.canvas_items.push_back(ci);
- prev_canvas_item = canvas_item;
+ prev_ci = ci;
prev_material = mat;
- prev_z_index = z_index;
+ prev_z_index = tile_z_index;
} else {
// Keep the same canvas_item to draw on.
- canvas_item = prev_canvas_item;
+ ci = prev_ci;
}
// Drawing the tile in the canvas item.
- draw_tile(canvas_item, E_cell.key - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate, tile_data);
+ draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, tile_modulate, tile_data);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -1206,12 +1231,12 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
xform.set_origin(E_cell.key);
if (tile_data->get_occluder(i).is_valid()) {
RID occluder_id = rs->canvas_light_occluder_create();
- rs->canvas_light_occluder_set_enabled(occluder_id, visible);
+ rs->canvas_light_occluder_set_enabled(occluder_id, node_visible);
rs->canvas_light_occluder_set_transform(occluder_id, get_global_transform() * xform);
rs->canvas_light_occluder_set_polygon(occluder_id, tile_data->get_occluder(i)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder_id, get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
- q.occluders.push_back(occluder_id);
+ q.occluders[E_cell.value] = occluder_id;
}
}
}
@@ -1259,8 +1284,8 @@ void TileMap::_rendering_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
p_quadrant->canvas_items.clear();
// Free the occluders.
- for (const RID &occluder : p_quadrant->occluders) {
- RenderingServer::get_singleton()->free(occluder);
+ for (const KeyValue<Vector2i, RID> &kv : p_quadrant->occluders) {
+ RenderingServer::get_singleton()->free(kv.value);
}
p_quadrant->occluders.clear();
}
@@ -1272,7 +1297,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
return;
}
- // Draw a placeholder for scenes needing one.
+ // Draw a placeholder for tiles needing one.
RenderingServer *rs = RenderingServer::get_singleton();
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
for (const Vector2i &E_cell : p_quadrant->cells) {
@@ -1305,9 +1330,9 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
}
@@ -1420,7 +1445,7 @@ void TileMap::_physics_notification(int p_what) {
#endif
if (is_inside_tree() && (!collision_animatable || in_editor)) {
// Update the new transform directly if we are not in animatable mode.
- Transform2D global_transform = get_global_transform();
+ Transform2D gl_transform = get_global_transform();
for (int layer = 0; layer < (int)layers.size(); layer++) {
for (KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) {
TileMapQuadrant &q = E.value;
@@ -1428,7 +1453,7 @@ void TileMap::_physics_notification(int p_what) {
for (RID body : q.bodies) {
Transform2D xform;
xform.set_origin(map_to_local(bodies_coords[body]));
- xform = global_transform * xform;
+ xform = gl_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
}
@@ -1471,9 +1496,9 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
ERR_FAIL_COND(!is_inside_tree());
ERR_FAIL_COND(!tile_set.is_valid());
- Transform2D global_transform = get_global_transform();
- last_valid_transform = global_transform;
- new_transform = global_transform;
+ Transform2D gl_transform = get_global_transform();
+ last_valid_transform = gl_transform;
+ new_transform = gl_transform;
PhysicsServer2D *ps = PhysicsServer2D::get_singleton();
RID space = get_world_2d()->get_space();
@@ -1521,7 +1546,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
Transform2D xform;
xform.set_origin(map_to_local(E_cell));
- xform = global_transform * xform;
+ xform = gl_transform * xform;
ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
ps->body_attach_object_instance_id(body, get_instance_id());
@@ -1607,13 +1632,13 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
color.push_back(debug_collision_color);
Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer));
- Transform2D qudrant_xform;
- qudrant_xform.set_origin(quadrant_pos);
- Transform2D global_transform_inv = (get_global_transform() * qudrant_xform).affine_inverse();
+ Transform2D quadrant_to_local;
+ quadrant_to_local.set_origin(quadrant_pos);
+ Transform2D global_to_quadrant = (get_global_transform() * quadrant_to_local).affine_inverse();
for (RID body : p_quadrant->bodies) {
- Transform2D xform = Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM)) * global_transform_inv;
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D body_to_quadrant = global_to_quadrant * Transform2D(ps->body_get_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM));
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, body_to_quadrant);
for (int shape_index = 0; shape_index < ps->body_get_shape_count(body); shape_index++) {
const RID &shape = ps->body_get_shape(body, shape_index);
PhysicsServer2D::ShapeType type = ps->shape_get_type(shape);
@@ -1790,9 +1815,9 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile);
}
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
Ref<NavigationPolygon> navpoly = tile_data->get_navigation_polygon(layer_index);
@@ -1838,7 +1863,7 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_
for (const KeyValue<Vector2i, String> &E : q.scenes) {
Node *node = get_node_or_null(E.value);
if (node) {
- node->queue_delete();
+ node->queue_free();
}
}
@@ -1886,7 +1911,7 @@ void TileMap::_scenes_cleanup_quadrant(TileMapQuadrant *p_quadrant) {
for (const KeyValue<Vector2i, String> &E : p_quadrant->scenes) {
Node *node = get_node_or_null(E.value);
if (node) {
- node->queue_delete();
+ node->queue_free();
}
}
@@ -1931,9 +1956,9 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
0.8);
// Draw a placeholder tile.
- Transform2D xform;
- xform.set_origin(map_to_local(E_cell) - quadrant_pos);
- rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform);
+ Transform2D cell_to_quadrant;
+ cell_to_quadrant.set_origin(map_to_local(E_cell) - quadrant_pos);
+ rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, cell_to_quadrant);
rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color);
}
}
@@ -2181,11 +2206,10 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat
}
}
-TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) {
+TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern) {
if (!tile_set.is_valid()) {
return TileSet::TerrainsPattern();
}
-
// Returns all tiles compatible with the given constraints.
RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score;
RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set);
@@ -2196,28 +2220,41 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int
// Check the center bit constraint
TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain());
RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) {
+ continue; // Ignore a pattern that cannot keep bits without constraints unmodified.
}
// Check the surrounding bits
+ bool invalid_pattern = false;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
// Check if the bit is compatible with the constraints.
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit));
in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
- if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
- score += in_set_constraint_element->get().get_priority();
+ if (in_set_constraint_element) {
+ if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
+ score += in_set_constraint_element->get().get_priority();
+ }
+ } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) {
+ invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified.
+ break;
}
}
}
+ if (invalid_pattern) {
+ continue;
+ }
terrain_pattern_score[terrain_pattern] = score;
}
// Compute the minimum score
- TileSet::TerrainsPattern min_score_pattern;
+ TileSet::TerrainsPattern min_score_pattern = p_current_pattern;
int min_score = INT32_MAX;
for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) {
if (E.value < min_score) {
@@ -2249,7 +2286,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p
return output;
}
-RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const {
+RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const {
if (!tile_set.is_valid()) {
return RBSet<TerrainConstraint>();
}
@@ -2259,8 +2296,8 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
// Build a set of dummy constraints to get the constrained points.
RBSet<TerrainConstraint> dummy_constraints;
- for (const Vector2i &E : p_cell_list) {
- for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides.
+ for (const Vector2i &E : p_painted) {
+ for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits.
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) {
dummy_constraints.insert(TerrainConstraint(this, E, bit, -1));
@@ -2317,7 +2354,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
}
// Add the centers as constraints
- for (Vector2i E_coords : p_cell_list) {
+ for (Vector2i E_coords : p_painted) {
TileData *tile_data = nullptr;
TileMapCell cell = get_cell(p_layer, E_coords);
if (cell.source_id != TileSet::INVALID_SOURCE) {
@@ -2337,7 +2374,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l
return constraints;
}
-HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
+HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) {
if (!tile_set.is_valid()) {
return HashMap<Vector2i, TileSet::TerrainsPattern>();
}
@@ -2353,7 +2390,20 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(co
const Vector2i &coords = p_to_replace[i];
// Select the best pattern for the given constraints
- TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints);
+ TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, coords);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ current_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern);
// Update the constraint set with the new ones
RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern);
@@ -2467,12 +2517,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2502,10 +2552,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
// Build list and set of tiles that can be modified (painted and their surroundings)
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_path.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_path[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_path) {
// Find the adequate neighbor
@@ -2538,12 +2590,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay
}
// Fills in the constraint list from existing tiles.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2555,10 +2607,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
// Build list and set of tiles that can be modified (painted and their surroundings).
Vector<Vector2i> can_modify_list;
RBSet<Vector2i> can_modify_set;
+ RBSet<Vector2i> painted_set;
for (int i = p_coords_array.size() - 1; i >= 0; i--) {
const Vector2i &coords = p_coords_array[i];
can_modify_list.push_back(coords);
can_modify_set.insert(coords);
+ painted_set.insert(coords);
}
for (Vector2i coords : p_coords_array) {
// Find the adequate neighbor
@@ -2588,12 +2642,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_
}
// Fills in the constraint list from modified tiles border.
- for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) {
+ for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) {
constraints.insert(c);
}
// Fill the terrains.
- output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints);
+ output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints);
return output;
}
@@ -2602,14 +2656,38 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell
ERR_FAIL_INDEX(p_layer, (int)layers.size());
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
- Vector<Vector2i> vector_cells;
+ Vector<Vector2i> cells_vector;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_cells.size(); i++) {
- vector_cells.push_back(p_cells[i]);
- }
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ cells_vector.push_back(p_cells[i]);
+ painted_set.insert(p_cells[i]);
+ }
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -2619,13 +2697,38 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i
ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count());
Vector<Vector2i> vector_path;
+ HashSet<Vector2i> painted_set;
for (int i = 0; i < p_path.size(); i++) {
vector_path.push_back(p_path[i]);
+ painted_set.insert(p_path[i]);
}
+
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains);
- for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) {
- TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value);
- set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) {
+ if (painted_set.has(kv.key)) {
+ // Paint a random tile with the correct terrain for the painted path.
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ } else {
+ // Avoids updating the painted path from the output if the new pattern is the same as before.
+ TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set);
+ TileMapCell cell = get_cell(p_layer, kv.key);
+ if (cell.source_id != TileSet::INVALID_SOURCE) {
+ TileSetSource *source = *tile_set->get_source(cell.source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Get tile data.
+ TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile);
+ if (tile_data && tile_data->get_terrain_set() == p_terrain_set) {
+ in_map_terrain_pattern = tile_data->get_terrains_pattern();
+ }
+ }
+ }
+ if (in_map_terrain_pattern != kv.value) {
+ TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
+ set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile);
+ }
+ }
}
}
@@ -2794,9 +2897,9 @@ Vector<int> TileMap::_get_tile_data(int p_layer) const {
// Export tile data to raw format
const HashMap<Vector2i, TileMapCell> &tile_map = layers[p_layer].tile_map;
- Vector<int> data;
- data.resize(tile_map.size() * 3);
- int *w = data.ptrw();
+ Vector<int> tile_data;
+ tile_data.resize(tile_map.size() * 3);
+ int *w = tile_data.ptrw();
// Save in highest format
@@ -2812,7 +2915,7 @@ Vector<int> TileMap::_get_tile_data(int p_layer) const {
idx += 3;
}
- return data;
+ return tile_data;
}
void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r_dirty_quadrant_list) {
@@ -3692,13 +3795,14 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) {
}
void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
- // Set a default texture filter for the whole tilemap
+ // Set a default texture filter for the whole tilemap.
CanvasItem::set_texture_filter(p_texture_filter);
+ TextureFilter target_filter = get_texture_filter_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(p_texture_filter));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter));
_make_quadrant_dirty(F);
}
}
@@ -3707,13 +3811,14 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) {
}
void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {
- // Set a default texture repeat for the whole tilemap
+ // Set a default texture repeat for the whole tilemap.
CanvasItem::set_texture_repeat(p_texture_repeat);
+ TextureRepeat target_repeat = get_texture_repeat_in_tree();
for (unsigned int layer = 0; layer < layers.size(); layer++) {
for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) {
TileMapQuadrant &q = F->value;
for (const RID &ci : q.canvas_items) {
- RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(p_texture_repeat));
+ RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat));
_make_quadrant_dirty(F);
}
}
@@ -3951,9 +4056,5 @@ TileMap::TileMap() {
}
TileMap::~TileMap() {
- if (tile_set.is_valid()) {
- tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed));
- }
-
_clear_internals();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 902926291d..7f3e241871 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -68,7 +68,7 @@ struct TileMapQuadrant {
// Rendering.
List<RID> canvas_items;
- List<RID> occluders;
+ HashMap<Vector2i, RID> occluders;
// Physics.
List<RID> bodies;
@@ -266,9 +266,9 @@ private:
void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant);
// Terrains.
- TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints);
+ TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern);
RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const;
- RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const;
+ RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const;
// Set and get tiles from data arrays.
void _set_tile_data(int p_layer, const Vector<int> &p_data);
@@ -352,7 +352,7 @@ public:
void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern);
// Terrains.
- HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
+ HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed.
HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed.
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index cefa9eceff..c6433e773d 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -578,11 +578,11 @@ bool Area3D::is_using_reverb_bus() const {
return use_reverb_bus;
}
-void Area3D::set_reverb_bus(const StringName &p_audio_bus) {
+void Area3D::set_reverb_bus_name(const StringName &p_audio_bus) {
reverb_bus = p_audio_bus;
}
-StringName Area3D::get_reverb_bus() const {
+StringName Area3D::get_reverb_bus_name() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) {
return reverb_bus;
@@ -711,8 +711,8 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus);
ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus);
- ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area3D::set_reverb_bus);
- ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area3D::get_reverb_bus);
+ ClassDB::bind_method(D_METHOD("set_reverb_bus_name", "name"), &Area3D::set_reverb_bus_name);
+ ClassDB::bind_method(D_METHOD("get_reverb_bus_name"), &Area3D::get_reverb_bus_name);
ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area3D::set_reverb_amount);
ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area3D::get_reverb_amount);
@@ -760,8 +760,8 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name");
ADD_GROUP("Reverb Bus", "reverb_bus_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus");
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enabled"), "set_use_reverb_bus", "is_using_reverb_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus_name", "get_reverb_bus_name");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 0f0bcc7ce0..195f9f0d9e 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -141,13 +141,12 @@ private:
float reverb_amount = 0.0;
float reverb_uniformity = 0.0;
- void _validate_property(PropertyInfo &p_property) const;
-
void _initialize_wind();
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_gravity_space_override_mode(SpaceOverride p_mode);
@@ -216,8 +215,8 @@ public:
void set_use_reverb_bus(bool p_enable);
bool is_using_reverb_bus() const;
- void set_reverb_bus(const StringName &p_audio_bus);
- StringName get_reverb_bus() const;
+ void set_reverb_bus_name(const StringName &p_audio_bus);
+ StringName get_reverb_bus_name() const;
void set_reverb_amount(float p_amount);
float get_reverb_amount() const;
diff --git a/scene/3d/audio_listener_3d.cpp b/scene/3d/audio_listener_3d.cpp
index 4f3f403ab7..8836244f3b 100644
--- a/scene/3d/audio_listener_3d.cpp
+++ b/scene/3d/audio_listener_3d.cpp
@@ -138,8 +138,6 @@ bool AudioListener3D::is_current() const {
} else {
return current;
}
-
- return false;
}
void AudioListener3D::_bind_methods() {
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 21cf3bdb3b..b9d95672fe 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -231,7 +231,7 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
}
}
- att += unit_db;
+ att += volume_db;
if (att > max_db) {
att = max_db;
}
@@ -485,7 +485,7 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
}
if (area->is_using_reverb_bus()) {
- StringName reverb_bus_name = area->get_reverb_bus();
+ StringName reverb_bus_name = area->get_reverb_bus_name();
Vector<AudioFrame> reverb_vol;
_calc_reverb_vol(area, listener_area_pos, output_volume_vector, reverb_vol);
bus_volumes[reverb_bus_name] = reverb_vol;
@@ -538,12 +538,12 @@ Ref<AudioStream> AudioStreamPlayer3D::get_stream() const {
return stream;
}
-void AudioStreamPlayer3D::set_unit_db(float p_volume) {
- unit_db = p_volume;
+void AudioStreamPlayer3D::set_volume_db(float p_volume) {
+ volume_db = p_volume;
}
-float AudioStreamPlayer3D::get_unit_db() const {
- return unit_db;
+float AudioStreamPlayer3D::get_volume_db() const {
+ return volume_db;
}
void AudioStreamPlayer3D::set_unit_size(float p_volume) {
@@ -810,8 +810,8 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream);
- ClassDB::bind_method(D_METHOD("set_unit_db", "unit_db"), &AudioStreamPlayer3D::set_unit_db);
- ClassDB::bind_method(D_METHOD("get_unit_db"), &AudioStreamPlayer3D::get_unit_db);
+ ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer3D::set_volume_db);
+ ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer3D::get_volume_db);
ClassDB::bind_method(D_METHOD("set_unit_size", "unit_size"), &AudioStreamPlayer3D::set_unit_size);
ClassDB::bind_method(D_METHOD("get_unit_size"), &AudioStreamPlayer3D::get_unit_size);
@@ -878,7 +878,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Logarithmic,Disabled"), "set_attenuation_model", "get_attenuation_model");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80,suffix:dB"), "set_unit_db", "get_unit_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,80,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6,suffix:dB"), "set_max_db", "get_max_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
@@ -916,7 +916,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
velocity_tracker.instantiate();
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed));
set_disable_scale(true);
- cached_global_panning_strength = ProjectSettings::get_singleton()->get("audio/general/3d_panning_strength");
+ cached_global_panning_strength = GLOBAL_GET("audio/general/3d_panning_strength");
}
AudioStreamPlayer3D::~AudioStreamPlayer3D() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index ef48269544..913cc9fc00 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -71,7 +71,7 @@ private:
SafeNumeric<float> setplay{ -1.0 };
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
- float unit_db = 0.0;
+ float volume_db = 0.0;
float unit_size = 10.0;
float max_db = 3.0;
float pitch_scale = 1.0;
@@ -128,8 +128,8 @@ public:
void set_stream(Ref<AudioStream> p_stream);
Ref<AudioStream> get_stream() const;
- void set_unit_db(float p_volume);
- float get_unit_db() const;
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
void set_unit_size(float p_volume);
float get_unit_size() const;
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 7b0a6c7e3e..d8524a7392 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -91,7 +91,7 @@ bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "override_pose", PROPERTY_HINT_NONE, ""));
if (override_pose) {
- p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override, Local Pose Override, Custom Pose"));
+ p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override,Local Pose Override,Custom Pose"));
}
p_list->push_back(PropertyInfo(Variant::BOOL, "use_external_skeleton", PROPERTY_HINT_NONE, ""));
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index c3c1c8ba36..a98be62dfa 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -150,13 +150,13 @@ uint32_t CollisionObject3D::get_collision_mask() const {
void CollisionObject3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t collision_layer = get_collision_layer();
+ uint32_t collision_layer_new = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << (p_layer_number - 1);
+ collision_layer_new |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << (p_layer_number - 1));
+ collision_layer_new &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(collision_layer);
+ set_collision_layer(collision_layer_new);
}
bool CollisionObject3D::get_collision_layer_value(int p_layer_number) const {
@@ -339,9 +339,9 @@ void CollisionObject3D::_update_shape_data(uint32_t p_owner) {
void CollisionObject3D::_shape_changed(const Ref<Shape3D> &p_shape) {
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
ShapeData &shapedata = E.value;
- ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- ShapeData::ShapeBase &s = shapes[i];
+ ShapeData::ShapeBase &s = shape_bases[i];
if (s.shape == p_shape && s.debug_shape.is_valid()) {
Ref<Mesh> mesh = s.shape->get_debug_mesh();
RS::get_singleton()->instance_set_base(s.debug_shape, mesh->get_rid());
@@ -359,9 +359,9 @@ void CollisionObject3D::_update_debug_shapes() {
for (const uint32_t &shapedata_idx : debug_shapes_to_update) {
if (shapes.has(shapedata_idx)) {
ShapeData &shapedata = shapes[shapedata_idx];
- ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- ShapeData::ShapeBase &s = shapes[i];
+ ShapeData::ShapeBase &s = shape_bases[i];
if (s.shape.is_null() || shapedata.disabled) {
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
@@ -394,9 +394,9 @@ void CollisionObject3D::_update_debug_shapes() {
void CollisionObject3D::_clear_debug_shapes() {
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
ShapeData &shapedata = E.value;
- ShapeData::ShapeBase *shapes = shapedata.shapes.ptrw();
+ ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptrw();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- ShapeData::ShapeBase &s = shapes[i];
+ ShapeData::ShapeBase &s = shape_bases[i];
if (s.debug_shape.is_valid()) {
RS::get_singleton()->free(s.debug_shape);
s.debug_shape = RID();
@@ -417,9 +417,9 @@ void CollisionObject3D::_on_transform_changed() {
if (shapedata.disabled) {
continue; // If disabled then there are no debug shapes to update.
}
- const ShapeData::ShapeBase *shapes = shapedata.shapes.ptr();
+ const ShapeData::ShapeBase *shape_bases = shapedata.shapes.ptr();
for (int i = 0; i < shapedata.shapes.size(); i++) {
- RS::get_singleton()->instance_set_transform(shapes[i].debug_shape, debug_shape_old_transform * shapedata.xform);
+ RS::get_singleton()->instance_set_transform(shape_bases[i].debug_shape, debug_shape_old_transform * shapedata.xform);
}
}
}
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 7a0001bc6f..ef381641ab 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -62,9 +62,9 @@ void CollisionShape3D::make_convex_from_siblings() {
}
}
- Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D);
- shape->set_points(vertices);
- set_shape(shape);
+ Ref<ConvexPolygonShape3D> shape_new = memnew(ConvexPolygonShape3D);
+ shape_new->set_points(vertices);
+ set_shape(shape_new);
}
void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) {
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index ef373cf9ca..7de685b469 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -1326,24 +1326,24 @@ void CPUParticles3D::_notification(int p_what) {
}
void CPUParticles3D::convert_from_particles(Node *p_particles) {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_particles);
- ERR_FAIL_COND_MSG(!particles, "Only GPUParticles3D nodes can be converted to CPUParticles3D.");
-
- set_emitting(particles->is_emitting());
- set_amount(particles->get_amount());
- set_lifetime(particles->get_lifetime());
- set_one_shot(particles->get_one_shot());
- set_pre_process_time(particles->get_pre_process_time());
- set_explosiveness_ratio(particles->get_explosiveness_ratio());
- set_randomness_ratio(particles->get_randomness_ratio());
- set_use_local_coordinates(particles->get_use_local_coordinates());
- set_fixed_fps(particles->get_fixed_fps());
- set_fractional_delta(particles->get_fractional_delta());
- set_speed_scale(particles->get_speed_scale());
- set_draw_order(DrawOrder(particles->get_draw_order()));
- set_mesh(particles->get_draw_pass_mesh(0));
-
- Ref<ParticleProcessMaterial> material = particles->get_process_material();
+ GPUParticles3D *gpu_particles = Object::cast_to<GPUParticles3D>(p_particles);
+ ERR_FAIL_COND_MSG(!gpu_particles, "Only GPUParticles3D nodes can be converted to CPUParticles3D.");
+
+ set_emitting(gpu_particles->is_emitting());
+ set_amount(gpu_particles->get_amount());
+ set_lifetime(gpu_particles->get_lifetime());
+ set_one_shot(gpu_particles->get_one_shot());
+ set_pre_process_time(gpu_particles->get_pre_process_time());
+ set_explosiveness_ratio(gpu_particles->get_explosiveness_ratio());
+ set_randomness_ratio(gpu_particles->get_randomness_ratio());
+ set_use_local_coordinates(gpu_particles->get_use_local_coordinates());
+ set_fixed_fps(gpu_particles->get_fixed_fps());
+ set_fractional_delta(gpu_particles->get_fractional_delta());
+ set_speed_scale(gpu_particles->get_speed_scale());
+ set_draw_order(DrawOrder(gpu_particles->get_draw_order()));
+ set_mesh(gpu_particles->get_draw_pass_mesh(0));
+
+ Ref<ParticleProcessMaterial> material = gpu_particles->get_process_material();
if (material.is_null()) {
return;
}
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 26c702172b..6b70137736 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -156,7 +156,7 @@ private:
real_t spread = 45.0;
real_t flatness = 0.0;
- real_t parameters_min[PARAM_MAX];
+ real_t parameters_min[PARAM_MAX] = {};
real_t parameters_max[PARAM_MAX] = {};
Ref<Curve> curve_parameters[PARAM_MAX];
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index d3f53d9c0d..2c5df48b75 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -225,23 +225,23 @@ static _FORCE_INLINE_ real_t Vector3_dot2(const Vector3 &p_vec3) {
return p_vec3.dot(p_vec3);
}
-void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance) {
+void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, const BVH *p_bvh, uint32_t p_bvh_cell, const Face3 *p_triangles, float p_thickness, float &r_closest_distance) {
if (p_bvh_cell & BVH::LEAF_BIT) {
p_bvh_cell &= BVH::LEAF_MASK; //remove bit
Vector3 point = p_pos;
- Plane p = triangles[p_bvh_cell].get_plane();
+ Plane p = p_triangles[p_bvh_cell].get_plane();
float d = p.distance_to(point);
float inside_d = 1e20;
- if (d < 0 && d > -thickness) {
+ if (d < 0 && d > -p_thickness) {
//inside planes, do this in 2D
- Vector3 x_axis = (triangles[p_bvh_cell].vertex[0] - triangles[p_bvh_cell].vertex[1]).normalized();
+ Vector3 x_axis = (p_triangles[p_bvh_cell].vertex[0] - p_triangles[p_bvh_cell].vertex[1]).normalized();
Vector3 y_axis = p.normal.cross(x_axis).normalized();
Vector2 points[3];
for (int i = 0; i < 3; i++) {
- points[i] = Vector2(x_axis.dot(triangles[p_bvh_cell].vertex[i]), y_axis.dot(triangles[p_bvh_cell].vertex[i]));
+ points[i] = Vector2(x_axis.dot(p_triangles[p_bvh_cell].vertex[i]), y_axis.dot(p_triangles[p_bvh_cell].vertex[i]));
}
Vector2 p2d = Vector2(x_axis.dot(point), y_axis.dot(point));
@@ -270,19 +270,19 @@ void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, co
//make sure distance to planes is not shorter if inside
if (inside_d < 0) {
inside_d = MAX(inside_d, d);
- inside_d = MAX(inside_d, -(thickness + d));
+ inside_d = MAX(inside_d, -(p_thickness + d));
}
- closest_distance = MIN(closest_distance, inside_d);
+ r_closest_distance = MIN(r_closest_distance, inside_d);
} else {
if (d < 0) {
- point -= p.normal * thickness; //flatten
+ point -= p.normal * p_thickness; //flatten
}
// https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
- Vector3 a = triangles[p_bvh_cell].vertex[0];
- Vector3 b = triangles[p_bvh_cell].vertex[1];
- Vector3 c = triangles[p_bvh_cell].vertex[2];
+ Vector3 a = p_triangles[p_bvh_cell].vertex[0];
+ Vector3 b = p_triangles[p_bvh_cell].vertex[1];
+ Vector3 c = p_triangles[p_bvh_cell].vertex[2];
Vector3 ba = b - a;
Vector3 pa = point - a;
@@ -300,28 +300,28 @@ void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, co
Vector3_dot2(ac * CLAMP(ac.dot(pc) / Vector3_dot2(ac), 0.0, 1.0) - pc))
: nor.dot(pa) * nor.dot(pa) / Vector3_dot2(nor));
- closest_distance = MIN(closest_distance, inside_d);
+ r_closest_distance = MIN(r_closest_distance, inside_d);
}
} else {
bool pass = true;
- if (!bvh[p_bvh_cell].bounds.has_point(p_pos)) {
+ if (!p_bvh[p_bvh_cell].bounds.has_point(p_pos)) {
//outside, find closest point
- Vector3 he = bvh[p_bvh_cell].bounds.size * 0.5;
- Vector3 center = bvh[p_bvh_cell].bounds.position + he;
+ Vector3 he = p_bvh[p_bvh_cell].bounds.size * 0.5;
+ Vector3 center = p_bvh[p_bvh_cell].bounds.position + he;
Vector3 rel = (p_pos - center).abs();
Vector3 closest(MIN(rel.x, he.x), MIN(rel.y, he.y), MIN(rel.z, he.z));
float d = rel.distance_to(closest);
- if (d >= closest_distance) {
+ if (d >= r_closest_distance) {
pass = false; //already closer than this aabb, discard
}
}
if (pass) {
- _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[0], triangles, thickness, closest_distance);
- _find_closest_distance(p_pos, bvh, bvh[p_bvh_cell].children[1], triangles, thickness, closest_distance);
+ _find_closest_distance(p_pos, p_bvh, p_bvh[p_bvh_cell].children[0], p_triangles, p_thickness, r_closest_distance);
+ _find_closest_distance(p_pos, p_bvh, p_bvh[p_bvh_cell].children[1], p_triangles, p_thickness, r_closest_distance);
}
}
}
@@ -473,15 +473,15 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
_create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th);
- Vector<uint8_t> data;
- data.resize(sdf_size.z * sdf_size.y * sdf_size.x * (int)sizeof(float));
+ Vector<uint8_t> cells_data;
+ cells_data.resize(sdf_size.z * sdf_size.y * sdf_size.x * (int)sizeof(float));
if (bake_step_function) {
bake_step_function(0, "Baking SDF");
}
ComputeSDFParams params;
- params.cells = (float *)data.ptrw();
+ params.cells = (float *)cells_data.ptrw();
params.size = sdf_size;
params.cell_size = cell_size;
params.cell_offset = aabb.position + Vector3(cell_size * 0.5, cell_size * 0.5, cell_size * 0.5);
@@ -490,9 +490,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
params.thickness = th;
_compute_sdf(&params);
- Ref<Image> ret;
- ret.instantiate();
- ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, data);
+ Ref<Image> ret = Image::create_from_data(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data);
ret->convert(Image::FORMAT_RH); //convert to half, save space
ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function
@@ -532,7 +530,7 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 548552bb70..25b111c8ff 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -154,7 +154,7 @@ private:
float thickness = 0.0;
};
- void _find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance);
+ void _find_closest_distance(const Vector3 &p_pos, const BVH *p_bvh, uint32_t p_bvh_cell, const Face3 *p_triangles, float p_thickness, float &r_closest_distance);
void _compute_sdf_z(uint32_t p_z, ComputeSDFParams *params);
void _compute_sdf(ComputeSDFParams *params);
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index d977874911..262dc0db37 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -283,14 +283,14 @@ Ref<TriangleMesh> Label3D::generate_triangle_mesh() const {
return Ref<TriangleMesh>();
}
- real_t pixel_size = get_pixel_size();
+ real_t px_size = get_pixel_size();
Vector2 vertices[4] = {
- (final_rect.position + Vector2(0, -final_rect.size.y)) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, -final_rect.size.y)) * pixel_size,
- (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
- final_rect.position * pixel_size,
+ (final_rect.position + Vector2(0, -final_rect.size.y)) * px_size,
+ (final_rect.position + Vector2(final_rect.size.x, -final_rect.size.y)) * px_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * px_size,
+ final_rect.position * px_size,
};
@@ -436,17 +436,17 @@ void Label3D::_shape() {
TS->shaped_text_clear(text_rid);
TS->shaped_text_set_direction(text_rid, text_direction);
- String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
+ TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
TypedArray<Vector2i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
- GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt);
+ GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
- stt = TS->parse_structured_text(st_parser, st_args, text);
+ stt = TS->parse_structured_text(st_parser, st_args, txt);
}
TS->shaped_text_set_bidi_override(text_rid, stt);
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 23fd091be6..198dba7811 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -165,6 +165,16 @@ AABB Light3D::get_aabb() const {
return AABB();
}
+PackedStringArray Light3D::get_configuration_warnings() const {
+ PackedStringArray warnings = VisualInstance3D::get_configuration_warnings();
+
+ if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) {
+ warnings.push_back(RTR("A light's scale does not affect the visual size of the light."));
+ }
+
+ return warnings;
+}
+
void Light3D::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
RS::get_singleton()->light_set_bake_mode(light, RS::LightBakeMode(p_mode));
@@ -579,7 +589,7 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
}
PackedStringArray OmniLight3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Light3D::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) {
warnings.push_back(RTR("Projector texture only works with shadows active."));
@@ -609,7 +619,7 @@ OmniLight3D::OmniLight3D() :
}
PackedStringArray SpotLight3D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
+ PackedStringArray warnings = Light3D::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 8da45bee79..84d214030b 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -147,6 +147,7 @@ public:
Color get_correlated_color() const;
virtual AABB get_aabb() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
Light3D();
~Light3D();
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index cbcbac7b83..1b5427c80d 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -145,10 +145,7 @@ Array LightmapGIData::_get_light_textures_data() const {
for (int i = 0; i < texture_count; i++) {
int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture;
- Ref<Image> texture_image;
- texture_image.instantiate();
-
- texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
+ Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format());
for (int j = 0; j < texture_slice_count; j++) {
texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j));
@@ -818,7 +815,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
md.albedo_on_uv2.instantiate();
- md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
+ md.albedo_on_uv2->set_data(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom);
}
md.emission_on_uv2 = images[RS::BAKE_CHANNEL_EMISSION];
@@ -1054,7 +1051,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
} break;
case ENVIRONMENT_MODE_CUSTOM_COLOR: {
environment_image.instantiate();
- environment_image->create(128, 64, false, Image::FORMAT_RGBAF);
+ environment_image->initialize_data(128, 64, false, Image::FORMAT_RGBAF);
Color c = environment_custom_color;
c.r *= environment_custom_energy;
c.g *= environment_custom_energy;
@@ -1081,13 +1078,13 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
/* POSTBAKE: Save Light Data */
- Ref<LightmapGIData> data;
+ Ref<LightmapGIData> gi_data;
if (get_light_data().is_valid()) {
- data = get_light_data();
+ gi_data = get_light_data();
set_light_data(Ref<LightmapGIData>()); //clear
- data->clear();
+ gi_data->clear();
} else {
- data.instantiate();
+ gi_data.instantiate();
}
Ref<Texture2DArray> texture;
@@ -1101,8 +1098,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
texture->create_from_images(images);
}
- data->set_light_texture(texture);
- data->set_uses_spherical_harmonics(directional);
+ gi_data->set_light_texture(texture);
+ gi_data->set_uses_spherical_harmonics(directional);
for (int i = 0; i < lightmapper->get_bake_mesh_count(); i++) {
Dictionary d = lightmapper->get_bake_mesh_userdata(i);
@@ -1114,7 +1111,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Rect2 uv_scale = lightmapper->get_bake_mesh_uv_scale(i);
int slice_index = lightmapper->get_bake_mesh_texture_slice(i);
- data->add_user(np, uv_scale, slice_index, subindex);
+ gi_data->add_user(np, uv_scale, slice_index, subindex);
}
{
@@ -1247,18 +1244,18 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
/* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */
- data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization);
+ gi_data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization);
/* Compute a BSP tree of the simplices, so it's easy to find the exact one */
}
- data->set_path(p_image_data_path);
- Error err = ResourceSaver::save(data);
+ gi_data->set_path(p_image_data_path);
+ Error err = ResourceSaver::save(gi_data);
if (err != OK) {
return BAKE_ERROR_CANT_CREATE_IMAGE;
}
- set_light_data(data);
+ set_light_data(gi_data);
return BAKE_ERROR_OK;
}
@@ -1286,9 +1283,9 @@ void LightmapGI::_assign_lightmaps() {
Node *node = get_node(light_data->get_user_path(i));
int instance_idx = light_data->get_user_sub_instance(i);
if (instance_idx >= 0) {
- RID instance = node->call("get_bake_mesh_instance", instance_idx);
- if (instance.is_valid()) {
- RS::get_singleton()->instance_geometry_set_lightmap(instance, get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
+ RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance_id.is_valid()) {
+ RS::get_singleton()->instance_geometry_set_lightmap(instance_id, get_instance(), light_data->get_user_lightmap_uv_scale(i), light_data->get_user_lightmap_slice_index(i));
}
} else {
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
@@ -1304,9 +1301,9 @@ void LightmapGI::_clear_lightmaps() {
Node *node = get_node(light_data->get_user_path(i));
int instance_idx = light_data->get_user_sub_instance(i);
if (instance_idx >= 0) {
- RID instance = node->call("get_bake_mesh_instance", instance_idx);
- if (instance.is_valid()) {
- RS::get_singleton()->instance_geometry_set_lightmap(instance, RID(), Rect2(), 0);
+ RID instance_id = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance_id.is_valid()) {
+ RS::get_singleton()->instance_geometry_set_lightmap(instance_id, RID(), Rect2(), 0);
}
} else {
VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(node);
diff --git a/scene/3d/marker_3d.cpp b/scene/3d/marker_3d.cpp
index 3987172561..8e5998d14f 100644
--- a/scene/3d/marker_3d.cpp
+++ b/scene/3d/marker_3d.cpp
@@ -30,5 +30,24 @@
#include "marker_3d.h"
+void Marker3D::set_gizmo_extents(real_t p_extents) {
+ if (Math::is_equal_approx(gizmo_extents, p_extents)) {
+ return;
+ }
+ gizmo_extents = p_extents;
+ update_gizmos();
+}
+
+real_t Marker3D::get_gizmo_extents() const {
+ return gizmo_extents;
+}
+
+void Marker3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Marker3D::set_gizmo_extents);
+ ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Marker3D::get_gizmo_extents);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater,suffix:m"), "set_gizmo_extents", "get_gizmo_extents");
+}
+
Marker3D::Marker3D() {
}
diff --git a/scene/3d/marker_3d.h b/scene/3d/marker_3d.h
index 95caa101c5..a9bd993476 100644
--- a/scene/3d/marker_3d.h
+++ b/scene/3d/marker_3d.h
@@ -36,7 +36,15 @@
class Marker3D : public Node3D {
GDCLASS(Marker3D, Node3D);
+ real_t gizmo_extents = 0.25;
+
+protected:
+ static void _bind_methods();
+
public:
+ void set_gizmo_extents(real_t p_extents);
+ real_t get_gizmo_extents() const;
+
Marker3D();
};
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index a76f4dd0d5..d4f60503c2 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -346,9 +346,9 @@ Ref<Material> MeshInstance3D::get_surface_override_material(int p_surface) const
}
Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
- Ref<Material> material_override = get_material_override();
- if (material_override.is_valid()) {
- return material_override;
+ Ref<Material> mat_override = get_material_override();
+ if (mat_override.is_valid()) {
+ return mat_override;
}
Ref<Material> surface_material = get_surface_override_material(p_surface);
@@ -356,9 +356,9 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const {
return surface_material;
}
- Ref<Mesh> mesh = get_mesh();
- if (mesh.is_valid()) {
- return mesh->surface_get_material(p_surface);
+ Ref<Mesh> m = get_mesh();
+ if (m.is_valid()) {
+ return m->surface_get_material(p_surface);
}
return Ref<Material>();
@@ -390,17 +390,17 @@ void MeshInstance3D::_mesh_changed() {
update_gizmos();
}
-void MeshInstance3D::create_debug_tangents() {
+MeshInstance3D *MeshInstance3D::create_debug_tangents_node() {
Vector<Vector3> lines;
Vector<Color> colors;
- Ref<Mesh> mesh = get_mesh();
- if (!mesh.is_valid()) {
- return;
+ Ref<Mesh> m = get_mesh();
+ if (!m.is_valid()) {
+ return nullptr;
}
- for (int i = 0; i < mesh->get_surface_count(); i++) {
- Array arrays = mesh->surface_get_arrays(i);
+ for (int i = 0; i < m->get_surface_count(); i++) {
+ Array arrays = m->surface_get_arrays(i);
ERR_CONTINUE(arrays.size() != Mesh::ARRAY_MAX);
Vector<Vector3> verts = arrays[Mesh::ARRAY_VERTEX];
@@ -457,15 +457,23 @@ void MeshInstance3D::create_debug_tangents() {
MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_mesh(am);
mi->set_name("DebugTangents");
- add_child(mi, true);
-#ifdef TOOLS_ENABLED
+ return mi;
+ }
- if (is_inside_tree() && this == get_tree()->get_edited_scene_root()) {
- mi->set_owner(this);
- } else {
- mi->set_owner(get_owner());
- }
-#endif
+ return nullptr;
+}
+
+void MeshInstance3D::create_debug_tangents() {
+ MeshInstance3D *mi = create_debug_tangents_node();
+ if (!mi) {
+ return;
+ }
+
+ add_child(mi, true);
+ if (is_inside_tree() && this == get_tree()->get_edited_scene_root()) {
+ mi->set_owner(this);
+ } else {
+ mi->set_owner(get_owner());
}
}
@@ -495,8 +503,6 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_blend_shape_value", "blend_shape_idx", "value"), &MeshInstance3D::set_blend_shape_value);
ClassDB::bind_method(D_METHOD("create_debug_tangents"), &MeshInstance3D::create_debug_tangents);
- ClassDB::set_method_flags("MeshInstance3D", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
ADD_GROUP("Skeleton", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index 48d76b9a88..caf7d25616 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -90,6 +90,7 @@ public:
Node *create_multiple_convex_collisions_node();
void create_multiple_convex_collisions();
+ MeshInstance3D *create_debug_tangents_node();
void create_debug_tangents();
virtual AABB get_aabb() const override;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 39068fe83c..36350d251e 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -79,6 +79,7 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent3D::set_target_location);
ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent3D::get_target_location);
+
ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent3D::get_next_location);
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent3D::distance_to_target);
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent3D::set_velocity);
@@ -92,6 +93,7 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done);
ADD_GROUP("Pathfinding", "");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_location", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_location", "get_target_location");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_path_desired_distance", "get_path_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset");
@@ -495,8 +497,8 @@ void NavigationAgent3D::_request_repath() {
void NavigationAgent3D::_check_distance_to_target() {
if (!target_reached) {
if (distance_to_target() < target_desired_distance) {
- emit_signal(SNAME("target_reached"));
target_reached = true;
+ emit_signal(SNAME("target_reached"));
}
}
}
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 07d8cd9289..f241d65649 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -159,7 +159,7 @@ void NavigationObstacle3D::reevaluate_agent_radius() {
real_t NavigationObstacle3D::estimate_agent_radius() const {
if (parent_node3d && parent_node3d->is_inside_tree()) {
// Estimate the radius of this physics body
- real_t radius = 0.0;
+ real_t max_radius = 0.0;
for (int i(0); i < parent_node3d->get_child_count(); i++) {
// For each collision shape
CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(parent_node3d->get_child(i));
@@ -173,7 +173,7 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
Vector3 s = cs->get_global_transform().basis.get_scale();
r *= MAX(s.x, MAX(s.y, s.z));
// Takes the biggest radius
- radius = MAX(radius, r);
+ max_radius = MAX(max_radius, r);
} else if (cs && !cs->is_inside_tree()) {
WARN_PRINT("A CollisionShape3D of the NavigationObstacle3D parent node was not inside the SceneTree when estimating the obstacle radius."
"\nMove the NavigationObstacle3D to a child position below any CollisionShape3D node of the parent node so the CollisionShape3D is already inside the SceneTree.");
@@ -181,10 +181,10 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
}
Vector3 s = parent_node3d->get_global_transform().basis.get_scale();
- radius *= MAX(s.x, MAX(s.y, s.z));
+ max_radius *= MAX(s.x, MAX(s.y, s.z));
- if (radius > 0.0) {
- return radius;
+ if (max_radius > 0.0) {
+ return max_radius;
}
}
return 1.0; // Never a 0 radius
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 12d2e66b41..1743fa1838 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -253,9 +253,7 @@ Vector3 Node3D::get_global_rotation() const {
void Node3D::set_global_rotation(const Vector3 &p_euler_rad) {
Transform3D transform = get_global_transform();
- Basis new_basis = transform.get_basis();
- new_basis.set_euler(p_euler_rad);
- transform.set_basis(new_basis);
+ transform.basis = Basis::from_euler(p_euler_rad);
set_global_transform(transform);
}
@@ -1054,7 +1052,7 @@ void Node3D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,hide_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index 90c7bc89ef..457f634c34 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -71,8 +71,8 @@ public:
};
private:
- // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale.
- // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
+ // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale.
+ // Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand).
// Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users
// editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support
// "redundant" rotations for animation interpolation, like going from 0 to 720 degrees).
@@ -96,6 +96,7 @@ private:
mutable SelfList<Node> xform_change;
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
mutable Transform3D global_transform;
mutable Transform3D local_transform;
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 123a044b84..ab4cba86fb 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -348,8 +348,8 @@ PackedStringArray PathFollow3D::get_configuration_warnings() const {
if (!Object::cast_to<Path3D>(get_parent())) {
warnings.push_back(RTR("PathFollow3D only works when set as a child of a Path3D node."));
} else {
- Path3D *path = Object::cast_to<Path3D>(get_parent());
- if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
+ Path3D *p = Object::cast_to<Path3D>(get_parent());
+ if (p->get_curve().is_valid() && !p->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) {
warnings.push_back(RTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));
}
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 594e94644c..d9fa37ce74 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -522,28 +522,28 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
//put the ones to add
for (int i = 0; i < p_state->get_contact_count(); i++) {
- RID rid = p_state->get_contact_collider(i);
- ObjectID obj = p_state->get_contact_collider_id(i);
+ RID col_rid = p_state->get_contact_collider(i);
+ ObjectID col_obj = p_state->get_contact_collider_id(i);
int local_shape = p_state->get_contact_local_shape(i);
- int shape = p_state->get_contact_collider_shape(i);
+ int col_shape = p_state->get_contact_collider_shape(i);
- HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(obj);
+ HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(col_obj);
if (!E) {
- toadd[toadd_count].rid = rid;
+ toadd[toadd_count].rid = col_rid;
toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
+ toadd[toadd_count].id = col_obj;
+ toadd[toadd_count].shape = col_shape;
toadd_count++;
continue;
}
- ShapePair sp(shape, local_shape);
+ ShapePair sp(col_shape, local_shape);
int idx = E->value.shapes.find(sp);
if (idx == -1) {
- toadd[toadd_count].rid = rid;
+ toadd[toadd_count].rid = col_rid;
toadd[toadd_count].local_shape = local_shape;
- toadd[toadd_count].id = obj;
- toadd[toadd_count].shape = shape;
+ toadd[toadd_count].id = col_obj;
+ toadd[toadd_count].shape = col_shape;
toadd_count++;
continue;
}
@@ -1200,6 +1200,7 @@ bool CharacterBody3D::move_and_slide() {
if (!current_platform_velocity.is_zero_approx()) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.exclude_bodies.insert(platform_rid);
if (platform_object_id.is_valid()) {
@@ -1264,6 +1265,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 = 6; // There can be 4 collisions between 2 walls + 2 more for the floor.
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
PhysicsServer3D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
@@ -1508,6 +1510,7 @@ 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);
@@ -1562,7 +1565,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; // Report margin recovery as collision to improve floor detection.
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result;
@@ -1598,7 +1601,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; // Report margin recovery as collision to improve floor detection.
+ parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result;
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index a45ef52452..45ff0a4b45 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -516,7 +516,7 @@ void RayCast3D::_clear_debug_shape() {
MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
if (mi->is_inside_tree()) {
- mi->queue_delete();
+ mi->queue_free();
} else {
memdelete(mi);
}
diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp
index e7d1a8ec7d..03cbd984cd 100644
--- a/scene/3d/shape_cast_3d.cpp
+++ b/scene/3d/shape_cast_3d.cpp
@@ -619,7 +619,7 @@ void ShapeCast3D::_clear_debug_shape() {
MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape);
if (mi->is_inside_tree()) {
- mi->queue_delete();
+ mi->queue_free();
} else {
memdelete(mi);
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 85b2c5154b..a1f962c690 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -888,10 +888,14 @@ void _pb_start_simulation(const Skeleton3D *p_skeleton, Node *p_node, const Vect
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
- for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
- if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
- pb->set_simulate_physics(true);
- break;
+ if (p_sim_bones.is_empty()) { // If no bones is specified, activate ragdoll on full body.
+ pb->set_simulate_physics(true);
+ } else {
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ pb->set_simulate_physics(true);
+ break;
+ }
}
}
}
@@ -901,9 +905,7 @@ void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName>
set_physics_process_internal(false);
Vector<int> sim_bones;
- if (p_bones.size() <= 0) {
- sim_bones.push_back(0); // If no bones is specified, activate ragdoll on full body.
- } else {
+ if (p_bones.size() > 0) {
sim_bones.resize(p_bones.size());
int c = 0;
for (int i = sim_bones.size() - 1; 0 <= i; --i) {
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index 2466b71aea..83e3369423 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -523,13 +523,13 @@ uint32_t SoftBody3D::get_collision_layer() const {
void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t collision_layer = get_collision_layer();
+ uint32_t collision_layer_new = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << (p_layer_number - 1);
+ collision_layer_new |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << (p_layer_number - 1));
+ collision_layer_new &= ~(1 << (p_layer_number - 1));
}
- set_collision_layer(collision_layer);
+ set_collision_layer(collision_layer_new);
}
bool SoftBody3D::get_collision_layer_value(int p_layer_number) const {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 4b83bcdfc4..d69953fee5 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -118,14 +118,14 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
Color color = _get_color_accum();
- real_t pixel_size = get_pixel_size();
+ real_t px_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,
+ (final_rect.position + Vector2(0, final_rect.size.y)) * px_size,
+ (final_rect.position + final_rect.size) * px_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * px_size,
+ final_rect.position * px_size,
};
Vector2 src_tsize = p_texture->get_size();
@@ -156,34 +156,34 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
}
Vector3 normal;
- int axis = get_axis();
- normal[axis] = 1.0;
+ int ax = get_axis();
+ normal[ax] = 1.0;
Plane tangent;
- if (axis == Vector3::AXIS_X) {
+ if (ax == 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);
+ int x_axis = ((ax + 1) % 3);
+ int y_axis = ((ax + 2) % 3);
- if (axis != Vector3::AXIS_Z) {
+ if (ax != 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) {
+ if (ax == Vector3::AXIS_Y) {
vertices[i].y = -vertices[i].y;
- } else if (axis == Vector3::AXIS_X) {
+ } else if (ax == Vector3::AXIS_X) {
vertices[i].x = -vertices[i].x;
}
}
}
- AABB aabb;
+ AABB aabb_new;
// Everything except position and UV is compressed.
uint8_t *vertex_write_buffer = vertex_buffer.ptrw();
@@ -223,10 +223,10 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
vtx[x_axis] = vertices[i][0];
vtx[y_axis] = vertices[i][1];
if (i == 0) {
- aabb.position = vtx;
- aabb.size = Vector3();
+ aabb_new.position = vtx;
+ aabb_new.size = Vector3();
} else {
- aabb.expand_to(vtx);
+ aabb_new.expand_to(vtx);
}
float v_uv[2] = { (float)uvs[i].x, (float)uvs[i].y };
@@ -240,12 +240,12 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
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);
+ RID mesh_new = get_mesh();
+ RS::get_singleton()->mesh_surface_update_vertex_region(mesh_new, 0, 0, vertex_buffer);
+ RS::get_singleton()->mesh_surface_update_attribute_region(mesh_new, 0, 0, attribute_buffer);
- RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
- set_aabb(aabb);
+ RS::get_singleton()->mesh_set_custom_aabb(mesh_new, aabb_new);
+ set_aabb(aabb_new);
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);
@@ -378,14 +378,14 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
return Ref<TriangleMesh>();
}
- real_t pixel_size = get_pixel_size();
+ real_t px_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,
+ (final_rect.position + Vector2(0, final_rect.size.y)) * px_size,
+ (final_rect.position + final_rect.size) * px_size,
+ (final_rect.position + Vector2(final_rect.size.x, 0)) * px_size,
+ final_rect.position * px_size,
};
@@ -680,6 +680,7 @@ void Sprite3D::set_region_enabled(bool p_region) {
region = p_region;
_queue_redraw();
+ notify_property_list_changed();
}
bool Sprite3D::is_region_enabled() const {
@@ -781,6 +782,10 @@ void Sprite3D::_validate_property(PropertyInfo &p_property) const {
if (p_property.name == "frame_coords") {
p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (!region && (p_property.name == "region_rect")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
void Sprite3D::_bind_methods() {
@@ -810,7 +815,7 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect");
diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp
index bcf294e216..6d4c18a69e 100644
--- a/scene/3d/visible_on_screen_notifier_3d.cpp
+++ b/scene/3d/visible_on_screen_notifier_3d.cpp
@@ -95,10 +95,11 @@ VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() {
RS::get_singleton()->visibility_notifier_set_callbacks(notifier, callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_exit));
set_base(notifier);
}
+
VisibleOnScreenNotifier3D::~VisibleOnScreenNotifier3D() {
- RID base = get_base();
+ RID base_old = get_base();
set_base(RID());
- RS::get_singleton()->free(base);
+ RS::get_singleton()->free(base_old);
}
//////////////////////////////////////
@@ -188,7 +189,7 @@ void VisibleOnScreenEnabler3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler3D::get_enable_node_path);
ADD_GROUP("Enabling", "enable_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,When Paused"), "set_enable_mode", "get_enable_mode");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path");
BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT);
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index e93ad5ecbf..8f5a51eff6 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -34,14 +34,8 @@
AABB VisualInstance3D::get_aabb() const {
AABB ret;
- if (GDVIRTUAL_CALL(_get_aabb, ret)) {
- return ret;
- }
- return AABB();
-}
-
-AABB VisualInstance3D::get_transformed_aabb() const {
- return get_global_transform().xform(get_aabb());
+ GDVIRTUAL_CALL(_get_aabb, ret);
+ return ret;
}
void VisualInstance3D::_update_visibility() {
@@ -121,8 +115,6 @@ void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value);
ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value);
- ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb);
-
GDVIRTUAL_BIND(_get_aabb);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask");
}
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 4755545516..06a8c05faa 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -60,8 +60,6 @@ public:
RID get_instance() const;
virtual AABB get_aabb() const;
- virtual AABB get_transformed_aabb() const; // helper
-
void set_base(const RID &p_base);
RID get_base() const;
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index c2728960ee..7caf2f4874 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -46,8 +46,8 @@ void VoxelGIData::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("level_counts"));
ERR_FAIL_COND(!p_data.has("to_cell_xform"));
- AABB bounds = p_data["bounds"];
- Vector3 octree_size = p_data["octree_size"];
+ AABB bounds_new = p_data["bounds"];
+ Vector3 octree_size_new = p_data["octree_size"];
Vector<uint8_t> octree_cells = p_data["octree_cells"];
Vector<uint8_t> octree_data = p_data["octree_data"];
@@ -64,9 +64,9 @@ void VoxelGIData::_set_data(const Dictionary &p_data) {
octree_df = img->get_data();
}
Vector<int> octree_levels = p_data["level_counts"];
- Transform3D to_cell_xform = p_data["to_cell_xform"];
+ Transform3D to_cell_xform_new = p_data["to_cell_xform"];
- allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels);
+ allocate(to_cell_xform_new, bounds_new, octree_size_new, octree_cells, octree_data, octree_df, octree_levels);
}
Dictionary VoxelGIData::_get_data() const {
@@ -77,9 +77,7 @@ Dictionary VoxelGIData::_get_data() const {
d["octree_cells"] = get_octree_cells();
d["octree_data"] = get_data_cells();
if (otsize != Vector3i()) {
- Ref<Image> img;
- img.instantiate();
- img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
+ Ref<Image> img = Image::create_from_data(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field());
Vector<uint8_t> df_png = img->save_png_to_buffer();
ERR_FAIL_COND_V(df_png.size() == 0, Dictionary());
d["octree_df_png"] = df_png;
@@ -435,10 +433,10 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
#endif
} else {
- Ref<VoxelGIData> probe_data = get_probe_data();
+ Ref<VoxelGIData> probe_data_new = get_probe_data();
- if (probe_data.is_null()) {
- probe_data.instantiate();
+ if (probe_data_new.is_null()) {
+ probe_data_new.instantiate();
}
if (bake_step_function) {
@@ -447,13 +445,13 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
Vector<uint8_t> df = baker.get_sdf_3d_image();
- RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data->get_rid(), exposure_normalization);
+ RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
- probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
+ probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
- set_probe_data(probe_data);
+ set_probe_data(probe_data_new);
#ifdef TOOLS_ENABLED
- probe_data->set_edited(true); //so it gets saved
+ probe_data_new->set_edited(true); //so it gets saved
#endif
}
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 4401d22f30..f5d30c584f 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -36,49 +36,37 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
-void XRCamera3D::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- // need to find our XROrigin3D parent and let it know we're its camera!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin != nullptr) {
- origin->set_tracked_camera(this);
- }
- } break;
+void XRCamera3D::_bind_tracker() {
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL(xr_server);
- case NOTIFICATION_EXIT_TREE: {
- // need to find our XROrigin3D parent and let it know we're no longer its camera!
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
- if (origin != nullptr && origin->get_tracked_camera() == this) {
- origin->set_tracked_camera(nullptr);
- }
- } break;
+ tracker = xr_server->get_tracker(tracker_name);
+ if (tracker.is_valid()) {
+ tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+
+ Ref<XRPose> pose = tracker->get_pose(pose_name);
+ if (pose.is_valid()) {
+ set_transform(pose->get_adjusted_transform());
+ }
}
}
+void XRCamera3D::_unbind_tracker() {
+ if (tracker.is_valid()) {
+ tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
+ }
+ tracker.unref();
+}
+
void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
-
- tracker = xr_server->get_tracker(p_tracker_name);
- if (tracker.is_valid()) {
- tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
-
- Ref<XRPose> pose = tracker->get_pose(pose_name);
- if (pose.is_valid()) {
- set_transform(pose->get_adjusted_transform());
- }
- }
+ _bind_tracker();
}
}
void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
if (p_tracker_name == tracker_name) {
- if (tracker.is_valid()) {
- tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
- }
- tracker.unref();
+ _unbind_tracker();
}
}
@@ -213,6 +201,9 @@ XRCamera3D::XRCamera3D() {
xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
+
+ // check if our tracker already exists and if so, bind it...
+ _bind_tracker();
}
XRCamera3D::~XRCamera3D() {
@@ -372,7 +363,7 @@ void XRNode3D::_unbind_tracker() {
}
void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// just in case unref our current tracker
_unbind_tracker();
@@ -382,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t
}
void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
- if (p_tracker_name == p_tracker_name) {
+ if (tracker_name == p_tracker_name) {
// unref our tracker, it's no longer available
_unbind_tracker();
}
@@ -582,11 +573,22 @@ Plane XRAnchor3D::get_plane() const {
////////////////////////////////////////////////////////////////////////////////////////////////////
+Vector<XROrigin3D *> XROrigin3D::origin_nodes;
+
PackedStringArray XROrigin3D::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
if (is_visible() && is_inside_tree()) {
- if (tracked_camera == nullptr) {
+ bool has_camera = false;
+ for (int i = 0; !has_camera && i < get_child_count(); i++) {
+ XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_child(i));
+ if (camera) {
+ // found it!
+ has_camera = true;
+ }
+ }
+
+ if (!has_camera) {
warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node."));
}
}
@@ -603,14 +605,10 @@ void XROrigin3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
-}
-void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
- tracked_camera = p_tracked_camera;
-}
-
-XRCamera3D *XROrigin3D::get_tracked_camera() const {
- return tracked_camera;
+ ClassDB::bind_method(D_METHOD("set_current", "enabled"), &XROrigin3D::set_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &XROrigin3D::is_current);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
}
real_t XROrigin3D::get_world_scale() const {
@@ -629,6 +627,44 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) {
xr_server->set_world_scale(p_world_scale);
}
+void XROrigin3D::set_current(bool p_enabled) {
+ current = p_enabled;
+
+ if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+
+ // Notify us of any transform changes
+ set_notify_local_transform(current);
+ set_notify_transform(current);
+
+ if (current) {
+ for (int i = 0; i < origin_nodes.size(); i++) {
+ if (origin_nodes[i] != this) {
+ origin_nodes[i]->set_current(false);
+ }
+ }
+ } else {
+ bool found = false;
+ // We no longer have a current origin so find the first one we can make current
+ for (int i = 0; !found && i < origin_nodes.size(); i++) {
+ if (origin_nodes[i] != this) {
+ origin_nodes[i]->set_current(true);
+ found = true;
+ }
+ }
+ }
+}
+
+bool XROrigin3D::is_current() const {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // return as is
+ return current;
+ } else {
+ return current && is_inside_tree();
+ }
+}
+
void XROrigin3D::_notification(int p_what) {
// get our XRServer
XRServer *xr_server = XRServer::get_singleton();
@@ -636,34 +672,47 @@ void XROrigin3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- set_process_internal(true);
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ if (origin_nodes.is_empty()) {
+ // first entry always becomes current
+ current = true;
+ }
+
+ origin_nodes.push_back(this);
+
+ if (current) {
+ // set this again so we do whatever setup is needed.
+ set_current(true);
+ }
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
- } break;
-
- case NOTIFICATION_INTERNAL_PROCESS: {
- // set our world origin to our node transform
- xr_server->set_world_origin(get_global_transform());
+ if (!Engine::get_singleton()->is_editor_hint()) {
+ origin_nodes.erase(this);
- // check if we have a primary interface
- Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
- if (xr_interface.is_valid() && tracked_camera != nullptr) {
- // get our positioning transform for our headset
- Transform3D t = xr_interface->get_camera_transform();
+ if (current) {
+ // We are no longer current
+ set_current(false);
+ }
+ }
+ } break;
- // now apply this to our camera
- tracked_camera->set_transform(t);
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED:
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (current && !Engine::get_singleton()->is_editor_hint()) {
+ xr_server->set_world_origin(get_global_transform());
}
} break;
}
- // send our notification to all active XE interfaces, they may need to react to it also
- for (int i = 0; i < xr_server->get_interface_count(); i++) {
- Ref<XRInterface> interface = xr_server->get_interface(i);
- if (interface.is_valid() && interface->is_initialized()) {
- interface->notification(p_what);
+ if (current) {
+ // send our notification to all active XE interfaces, they may need to react to it also
+ for (int i = 0; i < xr_server->get_interface_count(); i++) {
+ Ref<XRInterface> interface = xr_server->get_interface(i);
+ if (interface.is_valid() && interface->is_initialized()) {
+ interface->notification(p_what);
+ }
}
}
}
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index ef846cc3a3..990fb61983 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -48,8 +48,8 @@ protected:
StringName pose_name = "default";
Ref<XRPositionalTracker> tracker;
- void _notification(int p_what);
-
+ void _bind_tracker();
+ void _unbind_tracker();
void _changed_tracker(const StringName p_tracker_name, int p_tracker_type);
void _removed_tracker(const StringName p_tracker_name, int p_tracker_type);
void _pose_changed(const Ref<XRPose> &p_pose);
@@ -180,7 +180,8 @@ class XROrigin3D : public Node3D {
GDCLASS(XROrigin3D, Node3D);
private:
- XRCamera3D *tracked_camera = nullptr;
+ bool current = false;
+ static Vector<XROrigin3D *> origin_nodes; // all origin nodes in tree
protected:
void _notification(int p_what);
@@ -189,12 +190,12 @@ protected:
public:
PackedStringArray get_configuration_warnings() const override;
- void set_tracked_camera(XRCamera3D *p_tracked_camera);
- XRCamera3D *get_tracked_camera() const;
-
real_t get_world_scale() const;
void set_world_scale(real_t p_world_scale);
+ void set_current(bool p_enabled);
+ bool is_current() const;
+
XROrigin3D() {}
~XROrigin3D() {}
};
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 2dc61efb94..0d8b7ba8f7 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -343,10 +343,10 @@ void AnimationNodeBlendSpace2D::_update_triangles() {
points.write[i] = blend_points[i].position;
}
- Vector<Delaunay2D::Triangle> triangles = Delaunay2D::triangulate(points);
+ Vector<Delaunay2D::Triangle> tr = Delaunay2D::triangulate(points);
- for (int i = 0; i < triangles.size(); i++) {
- add_triangle(triangles[i].points[0], triangles[i].points[1], triangles[i].points[2]);
+ for (int i = 0; i < tr.size(); i++) {
+ add_triangle(tr[i].points[0], tr[i].points[1], tr[i].points[2]);
}
emit_signal(SNAME("triangles_updated"));
}
@@ -376,9 +376,9 @@ Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) {
points[j],
points[(j + 1) % 3]
};
- Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, s);
- if (first || closest.distance_to(p_point) < best_point.distance_to(p_point)) {
- best_point = closest;
+ Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, s);
+ if (first || closest_point.distance_to(p_point) < best_point.distance_to(p_point)) {
+ best_point = closest_point;
first = false;
}
}
@@ -436,8 +436,8 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
_update_triangles();
Vector2 blend_pos = get_parameter(blend_position);
- int closest = get_parameter(this->closest);
- double length_internal = get_parameter(this->length_internal);
+ int cur_closest = get_parameter(closest);
+ double cur_length_internal = get_parameter(length_internal);
double mind = 0.0; //time of min distance point
if (blend_mode == BLEND_MODE_INTERPOLATED) {
@@ -528,37 +528,37 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_see
}
}
- if (new_closest != closest && new_closest != -1) {
+ if (new_closest != cur_closest && new_closest != -1) {
double from = 0.0;
- if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) {
+ if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
//for ping-pong loop
- Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[closest].node);
+ Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
if (!na_c.is_null() && !na_n.is_null()) {
na_n->set_backward(na_c->is_backward());
}
//see how much animation remains
- from = length_internal - blend_node(blend_points[closest].name, blend_points[closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, true);
+ from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_seek_root, 0.0, FILTER_IGNORE, true);
}
mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_seek_root, 1.0, FILTER_IGNORE, true);
- length_internal = from + mind;
+ cur_length_internal = from + mind;
- closest = new_closest;
+ cur_closest = new_closest;
} else {
- mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
}
for (int i = 0; i < blend_points_used; i++) {
- if (i != closest) {
+ if (i != cur_closest) {
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
}
}
}
- set_parameter(this->closest, closest);
- set_parameter(this->length_internal, length_internal);
+ set_parameter(this->closest, cur_closest);
+ set_parameter(this->length_internal, cur_length_internal);
return mind;
}
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index c063d8f1bf..0c91729a6f 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -68,13 +68,13 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r
AnimationPlayer *ap = state->player;
ERR_FAIL_COND_V(!ap, 0);
- double time = get_parameter(this->time);
+ double cur_time = get_parameter(time);
if (!ap->has_animation(animation)) {
AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent);
if (tree) {
- String name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
- make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), name, animation));
+ String node_name = tree->get_node_name(Ref<AnimationNodeAnimation>(this));
+ make_invalid(vformat(RTR("On BlendTree node '%s', animation not found: '%s'"), node_name, animation));
} else {
make_invalid(vformat(RTR("Animation not found: '%s'"), animation));
@@ -86,58 +86,58 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_seek_r
Ref<Animation> anim = ap->get_animation(animation);
double anim_size = (double)anim->get_length();
double step = 0.0;
- double prev_time = time;
+ double prev_time = cur_time;
int pingponged = 0;
bool current_backward = signbit(p_time);
if (p_seek) {
- step = p_time - time;
- time = p_time;
+ step = p_time - cur_time;
+ cur_time = p_time;
} else {
p_time *= backward ? -1.0 : 1.0;
- if (!(time == anim_size && !current_backward) && !(time == 0 && current_backward)) {
- time = time + p_time;
+ if (!(cur_time == anim_size && !current_backward) && !(cur_time == 0 && current_backward)) {
+ cur_time = cur_time + p_time;
step = p_time;
}
}
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
if (!Math::is_zero_approx(anim_size)) {
- if ((int)Math::floor(abs(time - prev_time) / anim_size) % 2 == 0) {
- if (prev_time >= 0 && time < 0) {
+ if ((int)Math::floor(abs(cur_time - prev_time) / anim_size) % 2 == 0) {
+ if (prev_time >= 0 && cur_time < 0) {
backward = !backward;
pingponged = -1;
}
- if (prev_time <= anim_size && time > anim_size) {
+ if (prev_time <= anim_size && cur_time > anim_size) {
backward = !backward;
pingponged = 1;
}
}
- time = Math::pingpong(time, anim_size);
+ cur_time = Math::pingpong(cur_time, anim_size);
}
} else {
if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
if (!Math::is_zero_approx(anim_size)) {
- time = Math::fposmod(time, anim_size);
+ cur_time = Math::fposmod(cur_time, anim_size);
}
- } else if (time < 0) {
- step += time;
- time = 0;
- } else if (time > anim_size) {
- step += anim_size - time;
- time = anim_size;
+ } else if (cur_time < 0) {
+ step += cur_time;
+ cur_time = 0;
+ } else if (cur_time > anim_size) {
+ step += anim_size - cur_time;
+ cur_time = anim_size;
}
backward = false;
}
if (play_mode == PLAY_MODE_FORWARD) {
- blend_animation(animation, time, step, p_seek, p_seek_root, 1.0, pingponged);
+ blend_animation(animation, cur_time, step, p_seek, p_seek_root, 1.0, pingponged);
} else {
- blend_animation(animation, anim_size - time, -step, p_seek, p_seek_root, 1.0, pingponged);
+ blend_animation(animation, anim_size - cur_time, -step, p_seek, p_seek_root, 1.0, pingponged);
}
- set_parameter(this->time, time);
+ set_parameter(time, cur_time);
- return anim_size - time;
+ return anim_size - cur_time;
}
String AnimationNodeAnimation::get_caption() const {
@@ -274,28 +274,28 @@ bool AnimationNodeOneShot::has_filter() const {
}
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_root) {
- bool active = get_parameter(this->active);
- bool prev_active = get_parameter(this->prev_active);
- double time = get_parameter(this->time);
- double remaining = get_parameter(this->remaining);
- double time_to_restart = get_parameter(this->time_to_restart);
+ bool cur_active = get_parameter(active);
+ bool cur_prev_active = get_parameter(prev_active);
+ double cur_time = get_parameter(time);
+ double cur_remaining = get_parameter(remaining);
+ double cur_time_to_restart = get_parameter(time_to_restart);
- if (!active) {
+ if (!cur_active) {
//make it as if this node doesn't exist, pass input 0 by.
- if (prev_active) {
- set_parameter(this->prev_active, false);
+ if (cur_prev_active) {
+ set_parameter(prev_active, false);
}
- if (time_to_restart >= 0.0 && !p_seek) {
- time_to_restart -= p_time;
- if (time_to_restart < 0) {
+ if (cur_time_to_restart >= 0.0 && !p_seek) {
+ cur_time_to_restart -= p_time;
+ if (cur_time_to_restart < 0) {
//restart
- set_parameter(this->active, true);
- active = true;
+ set_parameter(active, true);
+ cur_active = true;
}
- set_parameter(this->time_to_restart, time_to_restart);
+ set_parameter(time_to_restart, cur_time_to_restart);
}
- if (!active) {
+ if (!cur_active) {
return blend_input(0, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, sync);
}
}
@@ -303,27 +303,27 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
bool os_seek = p_seek;
if (p_seek) {
- time = p_time;
+ cur_time = p_time;
}
- bool do_start = !prev_active;
+ bool do_start = !cur_prev_active;
if (do_start) {
- time = 0;
+ cur_time = 0;
os_seek = true;
- set_parameter(this->prev_active, true);
+ set_parameter(prev_active, true);
}
real_t blend;
- if (time < fade_in) {
+ if (cur_time < fade_in) {
if (fade_in > 0) {
- blend = time / fade_in;
+ blend = cur_time / fade_in;
} else {
blend = 0;
}
- } else if (!do_start && remaining <= fade_out) {
+ } else if (!do_start && cur_remaining <= fade_out) {
if (fade_out > 0) {
- blend = (remaining / fade_out);
+ blend = (cur_remaining / fade_out);
} else {
blend = 0;
}
@@ -338,29 +338,29 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_seek_roo
main_rem = blend_input(0, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_BLEND, sync);
}
- double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
+ double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_seek_root, blend, FILTER_PASS, true);
if (do_start) {
- remaining = os_rem;
+ cur_remaining = os_rem;
}
if (!p_seek) {
- time += p_time;
- remaining = os_rem;
- if (remaining <= 0) {
- set_parameter(this->active, false);
- set_parameter(this->prev_active, false);
+ cur_time += p_time;
+ cur_remaining = os_rem;
+ if (cur_remaining <= 0) {
+ set_parameter(active, false);
+ set_parameter(prev_active, false);
if (autorestart) {
double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay;
- set_parameter(this->time_to_restart, restart_sec);
+ set_parameter(time_to_restart, restart_sec);
}
}
}
- set_parameter(this->time, time);
- set_parameter(this->remaining, remaining);
+ set_parameter(time, cur_time);
+ set_parameter(remaining, cur_remaining);
- return MAX(main_rem, remaining);
+ return MAX(main_rem, cur_remaining);
}
void AnimationNodeOneShot::_bind_methods() {
@@ -554,11 +554,11 @@ String AnimationNodeTimeScale::get_caption() const {
}
double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_seek_root) {
- double scale = get_parameter(this->scale);
+ double cur_scale = get_parameter(scale);
if (p_seek) {
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
} else {
- return blend_input(0, p_time * scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
+ return blend_input(0, p_time * cur_scale, false, p_seek_root, 1.0, FILTER_IGNORE, true);
}
}
@@ -584,12 +584,12 @@ String AnimationNodeTimeSeek::get_caption() const {
}
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_seek_root) {
- double seek_pos = get_parameter(this->seek_pos);
+ double cur_seek_pos = get_parameter(seek_pos);
if (p_seek) {
return blend_input(0, p_time, true, p_seek_root, 1.0, FILTER_IGNORE, true);
- } else if (seek_pos >= 0) {
- double ret = blend_input(0, seek_pos, true, true, 1.0, FILTER_IGNORE, true);
- set_parameter(this->seek_pos, -1.0); //reset
+ } else if (cur_seek_pos >= 0) {
+ double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true);
+ set_parameter(seek_pos, -1.0); //reset
return ret;
} else {
return blend_input(0, p_time, false, p_seek_root, 1.0, FILTER_IGNORE, true);
@@ -701,80 +701,80 @@ bool AnimationNodeTransition::is_from_start() const {
}
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_root) {
- int current = get_parameter(this->current);
- int prev = get_parameter(this->prev);
- int prev_current = get_parameter(this->prev_current);
+ int cur_current = get_parameter(current);
+ int cur_prev = get_parameter(prev);
+ int cur_prev_current = get_parameter(prev_current);
- double time = get_parameter(this->time);
- double prev_xfading = get_parameter(this->prev_xfading);
+ double cur_time = get_parameter(time);
+ double cur_prev_xfading = get_parameter(prev_xfading);
- bool switched = current != prev_current;
+ bool switched = cur_current != cur_prev_current;
if (switched) {
- set_parameter(this->prev_current, current);
- set_parameter(this->prev, prev_current);
+ set_parameter(prev_current, cur_current);
+ set_parameter(prev, cur_prev_current);
- prev = prev_current;
- prev_xfading = xfade_time;
- time = 0;
+ cur_prev = cur_prev_current;
+ cur_prev_xfading = xfade_time;
+ cur_time = 0;
switched = true;
}
- if (current < 0 || current >= enabled_inputs || prev >= enabled_inputs) {
+ if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) {
return 0;
}
double rem = 0.0;
for (int i = 0; i < enabled_inputs; i++) {
- if (i != current && i != prev) {
+ if (i != cur_current && i != cur_prev) {
blend_input(i, p_time, p_seek, p_seek_root, 0, FILTER_IGNORE, sync);
}
}
- if (prev < 0) { // process current animation, check for transition
+ if (cur_prev < 0) { // process current animation, check for transition
- rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0, FILTER_IGNORE, true);
if (p_seek) {
- time = p_time;
+ cur_time = p_time;
} else {
- time += p_time;
+ cur_time += p_time;
}
- if (inputs[current].auto_advance && rem <= xfade_time) {
- set_parameter(this->current, (current + 1) % enabled_inputs);
+ if (inputs[cur_current].auto_advance && rem <= xfade_time) {
+ set_parameter(current, (cur_current + 1) % enabled_inputs);
}
} else { // cross-fading from prev to current
- real_t blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time);
+ real_t blend = xfade_time == 0 ? 0 : (cur_prev_xfading / xfade_time);
if (xfade_curve.is_valid()) {
blend = xfade_curve->sample(blend);
}
if (from_start && !p_seek && switched) { //just switched, seek to start of current
- rem = blend_input(current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, 0, true, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
} else {
- rem = blend_input(current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
+ rem = blend_input(cur_current, p_time, p_seek, p_seek_root, 1.0 - blend, FILTER_IGNORE, true);
}
if (p_seek) {
- blend_input(prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
- time = p_time;
+ blend_input(cur_prev, p_time, true, p_seek_root, blend, FILTER_IGNORE, true);
+ cur_time = p_time;
} else {
- blend_input(prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
- time += p_time;
- prev_xfading -= p_time;
- if (prev_xfading < 0) {
- set_parameter(this->prev, -1);
+ blend_input(cur_prev, p_time, false, p_seek_root, blend, FILTER_IGNORE, true);
+ cur_time += p_time;
+ cur_prev_xfading -= p_time;
+ if (cur_prev_xfading < 0) {
+ set_parameter(prev, -1);
}
}
}
- set_parameter(this->time, time);
- set_parameter(this->prev_xfading, prev_xfading);
+ set_parameter(time, cur_time);
+ set_parameter(prev_xfading, cur_prev_xfading);
return rem;
}
@@ -1070,10 +1070,10 @@ Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p
}
bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.begins_with("nodes/")) {
- String node_name = name.get_slicec('/', 1);
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("nodes/")) {
+ String node_name = prop_name.get_slicec('/', 1);
+ String what = prop_name.get_slicec('/', 2);
if (what == "node") {
Ref<AnimationNode> anode = p_value;
@@ -1089,7 +1089,7 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val
}
return true;
}
- } else if (name == "node_connections") {
+ } else if (prop_name == "node_connections") {
Array conns = p_value;
ERR_FAIL_COND_V(conns.size() % 3 != 0, false);
@@ -1103,10 +1103,10 @@ bool AnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_val
}
bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name.begins_with("nodes/")) {
- String node_name = name.get_slicec('/', 1);
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("nodes/")) {
+ String node_name = prop_name.get_slicec('/', 1);
+ String what = prop_name.get_slicec('/', 2);
if (what == "node") {
if (nodes.has(node_name)) {
@@ -1121,7 +1121,7 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
return true;
}
}
- } else if (name == "node_connections") {
+ } else if (prop_name == "node_connections") {
List<NodeConnection> nc;
get_node_connections(&nc);
Array conns;
@@ -1150,11 +1150,11 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
names.sort_custom<StringName::AlphCompare>();
for (const StringName &E : names) {
- String name = E;
- if (name != "output") {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
+ String prop_name = E;
+ if (prop_name != "output") {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "nodes/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
}
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "nodes/" + prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index facffb99ee..8291df8036 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -89,14 +89,6 @@ String AnimationNodeStateMachineTransition::get_advance_expression() const {
return advance_expression;
}
-void AnimationNodeStateMachineTransition::set_advance_expression_base_node(const NodePath &p_expression_base_node) {
- advance_expression_base_node = p_expression_base_node;
-}
-
-NodePath AnimationNodeStateMachineTransition::get_advance_expression_base_node() const {
- return advance_expression_base_node;
-}
-
void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
ERR_FAIL_COND(p_xfade < 0);
xfade_time = p_xfade;
@@ -158,9 +150,6 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_advance_expression", "text"), &AnimationNodeStateMachineTransition::set_advance_expression);
ClassDB::bind_method(D_METHOD("get_advance_expression"), &AnimationNodeStateMachineTransition::get_advance_expression);
- ClassDB::bind_method(D_METHOD("set_advance_expression_base_node", "path"), &AnimationNodeStateMachineTransition::set_advance_expression_base_node);
- ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationNodeStateMachineTransition::get_advance_expression_base_node);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
@@ -170,7 +159,6 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ADD_GROUP("Advance", "advance_");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "advance_condition"), "set_advance_condition", "get_advance_condition");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "advance_expression", PROPERTY_HINT_EXPRESSION, ""), "set_advance_expression", "get_advance_expression");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "advance_expression_base_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node"), "set_advance_expression_base_node", "get_advance_expression_base_node");
ADD_GROUP("Disabling", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
@@ -656,15 +644,10 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
AnimationTree *tree_base = state_machine->get_animation_tree();
ERR_FAIL_COND_V(tree_base == nullptr, false);
- NodePath advance_expression_base_node_path;
- Node *expression_base = nullptr;
- if (!transition->get_advance_expression_base_node().is_empty()) {
- advance_expression_base_node_path = transition->get_advance_expression_base_node();
- expression_base = tree_base->get_tree()->get_root()->get_child(0)->get_node_or_null(advance_expression_base_node_path);
- } else {
- advance_expression_base_node_path = tree_base->get_advance_expression_base_node();
- expression_base = tree_base->get_node_or_null(advance_expression_base_node_path);
- }
+ NodePath advance_expression_base_node_path = tree_base->get_advance_expression_base_node();
+ Node *expression_base = tree_base->get_node_or_null(advance_expression_base_node_path);
+
+ WARN_PRINT_ONCE("Animation transition has a valid expression, but no expression base node was set on its AnimationTree.");
if (expression_base) {
Ref<Expression> exp = transition->expression;
@@ -728,11 +711,11 @@ void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<Animation
ERR_FAIL_COND(p_node.is_null());
ERR_FAIL_COND(String(p_name).contains("/"));
- State state;
- state.node = p_node;
- state.position = p_position;
+ State state_new;
+ state_new.node = p_node;
+ state_new.position = p_position;
- states[p_name] = state;
+ states[p_name] = state_new;
Ref<AnimationNodeStateMachine> anodesm = p_node;
@@ -960,8 +943,8 @@ bool AnimationNodeStateMachine::_can_connect(const StringName &p_name, Vector<An
return true;
}
- String name = p_name;
- Vector<String> path = name.split("/");
+ String node_name = p_name;
+ Vector<String> path = node_name.split("/");
if (path.size() < 2) {
return false;
@@ -969,12 +952,12 @@ bool AnimationNodeStateMachine::_can_connect(const StringName &p_name, Vector<An
if (path[0] == "..") {
if (prev_state_machine != nullptr) {
- return prev_state_machine->_can_connect(name.replace_first("../", ""), p_parents);
+ return prev_state_machine->_can_connect(node_name.replace_first("../", ""), p_parents);
}
} else if (states.has(path[0])) {
Ref<AnimationNodeStateMachine> anodesm = states[path[0]].node;
if (anodesm.is_valid()) {
- return anodesm->_can_connect(name.replace_first(path[0] + "/", ""), p_parents);
+ return anodesm->_can_connect(node_name.replace_first(path[0] + "/", ""), p_parents);
}
}
@@ -1151,10 +1134,10 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const {
}
double AnimationNodeStateMachine::process(double p_time, bool p_seek, bool p_seek_root) {
- Ref<AnimationNodeStateMachinePlayback> playback = get_parameter(this->playback);
- ERR_FAIL_COND_V(playback.is_null(), 0.0);
+ Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback);
+ ERR_FAIL_COND_V(playback_new.is_null(), 0.0);
- return playback->process(this, p_time, p_seek, p_seek_root);
+ return playback_new->process(this, p_time, p_seek, p_seek_root);
}
String AnimationNodeStateMachine::get_caption() const {
@@ -1178,10 +1161,10 @@ Ref<AnimationNode> AnimationNodeStateMachine::get_child_by_name(const StringName
}
bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.begins_with("states/")) {
- String node_name = name.get_slicec('/', 1);
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("states/")) {
+ String node_name = prop_name.get_slicec('/', 1);
+ String what = prop_name.get_slicec('/', 2);
if (what == "node") {
Ref<AnimationNode> anode = p_value;
@@ -1197,7 +1180,7 @@ bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_
}
return true;
}
- } else if (name == "transitions") {
+ } else if (prop_name == "transitions") {
Array trans = p_value;
ERR_FAIL_COND_V(trans.size() % 3 != 0, false);
@@ -1205,7 +1188,7 @@ bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_
add_transition(trans[i], trans[i + 1], trans[i + 2]);
}
return true;
- } else if (name == "graph_offset") {
+ } else if (prop_name == "graph_offset") {
set_graph_offset(p_value);
return true;
}
@@ -1214,10 +1197,10 @@ bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_
}
bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name.begins_with("states/")) {
- String node_name = name.get_slicec('/', 1);
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("states/")) {
+ String node_name = prop_name.get_slicec('/', 1);
+ String what = prop_name.get_slicec('/', 2);
if (what == "node") {
if (states.has(node_name) && can_edit_node(node_name)) {
@@ -1232,7 +1215,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
return true;
}
}
- } else if (name == "transitions") {
+ } else if (prop_name == "transitions") {
Array trans;
for (int i = 0; i < transitions.size(); i++) {
String from = transitions[i].from;
@@ -1249,7 +1232,7 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
r_ret = trans;
return true;
- } else if (name == "graph_offset") {
+ } else if (prop_name == "graph_offset") {
r_ret = get_graph_offset();
return true;
}
@@ -1264,9 +1247,9 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c
}
names.sort_custom<StringName::AlphCompare>();
- for (const StringName &name : names) {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
+ for (const StringName &prop_name : names) {
+ p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NO_EDITOR));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
p_list->push_back(PropertyInfo(Variant::ARRAY, "transitions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index ab78b1afe8..cdb4c7528a 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -54,7 +54,6 @@ private:
bool disabled = false;
int priority = 1;
String advance_expression;
- NodePath advance_expression_base_node;
friend class AnimationNodeStateMachinePlayback;
Ref<Expression> expression;
@@ -77,9 +76,6 @@ public:
void set_advance_expression(const String &p_expression);
String get_advance_expression() const;
- void set_advance_expression_base_node(const NodePath &p_expression_base_node);
- NodePath get_advance_expression_base_node() const;
-
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 54b10d9d57..59930a3fbb 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -109,7 +109,7 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
Ref<AnimationLibrary> lib = d[lib_name];
add_animation_library(lib_name, lib);
}
-
+ emit_signal("animation_libraries_updated");
} else if (name.begins_with("next/")) {
String which = name.get_slicec('/', 1);
animation_set_next(which, p_value);
@@ -1274,6 +1274,23 @@ void AnimationPlayer::_animation_set_cache_update() {
}
void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
+ {
+ int at_pos = -1;
+
+ for (uint32_t i = 0; i < animation_libraries.size(); i++) {
+ if (animation_libraries[i].name == p_library) {
+ at_pos = i;
+ break;
+ }
+ }
+
+ ERR_FAIL_COND(at_pos == -1);
+
+ ERR_FAIL_COND(!animation_libraries[at_pos].library->animations.has(p_name));
+
+ _ref_anim(animation_libraries[at_pos].library->animations[p_name]);
+ }
+
_animation_set_cache_update();
}
@@ -1283,6 +1300,12 @@ void AnimationPlayer::_animation_removed(const StringName &p_name, const StringN
if (!animation_set.has(name)) {
return; // No need to update because not the one from the library being used.
}
+
+ AnimationData animation_data = animation_set[name];
+ if (animation_data.animation_library == p_library) {
+ _unref_anim(animation_data.animation);
+ }
+
_animation_set_cache_update();
// Erase blends if needed
@@ -1376,9 +1399,13 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref
animation_libraries.insert(insert_pos, ald);
ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name));
- ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name));
+ ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_name));
ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_name));
+ for (const KeyValue<StringName, Ref<Animation>> &K : ald.library->animations) {
+ _ref_anim(K.value);
+ }
+
_animation_set_cache_update();
notify_property_list_changed();
@@ -1399,7 +1426,7 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) {
ERR_FAIL_COND(at_pos == -1);
animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
- animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added));
+ animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
stop();
@@ -1438,11 +1465,11 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S
animation_libraries[i].name = p_new_name;
// rename connections
animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
- animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added));
+ animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
- animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
+ animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name));
animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name));
for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) {
@@ -1504,9 +1531,9 @@ bool AnimationPlayer::has_animation(const StringName &p_name) const {
Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const {
ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
- const AnimationData &data = animation_set[p_name];
+ const AnimationData &anim_data = animation_set[p_name];
- return data.animation;
+ return anim_data.animation;
}
void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const {
@@ -2037,10 +2064,9 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
aux_player->add_animation_library("", al);
aux_player->set_assigned_animation(SceneStringNames::get_singleton()->RESET);
// Forcing the use of the original root because the scene where original player belongs may be not the active one
- Node *root = get_node(get_root());
- Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(root);
+ Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(get_node(get_root()));
aux_player->seek(0.0f, true);
- aux_player->queue_delete();
+ aux_player->queue_free();
if (p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
@@ -2152,6 +2178,7 @@ void AnimationPlayer::_bind_methods() {
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("animation_libraries_updated"));
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 05a4a2d024..517908077d 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -50,10 +50,8 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
Variant ret;
- if (GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret)) {
- return ret;
- }
- return Variant();
+ GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret);
+ return ret;
}
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
@@ -97,8 +95,8 @@ void AnimationNode::blend_animation(const StringName &p_animation, double p_time
if (animation.is_null()) {
AnimationNodeBlendTree *btree = Object::cast_to<AnimationNodeBlendTree>(parent);
if (btree) {
- String name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
- make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), name, p_animation));
+ String node_name = btree->get_node_name(Ref<AnimationNodeAnimation>(this));
+ make_invalid(vformat(RTR("In node '%s', invalid animation: '%s'."), node_name, p_animation));
} else {
make_invalid(vformat(RTR("Invalid animation: '%s'."), p_animation));
}
@@ -160,8 +158,8 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
StringName node_name = connections[p_input];
if (!blend_tree->has_node(node_name)) {
- String name = blend_tree->get_node_name(Ref<AnimationNode>(this));
- make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), name));
+ String node_name2 = blend_tree->get_node_name(Ref<AnimationNode>(this));
+ make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), node_name2));
return 0;
}
@@ -312,12 +310,9 @@ String AnimationNode::get_input_name(int p_input) {
}
String AnimationNode::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_caption, ret)) {
- return ret;
- }
-
- return "Node";
+ String ret = "Node";
+ GDVIRTUAL_CALL(_get_caption, ret);
+ return ret;
}
void AnimationNode::add_input(const String &p_name) {
@@ -344,12 +339,9 @@ void AnimationNode::remove_input(int p_index) {
}
double AnimationNode::process(double p_time, bool p_seek, bool p_seek_root) {
- double ret;
- if (GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret)) {
- return ret;
- }
-
- return 0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_process, p_time, p_seek, p_seek_root, ret);
+ return ret;
}
void AnimationNode::set_filter_path(const NodePath &p_path, bool p_enable) {
@@ -373,12 +365,9 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
}
bool AnimationNode::has_filter() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_filter, ret)) {
- return ret;
- }
-
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_has_filter, ret);
+ return ret;
}
Array AnimationNode::_get_filters() const {
@@ -407,10 +396,8 @@ void AnimationNode::_validate_property(PropertyInfo &p_property) const {
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
Ref<AnimationNode> ret;
- if (GDVIRTUAL_CALL(_get_child_by_name, p_name, ret)) {
- return ret;
- }
- return Ref<AnimationNode>();
+ GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);
+ return ret;
}
void AnimationNode::_bind_methods() {
@@ -1565,11 +1552,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
real_t db = Math::linear_to_db(MAX(blend, 0.00001));
- if (t->object->has_method(SNAME("set_unit_db"))) {
- t->object->call(SNAME("set_unit_db"), db);
- } else {
- t->object->call(SNAME("set_volume_db"), db);
- }
+ t->object->call(SNAME("set_volume_db"), db);
} break;
case Animation::TYPE_ANIMATION: {
if (blend < CMP_EPSILON) {
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 4a0f870406..aa58e1044a 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -263,9 +263,9 @@ bool Tween::step(double p_delta) {
}
if (is_bound) {
- Node *bound_node = get_bound_node();
- if (bound_node) {
- if (!bound_node->is_inside_tree()) {
+ Node *node = get_bound_node();
+ if (node) {
+ if (!node->is_inside_tree()) {
return true;
}
} else {
@@ -342,9 +342,9 @@ bool Tween::step(double p_delta) {
bool Tween::can_process(bool p_tree_paused) const {
if (is_bound && pause_mode == TWEEN_PAUSE_BOUND) {
- Node *bound_node = get_bound_node();
- if (bound_node) {
- return bound_node->is_inside_tree() && bound_node->can_process();
+ Node *node = get_bound_node();
+ if (node) {
+ return node->is_inside_tree() && node->can_process();
}
}
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index 4c5a63e52c..b4bdda9ecb 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -450,9 +450,9 @@ void SceneDebuggerObject::_parse_script_properties(Script *p_script, ScriptInsta
for (const KeyValue<StringName, Variant> &E : sc.value) {
String script_path = sc.key == p_script ? "" : sc.key->get_path().get_file() + "/";
if (E.value.get_type() == Variant::OBJECT) {
- Variant id = ((Object *)E.value)->get_instance_id();
- PropertyInfo pi(id.get_type(), "Constants/" + E.key, PROPERTY_HINT_OBJECT_ID, "Object");
- properties.push_back(SceneDebuggerProperty(pi, id));
+ Variant inst_id = ((Object *)E.value)->get_instance_id();
+ PropertyInfo pi(inst_id.get_type(), "Constants/" + E.key, PROPERTY_HINT_OBJECT_ID, "Object");
+ properties.push_back(SceneDebuggerProperty(pi, inst_id));
} else {
PropertyInfo pi(E.value.get_type(), "Constants/" + script_path + E.key);
properties.push_back(SceneDebuggerProperty(pi, E.value));
@@ -548,14 +548,36 @@ SceneDebuggerTree::SceneDebuggerTree(Node *p_root) {
// Flatten tree into list, depth first, use stack to avoid recursion.
List<Node *> stack;
stack.push_back(p_root);
+ bool is_root = true;
+ const StringName &is_visible_sn = SNAME("is_visible");
+ const StringName &is_visible_in_tree_sn = SNAME("is_visible_in_tree");
while (stack.size()) {
Node *n = stack[0];
stack.pop_front();
+
int count = n->get_child_count();
- nodes.push_back(RemoteNode(count, n->get_name(), n->get_class(), n->get_instance_id()));
for (int i = 0; i < count; i++) {
stack.push_front(n->get_child(count - i - 1));
}
+
+ int view_flags = 0;
+ if (is_root) {
+ // Prevent root window visibility from being changed.
+ is_root = false;
+ } else if (n->has_method(is_visible_sn)) {
+ const Variant visible = n->call(is_visible_sn);
+ if (visible.get_type() == Variant::BOOL) {
+ view_flags = RemoteNode::VIEW_HAS_VISIBLE_METHOD;
+ view_flags |= uint8_t(visible) * RemoteNode::VIEW_VISIBLE;
+ }
+ if (n->has_method(is_visible_in_tree_sn)) {
+ const Variant visible_in_tree = n->call(is_visible_in_tree_sn);
+ if (visible_in_tree.get_type() == Variant::BOOL) {
+ view_flags |= uint8_t(visible_in_tree) * RemoteNode::VIEW_VISIBLE_IN_TREE;
+ }
+ }
+ }
+ nodes.push_back(RemoteNode(count, n->get_name(), n->get_class(), n->get_instance_id(), n->get_scene_file_path(), view_flags));
}
}
@@ -565,19 +587,23 @@ void SceneDebuggerTree::serialize(Array &p_arr) {
p_arr.push_back(n.name);
p_arr.push_back(n.type_name);
p_arr.push_back(n.id);
+ p_arr.push_back(n.scene_file_path);
+ p_arr.push_back(n.view_flags);
}
}
void SceneDebuggerTree::deserialize(const Array &p_arr) {
int idx = 0;
while (p_arr.size() > idx) {
- ERR_FAIL_COND(p_arr.size() < 4);
- CHECK_TYPE(p_arr[idx], INT);
- CHECK_TYPE(p_arr[idx + 1], STRING);
- CHECK_TYPE(p_arr[idx + 2], STRING);
- CHECK_TYPE(p_arr[idx + 3], INT);
- nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3]));
- idx += 4;
+ ERR_FAIL_COND(p_arr.size() < 6);
+ CHECK_TYPE(p_arr[idx], INT); // child_count.
+ CHECK_TYPE(p_arr[idx + 1], STRING); // name.
+ CHECK_TYPE(p_arr[idx + 2], STRING); // type_name.
+ CHECK_TYPE(p_arr[idx + 3], INT); // id.
+ CHECK_TYPE(p_arr[idx + 4], STRING); // scene_file_path.
+ CHECK_TYPE(p_arr[idx + 5], INT); // view_flags.
+ nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5]));
+ idx += 6;
}
}
diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h
index 911363f45d..fe35446aae 100644
--- a/scene/debugger/scene_debugger.h
+++ b/scene/debugger/scene_debugger.h
@@ -110,12 +110,23 @@ public:
String name;
String type_name;
ObjectID id;
+ String scene_file_path;
+ uint8_t view_flags = 0;
- RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id) {
+ enum ViewFlags {
+ VIEW_HAS_VISIBLE_METHOD = 1 << 1,
+ VIEW_VISIBLE = 1 << 2,
+ VIEW_VISIBLE_IN_TREE = 1 << 3,
+ };
+
+ RemoteNode(int p_child, const String &p_name, const String &p_type, ObjectID p_id, const String p_scene_file_path, int p_view_flags) {
child_count = p_child;
name = p_name;
type_name = p_type;
id = p_id;
+
+ scene_file_path = p_scene_file_path;
+ view_flags = p_view_flags;
}
RemoteNode() {}
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index af6a99ca62..1082fc4d6d 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -60,7 +60,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> mouse_button = p_event;
- bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo();
+ bool ui_accept = p_event->is_action("ui_accept", true) && !p_event->is_echo();
bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE;
if (button_masked || ui_accept) {
@@ -127,6 +127,7 @@ void BaseButton::_notification(int p_what) {
status.hovering = false;
status.press_attempt = false;
status.pressing_inside = false;
+ status.shortcut_press = false;
} break;
}
}
@@ -160,6 +161,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
if (action_mode == ACTION_MODE_BUTTON_PRESS) {
status.press_attempt = false;
status.pressing_inside = false;
+ status.shortcut_press = false;
}
status.pressed = !status.pressed;
_unpress_group();
@@ -185,6 +187,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
}
status.press_attempt = false;
status.pressing_inside = false;
+ status.shortcut_press = false;
emit_signal(SNAME("button_up"));
}
@@ -209,6 +212,7 @@ void BaseButton::set_disabled(bool p_disabled) {
}
status.press_attempt = false;
status.pressing_inside = false;
+ status.shortcut_press = false;
}
queue_redraw();
}
@@ -284,7 +288,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
pressing = status.pressed;
}
- if (pressing) {
+ if ((shortcut_feedback || !status.shortcut_press) && pressing) {
return DRAW_PRESSED;
} else {
return DRAW_NORMAL;
@@ -349,11 +353,8 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) {
+ status.shortcut_press = true;
on_action_event(p_event);
accept_event();
}
@@ -389,36 +390,16 @@ Ref<ButtonGroup> BaseButton::get_button_group() const {
return button_group;
}
-void BaseButton::set_shortcut_context(Node *p_node) {
- if (p_node != nullptr) {
- shortcut_context = p_node->get_instance_id();
- } else {
- shortcut_context = ObjectID();
- }
-}
-
-Node *BaseButton::get_shortcut_context() const {
- Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
- Node *ctx_node = Object::cast_to<Node>(ctx_obj);
-
- return ctx_node;
+bool BaseButton::_was_pressed_by_mouse() const {
+ return was_mouse_pressed;
}
-bool BaseButton::_is_focus_owner_in_shortcut_context() const {
- if (shortcut_context == ObjectID()) {
- // No context, therefore global - always "in" context.
- return true;
- }
-
- Node *ctx_node = get_shortcut_context();
- Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
-
- // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
- return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+void BaseButton::set_shortcut_feedback(bool p_feedback) {
+ shortcut_feedback = p_feedback;
}
-bool BaseButton::_was_pressed_by_mouse() const {
- return was_mouse_pressed;
+bool BaseButton::is_shortcut_feedback() const {
+ return shortcut_feedback;
}
void BaseButton::_bind_methods() {
@@ -446,8 +427,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group);
ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group);
- ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context);
- ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context);
+ ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback);
+ ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback);
GDVIRTUAL_BIND(_pressed);
GDVIRTUAL_BIND(_toggled, "button_pressed");
@@ -465,8 +446,8 @@ void BaseButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
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::BOOL, "shortcut_feedback"), "set_shortcut_feedback", "is_shortcut_feedback");
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_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
BIND_ENUM_CONSTANT(DRAW_NORMAL);
BIND_ENUM_CONSTANT(DRAW_PRESSED);
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index c83b08aadf..3acf535f54 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -53,6 +53,7 @@ private:
bool keep_pressed_outside = false;
Ref<Shortcut> shortcut;
ObjectID shortcut_context;
+ bool shortcut_feedback = true;
ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE;
struct Status {
@@ -60,6 +61,7 @@ private:
bool hovering = false;
bool press_attempt = false;
bool pressing_inside = false;
+ bool shortcut_press = false;
bool disabled = false;
@@ -81,7 +83,6 @@ protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
- bool _is_focus_owner_in_shortcut_context() const;
bool _was_pressed_by_mouse() const;
GDVIRTUAL0(_pressed)
@@ -132,8 +133,8 @@ public:
void set_button_group(const Ref<ButtonGroup> &p_group);
Ref<ButtonGroup> get_button_group() const;
- void set_shortcut_context(Node *p_node);
- Node *get_shortcut_context() const;
+ void set_shortcut_feedback(bool p_feedback);
+ bool is_shortcut_feedback() const;
BaseButton();
~BaseButton();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 8069ab465b..5f8f25154c 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -138,7 +138,7 @@ void CodeEdit::_notification(int p_what) {
code_completion_scroll_rect.position = code_completion_rect.position + Vector2(code_completion_rect.size.width, 0);
code_completion_scroll_rect.size = Vector2(scroll_width, code_completion_rect.size.height);
- code_completion_line_ofs = CLAMP(code_completion_current_selected - lines / 2, 0, code_completion_options_count - lines);
+ code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines);
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), code_completion_selected_color);
for (int i = 0; i < lines; i++) {
@@ -201,7 +201,7 @@ void CodeEdit::_notification(int p_what) {
if (caret_visible && !code_hint.is_empty() && (!code_completion_active || (code_completion_below != code_hint_draw_below))) {
const int font_height = font->get_height(font_size);
Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"));
- Color font_color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
+ Color color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
Vector<String> code_hint_lines = code_hint.split("\n");
int line_count = code_hint_lines.size();
@@ -238,17 +238,17 @@ void CodeEdit::_notification(int p_what) {
Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent(font_size) + font_height * i + yofs);
round_ofs = round_ofs.round();
- draw_string(font, round_ofs, line.replace(String::chr(0xFFFF), ""), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
+ draw_string(font, round_ofs, line.replace(String::chr(0xFFFF), ""), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);
if (end > 0) {
// Draw an underline for the currently edited function parameter.
const Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font_height + font_height * i + yofs);
- draw_line(b, b + Vector2(end - begin, 0), font_color, 2);
+ draw_line(b, b + Vector2(end - begin, 0), color, 2);
// Draw a translucent text highlight as well.
const Rect2 highlight_rect = Rect2(
b - Vector2(0, font_height),
Vector2(end - begin, font_height));
- draw_rect(highlight_rect, font_color * Color(1, 1, 1, 0.2));
+ draw_rect(highlight_rect, color * Color(1, 1, 1, 0.2));
}
yofs += line_spacing;
}
@@ -281,16 +281,22 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
case MouseButton::WHEEL_UP: {
if (code_completion_current_selected > 0) {
code_completion_current_selected--;
+ code_completion_force_item_center = -1;
queue_redraw();
}
} break;
case MouseButton::WHEEL_DOWN: {
if (code_completion_current_selected < code_completion_options.size() - 1) {
code_completion_current_selected++;
+ code_completion_force_item_center = -1;
queue_redraw();
}
} break;
case MouseButton::LEFT: {
+ if (code_completion_force_item_center == -1) {
+ code_completion_force_item_center = code_completion_current_selected;
+ }
+
code_completion_current_selected = CLAMP(code_completion_line_ofs + (mb->get_position().y - code_completion_rect.position.y) / get_line_height(), 0, code_completion_options.size() - 1);
if (mb->is_double_click()) {
confirm_code_completion();
@@ -300,6 +306,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
default:
break;
}
+
return;
} else if (code_completion_active && code_completion_scroll_rect.has_point(mb->get_position())) {
if (mb->get_button_index() != MouseButton::LEFT) {
@@ -448,6 +455,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = code_completion_options.size() - 1;
}
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
@@ -458,30 +466,35 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
} else {
code_completion_current_selected = 0;
}
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_up", true)) {
code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines);
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_down", true)) {
code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_home", true)) {
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_end", true)) {
code_completion_current_selected = code_completion_options.size() - 1;
+ code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
@@ -609,72 +622,74 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
/* Text manipulation */
// Overridable actions
-void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode) {
- bool had_selection = has_selection();
- String selection_text = (had_selection ? get_selected_text() : "");
+void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode, int p_caret) {
+ start_action(EditAction::ACTION_TYPING);
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
- if (had_selection) {
- begin_complex_operation();
- delete_selection();
- }
+ bool had_selection = has_selection(i);
+ String selection_text = (had_selection ? get_selected_text(i) : "");
- // Remove the old character if in overtype mode and no selection.
- if (is_overtype_mode_enabled() && !had_selection) {
- begin_complex_operation();
+ if (had_selection) {
+ delete_selection(i);
+ }
- /* Make sure we don't try and remove empty space. */
- if (get_caret_column() < get_line(get_caret_line()).length()) {
- remove_text(get_caret_line(), get_caret_column(), get_caret_line(), get_caret_column() + 1);
+ // Remove the old character if in overtype mode and no selection.
+ if (is_overtype_mode_enabled() && !had_selection) {
+ // Make sure we don't try and remove empty space.
+ if (get_caret_column(i) < get_line(get_caret_line(i)).length()) {
+ remove_text(get_caret_line(i), get_caret_column(i), get_caret_line(i), get_caret_column(i) + 1);
+ }
}
- }
- const char32_t chr[2] = { (char32_t)p_unicode, 0 };
+ const char32_t chr[2] = { (char32_t)p_unicode, 0 };
- if (auto_brace_completion_enabled) {
- int cl = get_caret_line();
- int cc = get_caret_column();
+ if (auto_brace_completion_enabled) {
+ int cl = get_caret_line(i);
+ int cc = get_caret_column(i);
- if (had_selection) {
- insert_text_at_caret(chr);
+ if (had_selection) {
+ insert_text_at_caret(chr, i);
- String close_key = get_auto_brace_completion_close_key(chr);
- if (!close_key.is_empty()) {
- insert_text_at_caret(selection_text + close_key);
- set_caret_column(get_caret_column() - 1);
- }
- } else {
- int caret_move_offset = 1;
-
- int post_brace_pair = cc < get_line(cl).length() ? _get_auto_brace_pair_close_at_pos(cl, cc) : -1;
-
- if (has_string_delimiter(chr) && cc > 0 && !is_symbol(get_line(cl)[cc - 1]) && post_brace_pair == -1) {
- insert_text_at_caret(chr);
- } else if (cc < get_line(cl).length() && !is_symbol(get_line(cl)[cc])) {
- insert_text_at_caret(chr);
- } else if (post_brace_pair != -1 && auto_brace_completion_pairs[post_brace_pair].close_key[0] == chr[0]) {
- caret_move_offset = auto_brace_completion_pairs[post_brace_pair].close_key.length();
- } else if (is_in_comment(cl, cc) != -1 || (is_in_string(cl, cc) != -1 && has_string_delimiter(chr))) {
- insert_text_at_caret(chr);
+ String close_key = get_auto_brace_completion_close_key(chr);
+ if (!close_key.is_empty()) {
+ insert_text_at_caret(selection_text + close_key, i);
+ set_caret_column(get_caret_column(i) - 1, i == 0, i);
+ }
} else {
- insert_text_at_caret(chr);
+ int caret_move_offset = 1;
+
+ int post_brace_pair = cc < get_line(cl).length() ? _get_auto_brace_pair_close_at_pos(cl, cc) : -1;
+
+ if (has_string_delimiter(chr) && cc > 0 && !is_symbol(get_line(cl)[cc - 1]) && post_brace_pair == -1) {
+ insert_text_at_caret(chr, i);
+ } else if (cc < get_line(cl).length() && !is_symbol(get_line(cl)[cc])) {
+ insert_text_at_caret(chr, i);
+ } else if (post_brace_pair != -1 && auto_brace_completion_pairs[post_brace_pair].close_key[0] == chr[0]) {
+ caret_move_offset = auto_brace_completion_pairs[post_brace_pair].close_key.length();
+ } else if (is_in_comment(cl, cc) != -1 || (is_in_string(cl, cc) != -1 && has_string_delimiter(chr))) {
+ insert_text_at_caret(chr, i);
+ } else {
+ insert_text_at_caret(chr, i);
- int pre_brace_pair = _get_auto_brace_pair_open_at_pos(cl, cc + 1);
- if (pre_brace_pair != -1) {
- insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key);
+ int pre_brace_pair = _get_auto_brace_pair_open_at_pos(cl, cc + 1);
+ if (pre_brace_pair != -1) {
+ insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i);
+ }
}
+ set_caret_column(cc + caret_move_offset, i == 0, i);
}
- set_caret_column(cc + caret_move_offset);
+ } else {
+ insert_text_at_caret(chr, i);
}
- } else {
- insert_text_at_caret(chr);
- }
-
- if ((is_overtype_mode_enabled() && !had_selection) || (had_selection)) {
- end_complex_operation();
}
+ end_action();
}
-void CodeEdit::_backspace_internal() {
+void CodeEdit::_backspace_internal(int p_caret) {
if (!is_editable()) {
return;
}
@@ -684,51 +699,65 @@ void CodeEdit::_backspace_internal() {
return;
}
- int cc = get_caret_column();
- int cl = get_caret_line();
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
- if (cc == 0 && cl == 0) {
- return;
- }
+ int cc = get_caret_column(i);
+ int cl = get_caret_line(i);
- if (cl > 0 && _is_line_hidden(cl - 1)) {
- unfold_line(get_caret_line() - 1);
- }
+ if (cc == 0 && cl == 0) {
+ continue;
+ }
- int prev_line = cc ? cl : cl - 1;
- int prev_column = cc ? (cc - 1) : (get_line(cl - 1).length());
+ if (cl > 0 && _is_line_hidden(cl - 1)) {
+ unfold_line(get_caret_line(i) - 1);
+ }
- merge_gutters(prev_line, cl);
+ int prev_line = cc ? cl : cl - 1;
+ int prev_column = cc ? (cc - 1) : (get_line(cl - 1).length());
- if (auto_brace_completion_enabled && cc > 0) {
- int idx = _get_auto_brace_pair_open_at_pos(cl, cc);
- if (idx != -1) {
- prev_column = cc - auto_brace_completion_pairs[idx].open_key.length();
+ merge_gutters(prev_line, cl);
- if (_get_auto_brace_pair_close_at_pos(cl, cc) == idx) {
- remove_text(prev_line, prev_column, cl, cc + auto_brace_completion_pairs[idx].close_key.length());
- } else {
- remove_text(prev_line, prev_column, cl, cc);
+ if (auto_brace_completion_enabled && cc > 0) {
+ int idx = _get_auto_brace_pair_open_at_pos(cl, cc);
+ if (idx != -1) {
+ prev_column = cc - auto_brace_completion_pairs[idx].open_key.length();
+
+ if (_get_auto_brace_pair_close_at_pos(cl, cc) == idx) {
+ remove_text(prev_line, prev_column, cl, cc + auto_brace_completion_pairs[idx].close_key.length());
+ } else {
+ remove_text(prev_line, prev_column, cl, cc);
+ }
+ set_caret_line(prev_line, false, true, 0, i);
+ set_caret_column(prev_column, i == 0, i);
+
+ adjust_carets_after_edit(i, prev_line, prev_column, cl, cc + auto_brace_completion_pairs[idx].close_key.length());
+ continue;
}
- set_caret_line(prev_line, false, true);
- set_caret_column(prev_column);
- return;
}
- }
- // For space indentation we need to do a simple unindent if there are no chars to the left, acting in the
- // same way as tabs.
- if (indent_using_spaces && cc != 0) {
- if (get_first_non_whitespace_column(cl) >= cc) {
- prev_column = cc - _calculate_spaces_till_next_left_indent(cc);
- prev_line = cl;
+ // For space indentation we need to do a simple unindent if there are no chars to the left, acting in the
+ // same way as tabs.
+ if (indent_using_spaces && cc != 0) {
+ if (get_first_non_whitespace_column(cl) >= cc) {
+ prev_column = cc - _calculate_spaces_till_next_left_indent(cc);
+ prev_line = cl;
+ }
}
- }
- remove_text(prev_line, prev_column, cl, cc);
+ remove_text(prev_line, prev_column, cl, cc);
- set_caret_line(prev_line, false, true);
- set_caret_column(prev_column);
+ set_caret_line(prev_line, false, true, 0, i);
+ set_caret_column(prev_column, i == 0, i);
+
+ adjust_carets_after_edit(i, prev_line, prev_column, cl, cc);
+ }
+ merge_overlapping_carets();
+ end_complex_operation();
}
/* Indent management */
@@ -803,10 +832,15 @@ void CodeEdit::do_indent() {
return;
}
- int spaces_to_add = _calculate_spaces_till_next_right_indent(get_caret_column());
- if (spaces_to_add > 0) {
- insert_text_at_caret(String(" ").repeat(spaces_to_add));
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ int spaces_to_add = _calculate_spaces_till_next_right_indent(get_caret_column(i));
+ if (spaces_to_add > 0) {
+ insert_text_at_caret(String(" ").repeat(spaces_to_add), i);
+ }
}
+ end_complex_operation();
}
void CodeEdit::indent_lines() {
@@ -815,48 +849,49 @@ void CodeEdit::indent_lines() {
}
begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ // This value informs us by how much we changed selection position by indenting right.
+ // Default is 1 for tab indentation.
+ int selection_offset = 1;
+
+ int start_line = get_caret_line(c);
+ int end_line = start_line;
+ if (has_selection(c)) {
+ start_line = get_selection_from_line(c);
+ end_line = get_selection_to_line(c);
+
+ // Ignore the last line if the selection is not past the first column.
+ if (get_selection_to_column(c) == 0) {
+ selection_offset = 0;
+ end_line--;
+ }
+ }
- /* This value informs us by how much we changed selection position by indenting right. */
- /* Default is 1 for tab indentation. */
- int selection_offset = 1;
+ for (int i = start_line; i <= end_line; i++) {
+ const String line_text = get_line(i);
+ if (line_text.size() == 0 && has_selection(c)) {
+ continue;
+ }
- int start_line = get_caret_line();
- int end_line = start_line;
- if (has_selection()) {
- start_line = get_selection_from_line();
- end_line = get_selection_to_line();
+ if (!indent_using_spaces) {
+ set_line(i, '\t' + line_text);
+ continue;
+ }
- /* Ignore the last line if the selection is not past the first column. */
- if (get_selection_to_column() == 0) {
- selection_offset = 0;
- end_line--;
+ // We don't really care where selection is - we just need to know indentation level at the beginning of the line.
+ // Since we will add this many spaces, we want to move the whole selection and caret by this much.
+ int spaces_to_add = _calculate_spaces_till_next_right_indent(get_first_non_whitespace_column(i));
+ set_line(i, String(" ").repeat(spaces_to_add) + line_text);
+ selection_offset = spaces_to_add;
}
- }
- for (int i = start_line; i <= end_line; i++) {
- const String line_text = get_line(i);
- if (line_text.size() == 0 && has_selection()) {
- continue;
+ // Fix selection and caret being off after shifting selection right.
+ if (has_selection(c)) {
+ select(start_line, get_selection_from_column(c) + selection_offset, get_selection_to_line(c), get_selection_to_column(c) + selection_offset, c);
}
-
- if (!indent_using_spaces) {
- set_line(i, '\t' + line_text);
- continue;
- }
-
- /* We don't really care where selection is - we just need to know indentation level at the beginning of the line. */
- /* Since we will add this many spaces, we want to move the whole selection and caret by this much. */
- int spaces_to_add = _calculate_spaces_till_next_right_indent(get_first_non_whitespace_column(i));
- set_line(i, String(" ").repeat(spaces_to_add) + line_text);
- selection_offset = spaces_to_add;
- }
-
- /* Fix selection and caret being off after shifting selection right.*/
- if (has_selection()) {
- select(start_line, get_selection_from_column() + selection_offset, get_selection_to_line(), get_selection_to_column() + selection_offset);
+ set_caret_column(get_caret_column(c) + selection_offset, false, c);
}
- set_caret_column(get_caret_column() + selection_offset, false);
-
end_complex_operation();
}
@@ -872,30 +907,36 @@ void CodeEdit::do_unindent() {
return;
}
- int cl = get_caret_line();
- const String &line = get_line(cl);
-
- if (line[cc - 1] == '\t') {
- remove_text(cl, cc - 1, cl, cc);
- set_caret_column(MAX(0, cc - 1));
- return;
- }
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ int cl = get_caret_line(c);
+ const String &line = get_line(cl);
+
+ if (line[cc - 1] == '\t') {
+ remove_text(cl, cc - 1, cl, cc);
+ set_caret_column(MAX(0, cc - 1), c == 0, c);
+ adjust_carets_after_edit(c, cl, cc, cl, cc - 1);
+ continue;
+ }
- if (line[cc - 1] != ' ') {
- return;
- }
+ if (line[cc - 1] != ' ') {
+ continue;
+ }
- int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
- if (spaces_to_remove > 0) {
- for (int i = 1; i <= spaces_to_remove; i++) {
- if (line[cc - i] != ' ') {
- spaces_to_remove = i - 1;
- break;
+ int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
+ if (spaces_to_remove > 0) {
+ for (int i = 1; i <= spaces_to_remove; i++) {
+ if (line[cc - i] != ' ') {
+ spaces_to_remove = i - 1;
+ break;
+ }
}
+ remove_text(cl, cc - spaces_to_remove, cl, cc);
+ set_caret_column(MAX(0, cc - spaces_to_remove), c == 0, c);
}
- remove_text(cl, cc - spaces_to_remove, cl, cc);
- set_caret_column(MAX(0, cc - spaces_to_remove));
}
+ end_complex_operation();
}
void CodeEdit::unindent_lines() {
@@ -905,71 +946,73 @@ void CodeEdit::unindent_lines() {
begin_complex_operation();
- /* Moving caret and selection after unindenting can get tricky because */
- /* changing content of line can move caret and selection on its own (if new line ends before previous position of either), */
- /* therefore we just remember initial values and at the end of the operation offset them by number of removed characters. */
- int removed_characters = 0;
- int initial_selection_end_column = 0;
- int initial_cursor_column = get_caret_column();
-
- int start_line = get_caret_line();
- int end_line = start_line;
- if (has_selection()) {
- start_line = get_selection_from_line();
- end_line = get_selection_to_line();
-
- /* Ignore the last line if the selection is not past the first column. */
- initial_selection_end_column = get_selection_to_column();
- if (initial_selection_end_column == 0) {
- end_line--;
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &c : caret_edit_order) {
+ // Moving caret and selection after unindenting can get tricky because
+ // changing content of line can move caret and selection on its own (if new line ends before previous position of either)
+ // therefore we just remember initial values and at the end of the operation offset them by number of removed characters.
+ int removed_characters = 0;
+ int initial_selection_end_column = 0;
+ int initial_cursor_column = get_caret_column(c);
+
+ int start_line = get_caret_line(c);
+ int end_line = start_line;
+ if (has_selection(c)) {
+ start_line = get_selection_from_line(c);
+ end_line = get_selection_to_line(c);
+
+ // Ignore the last line if the selection is not past the first column.
+ initial_selection_end_column = get_selection_to_column(c);
+ if (initial_selection_end_column == 0) {
+ end_line--;
+ }
}
- }
- bool first_line_edited = false;
- bool last_line_edited = false;
+ bool first_line_edited = false;
+ bool last_line_edited = false;
- for (int i = start_line; i <= end_line; i++) {
- String line_text = get_line(i);
+ for (int i = start_line; i <= end_line; i++) {
+ String line_text = get_line(i);
- if (line_text.begins_with("\t")) {
- line_text = line_text.substr(1, line_text.length());
+ if (line_text.begins_with("\t")) {
+ line_text = line_text.substr(1, line_text.length());
- set_line(i, line_text);
- removed_characters = 1;
+ set_line(i, line_text);
+ removed_characters = 1;
- first_line_edited = (i == start_line) ? true : first_line_edited;
- last_line_edited = (i == end_line) ? true : last_line_edited;
- continue;
- }
+ first_line_edited = (i == start_line) ? true : first_line_edited;
+ last_line_edited = (i == end_line) ? true : last_line_edited;
+ continue;
+ }
- if (line_text.begins_with(" ")) {
- /* When unindenting we aim to remove spaces before line that has selection no matter what is selected, */
- /* Here we remove only enough spaces to align text to nearest full multiple of indentation_size. */
- /* In case where selection begins at the start of indentation_size multiple we remove whole indentation level. */
- int spaces_to_remove = _calculate_spaces_till_next_left_indent(get_first_non_whitespace_column(i));
- line_text = line_text.substr(spaces_to_remove, line_text.length());
+ if (line_text.begins_with(" ")) {
+ // When unindenting we aim to remove spaces before line that has selection no matter what is selected.
+ // Here we remove only enough spaces to align text to nearest full multiple of indentation_size.
+ // In case where selection begins at the start of indentation_size multiple we remove whole indentation level.
+ int spaces_to_remove = _calculate_spaces_till_next_left_indent(get_first_non_whitespace_column(i));
+ line_text = line_text.substr(spaces_to_remove, line_text.length());
- set_line(i, line_text);
- removed_characters = spaces_to_remove;
+ set_line(i, line_text);
+ removed_characters = spaces_to_remove;
- first_line_edited = (i == start_line) ? true : first_line_edited;
- last_line_edited = (i == end_line) ? true : last_line_edited;
+ first_line_edited = (i == start_line) ? true : first_line_edited;
+ last_line_edited = (i == end_line) ? true : last_line_edited;
+ }
}
- }
- if (has_selection()) {
- /* Fix selection being off by one on the first line. */
- if (first_line_edited) {
- select(get_selection_from_line(), get_selection_from_column() - removed_characters, get_selection_to_line(), initial_selection_end_column);
- }
+ if (has_selection(c)) {
+ // Fix selection being off by one on the first line.
+ if (first_line_edited) {
+ select(get_selection_from_line(c), get_selection_from_column(c) - removed_characters, get_selection_to_line(c), initial_selection_end_column, c);
+ }
- /* Fix selection being off by one on the last line. */
- if (last_line_edited) {
- select(get_selection_from_line(), get_selection_from_column(), get_selection_to_line(), initial_selection_end_column - removed_characters);
+ // Fix selection being off by one on the last line.
+ if (last_line_edited) {
+ select(get_selection_from_line(c), get_selection_from_column(c), get_selection_to_line(c), initial_selection_end_column - removed_characters, c);
+ }
}
+ set_caret_column(initial_cursor_column - removed_characters, false, c);
}
- set_caret_column(initial_cursor_column - removed_characters, false);
-
end_complex_operation();
}
@@ -990,106 +1033,108 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
return;
}
- /* When not splitting the line, we need to factor in indentation from the end of the current line. */
- const int cc = p_split_current_line ? get_caret_column() : get_line(get_caret_line()).length();
- const int cl = get_caret_line();
-
- const String line = get_line(cl);
-
- String ins = "\n";
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ // When not splitting the line, we need to factor in indentation from the end of the current line.
+ const int cc = p_split_current_line ? get_caret_column(i) : get_line(get_caret_line(i)).length();
+ const int cl = get_caret_line(i);
- /* Append current indentation. */
- int space_count = 0;
- int line_col = 0;
- for (; line_col < cc; line_col++) {
- if (line[line_col] == '\t') {
- ins += indent_text;
- space_count = 0;
- continue;
- }
+ const String line = get_line(cl);
- if (line[line_col] == ' ') {
- space_count++;
+ String ins = "\n";
- if (space_count == indent_size) {
+ // Append current indentation.
+ int space_count = 0;
+ int line_col = 0;
+ for (; line_col < cc; line_col++) {
+ if (line[line_col] == '\t') {
ins += indent_text;
space_count = 0;
+ continue;
}
- continue;
- }
- break;
- }
- if (is_line_folded(cl)) {
- unfold_line(cl);
- }
-
- /* Indent once again if the previous line needs it, ie ':'. */
- /* Then add an addition new line for any closing pairs aka '()'. */
- /* Skip this in comments or if we are going above. */
- bool brace_indent = false;
- if (auto_indent && !p_above && cc > 0 && is_in_comment(cl) == -1) {
- bool should_indent = false;
- char32_t indent_char = ' ';
+ if (line[line_col] == ' ') {
+ space_count++;
- for (; line_col < cc; line_col++) {
- char32_t c = line[line_col];
- if (auto_indent_prefixes.has(c)) {
- should_indent = true;
- indent_char = c;
+ if (space_count == indent_size) {
+ ins += indent_text;
+ space_count = 0;
+ }
continue;
}
+ break;
+ }
- /* Make sure this is the last char, trailing whitespace or comments are okay. */
- /* Increment column for comments because the delimiter (#) should be ignored. */
- if (should_indent && (!is_whitespace(c) && is_in_comment(cl, line_col + 1) == -1)) {
- should_indent = false;
- }
+ if (is_line_folded(cl)) {
+ unfold_line(cl);
}
- if (should_indent) {
- ins += indent_text;
+ // Indent once again if the previous line needs it, ie ':'.
+ // Then add an addition new line for any closing pairs aka '()'.
+ // Skip this in comments or if we are going above.
+ bool brace_indent = false;
+ if (auto_indent && !p_above && cc > 0 && is_in_comment(cl) == -1) {
+ bool should_indent = false;
+ char32_t indent_char = ' ';
- String closing_pair = get_auto_brace_completion_close_key(String::chr(indent_char));
- if (!closing_pair.is_empty() && line.find(closing_pair, cc) == cc) {
- /* No need to move the brace below if we are not taking the text with us. */
- if (p_split_current_line) {
- brace_indent = true;
- ins += "\n" + ins.substr(indent_text.size(), ins.length() - 2);
- } else {
- brace_indent = false;
- ins = "\n" + ins.substr(indent_text.size(), ins.length() - 2);
+ for (; line_col < cc; line_col++) {
+ char32_t c = line[line_col];
+ if (auto_indent_prefixes.has(c)) {
+ should_indent = true;
+ indent_char = c;
+ continue;
+ }
+
+ // Make sure this is the last char, trailing whitespace or comments are okay.
+ // Increment column for comments because the delimiter (#) should be ignored.
+ if (should_indent && (!is_whitespace(c) && is_in_comment(cl, line_col + 1) == -1)) {
+ should_indent = false;
}
}
- }
- }
- begin_complex_operation();
+ if (should_indent) {
+ ins += indent_text;
- bool first_line = false;
- if (!p_split_current_line) {
- deselect();
+ String closing_pair = get_auto_brace_completion_close_key(String::chr(indent_char));
+ if (!closing_pair.is_empty() && line.find(closing_pair, cc) == cc) {
+ // No need to move the brace below if we are not taking the text with us.
+ if (p_split_current_line) {
+ brace_indent = true;
+ ins += "\n" + ins.substr(indent_text.size(), ins.length() - 2);
+ } else {
+ brace_indent = false;
+ ins = "\n" + ins.substr(indent_text.size(), ins.length() - 2);
+ }
+ }
+ }
+ }
- if (p_above) {
- if (cl > 0) {
- set_caret_line(cl - 1, false);
- set_caret_column(get_line(get_caret_line()).length());
+ bool first_line = false;
+ if (!p_split_current_line) {
+ deselect(i);
+
+ if (p_above) {
+ if (cl > 0) {
+ set_caret_line(cl - 1, false, true, 0, i);
+ set_caret_column(get_line(get_caret_line(i)).length(), i == 0, i);
+ } else {
+ set_caret_column(0, i == 0, i);
+ first_line = true;
+ }
} else {
- set_caret_column(0);
- first_line = true;
+ set_caret_column(line.length(), i == 0, i);
}
- } else {
- set_caret_column(line.length());
}
- }
- insert_text_at_caret(ins);
+ insert_text_at_caret(ins, i);
- if (first_line) {
- set_caret_line(0);
- } else if (brace_indent) {
- set_caret_line(get_caret_line() - 1, false);
- set_caret_column(get_line(get_caret_line()).length());
+ if (first_line) {
+ set_caret_line(0, i == 0, true, 0, i);
+ } else if (brace_indent) {
+ set_caret_line(get_caret_line(i) - 1, false, true, 0, i);
+ set_caret_column(get_line(get_caret_line(i)).length(), i == 0, i);
+ }
}
end_complex_operation();
@@ -1216,37 +1261,41 @@ 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);
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
+
+ Color use_color = breakpoint_color;
+ if (hovering && !shift_pressed) {
+ use_color = breakpointed ? use_color.lightened(0.3) : use_color.darkened(0.5);
+ }
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
-
- // 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 && bookmark_icon.is_valid()) {
- bool hovering = p_region.has_point(get_local_mouse_pos());
bool bookmarked = is_line_bookmarked(p_line);
+ bool hovering = p_region.has_point(get_local_mouse_pos());
+ bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) {
int horizontal_padding = p_region.size.x / 2;
int vertical_padding = p_region.size.y / 4;
+
+ Color use_color = bookmark_color;
+ if (hovering && shift_pressed) {
+ use_color = bookmarked ? use_color.lightened(0.3) : use_color.darkened(0.5);
+ }
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);
}
}
@@ -1255,10 +1304,10 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
int horizontal_padding = p_region.size.x / 10;
int vertical_padding = p_region.size.y / 4;
- Rect2 executing_line_region = p_region;
- executing_line_region.position += Point2(horizontal_padding, vertical_padding);
- executing_line_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- executing_line_icon->draw_rect(get_canvas_item(), executing_line_region, false, executing_line_color);
+ Rect2 icon_region = p_region;
+ icon_region.position += Point2(horizontal_padding, vertical_padding);
+ icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
+ executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, executing_line_color);
}
}
@@ -1522,22 +1571,26 @@ void CodeEdit::fold_line(int p_line) {
_set_line_as_hidden(i, true);
}
- /* Fix selection. */
- if (has_selection()) {
- if (_is_line_hidden(get_selection_from_line()) && _is_line_hidden(get_selection_to_line())) {
- deselect();
- } else if (_is_line_hidden(get_selection_from_line())) {
- select(p_line, 9999, get_selection_to_line(), get_selection_to_column());
- } else if (_is_line_hidden(get_selection_to_line())) {
- select(get_selection_from_line(), get_selection_from_column(), p_line, 9999);
+ for (int i = 0; i < get_caret_count(); i++) {
+ // Fix selection.
+ if (has_selection(i)) {
+ if (_is_line_hidden(get_selection_from_line(i)) && _is_line_hidden(get_selection_to_line(i))) {
+ deselect(i);
+ } else if (_is_line_hidden(get_selection_from_line(i))) {
+ select(p_line, 9999, get_selection_to_line(i), get_selection_to_column(i), i);
+ } else if (_is_line_hidden(get_selection_to_line(i))) {
+ select(get_selection_from_line(i), get_selection_from_column(i), p_line, 9999, i);
+ }
}
- }
- /* Reset caret. */
- if (_is_line_hidden(get_caret_line())) {
- set_caret_line(p_line, false, false);
- set_caret_column(get_line(p_line).length(), false);
+ // Reset caret.
+ if (_is_line_hidden(get_caret_line(i))) {
+ set_caret_line(p_line, false, false, 0, i);
+ set_caret_column(get_line(p_line).length(), false, i);
+ }
}
+
+ merge_overlapping_carets();
queue_redraw();
}
@@ -1938,6 +1991,7 @@ void CodeEdit::set_code_completion_selected_index(int p_index) {
}
ERR_FAIL_INDEX(p_index, code_completion_options.size());
code_completion_current_selected = p_index;
+ code_completion_force_item_center = -1;
queue_redraw();
}
@@ -1950,98 +2004,108 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
return;
}
+ char32_t caret_last_completion_char;
begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ int caret_line = get_caret_line(i);
+
+ const String &insert_text = code_completion_options[code_completion_current_selected].insert_text;
+ const String &display_text = code_completion_options[code_completion_current_selected].display;
+
+ if (p_replace) {
+ // Find end of current section.
+ const String line = get_line(caret_line);
+ int caret_col = get_caret_column(i);
+ int caret_remove_line = caret_line;
+
+ bool merge_text = true;
+ int in_string = is_in_string(caret_line, caret_col);
+ if (in_string != -1) {
+ Point2 string_end = get_delimiter_end_position(caret_line, caret_col);
+ if (string_end.x != -1) {
+ merge_text = false;
+ caret_remove_line = string_end.y;
+ caret_col = string_end.x - 1;
+ }
+ }
- int caret_line = get_caret_line();
-
- const String &insert_text = code_completion_options[code_completion_current_selected].insert_text;
- const String &display_text = code_completion_options[code_completion_current_selected].display;
-
- if (p_replace) {
- /* Find end of current section */
- const String line = get_line(caret_line);
- int caret_col = get_caret_column();
- int caret_remove_line = caret_line;
-
- bool merge_text = true;
- int in_string = is_in_string(caret_line, caret_col);
- if (in_string != -1) {
- Point2 string_end = get_delimiter_end_position(caret_line, caret_col);
- if (string_end.x != -1) {
- merge_text = false;
- caret_remove_line = string_end.y;
- caret_col = string_end.x - 1;
+ if (merge_text) {
+ for (; caret_col < line.length(); caret_col++) {
+ if (is_symbol(line[caret_col])) {
+ break;
+ }
+ }
}
- }
- if (merge_text) {
- for (; caret_col < line.length(); caret_col++) {
- if (is_symbol(line[caret_col])) {
+ // Replace.
+ remove_text(caret_line, get_caret_column(i) - code_completion_base.length(), caret_remove_line, caret_col);
+ adjust_carets_after_edit(i, caret_line, caret_col - code_completion_base.length(), caret_remove_line, caret_col);
+ set_caret_column(get_caret_column(i) - code_completion_base.length(), false, i);
+ insert_text_at_caret(insert_text, i);
+ } else {
+ // Get first non-matching char.
+ const String line = get_line(caret_line);
+ int caret_col = get_caret_column(i);
+ int matching_chars = code_completion_base.length();
+ for (; matching_chars <= insert_text.length(); matching_chars++) {
+ if (caret_col >= line.length() || line[caret_col] != insert_text[matching_chars]) {
break;
}
+ caret_col++;
}
+
+ // Remove base completion text.
+ remove_text(caret_line, get_caret_column(i) - code_completion_base.length(), caret_line, get_caret_column(i));
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i) - code_completion_base.length(), caret_line, get_caret_column(i));
+ set_caret_column(get_caret_column(i) - code_completion_base.length(), false, i);
+
+ // Merge with text.
+ insert_text_at_caret(insert_text.substr(0, code_completion_base.length()), i);
+ set_caret_column(caret_col, false, i);
+ insert_text_at_caret(insert_text.substr(matching_chars), i);
}
- /* Replace. */
- remove_text(caret_line, get_caret_column() - code_completion_base.length(), caret_remove_line, caret_col);
- set_caret_column(get_caret_column() - code_completion_base.length(), false);
- insert_text_at_caret(insert_text);
- } else {
- /* Get first non-matching char. */
+ //* Handle merging of symbols eg strings, brackets.
const String line = get_line(caret_line);
- int caret_col = get_caret_column();
- int matching_chars = code_completion_base.length();
- for (; matching_chars <= insert_text.length(); matching_chars++) {
- if (caret_col >= line.length() || line[caret_col] != insert_text[matching_chars]) {
- break;
- }
- caret_col++;
+ char32_t next_char = line[get_caret_column(i)];
+ char32_t last_completion_char = insert_text[insert_text.length() - 1];
+ if (i == 0) {
+ caret_last_completion_char = last_completion_char;
}
+ char32_t last_completion_char_display = display_text[display_text.length() - 1];
- /* Remove base completion text. */
- remove_text(caret_line, get_caret_column() - code_completion_base.length(), caret_line, get_caret_column());
- set_caret_column(get_caret_column() - code_completion_base.length(), false);
-
- /* Merge with text. */
- insert_text_at_caret(insert_text.substr(0, code_completion_base.length()));
- set_caret_column(caret_col, false);
- insert_text_at_caret(insert_text.substr(matching_chars));
- }
-
- /* Handle merging of symbols eg strings, brackets. */
- const String line = get_line(caret_line);
- char32_t next_char = line[get_caret_column()];
- char32_t last_completion_char = insert_text[insert_text.length() - 1];
- char32_t last_completion_char_display = display_text[display_text.length() - 1];
-
- int pre_brace_pair = get_caret_column() > 0 ? _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column()) : -1;
- int post_brace_pair = get_caret_column() < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column()) : -1;
+ int pre_brace_pair = get_caret_column(i) > 0 ? _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column(i)) : -1;
+ int post_brace_pair = get_caret_column(i) < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i)) : -1;
- if (post_brace_pair != -1 && (last_completion_char == next_char || last_completion_char_display == next_char)) {
- remove_text(caret_line, get_caret_column(), caret_line, get_caret_column() + 1);
- }
+ if (post_brace_pair != -1 && (last_completion_char == next_char || last_completion_char_display == next_char)) {
+ remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ }
- if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && (last_completion_char == next_char || last_completion_char_display == next_char)) {
- remove_text(caret_line, get_caret_column(), caret_line, get_caret_column() + 1);
- } else if (auto_brace_completion_enabled && pre_brace_pair != -1 && post_brace_pair == -1) {
- insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key);
- set_caret_column(get_caret_column() - auto_brace_completion_pairs[pre_brace_pair].close_key.length());
- }
+ if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && (last_completion_char == next_char || last_completion_char_display == next_char)) {
+ remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ } else if (auto_brace_completion_enabled && pre_brace_pair != -1 && post_brace_pair == -1) {
+ insert_text_at_caret(auto_brace_completion_pairs[pre_brace_pair].close_key, i);
+ set_caret_column(get_caret_column(i) - auto_brace_completion_pairs[pre_brace_pair].close_key.length(), i == 0, i);
+ }
- if (pre_brace_pair == -1 && post_brace_pair == -1 && get_caret_column() > 0 && get_caret_column() < get_line(caret_line).length()) {
- pre_brace_pair = _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column() + 1);
- if (pre_brace_pair != -1 && pre_brace_pair == _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column() - 1)) {
- remove_text(caret_line, get_caret_column() - 2, caret_line, get_caret_column());
- if (_get_auto_brace_pair_close_at_pos(caret_line, get_caret_column() - 1) != pre_brace_pair) {
- set_caret_column(get_caret_column() - 1);
+ if (pre_brace_pair == -1 && post_brace_pair == -1 && get_caret_column(i) > 0 && get_caret_column(i) < get_line(caret_line).length()) {
+ pre_brace_pair = _get_auto_brace_pair_open_at_pos(caret_line, get_caret_column(i) + 1);
+ if (pre_brace_pair != -1 && pre_brace_pair == _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i) - 1)) {
+ remove_text(caret_line, get_caret_column(i) - 2, caret_line, get_caret_column(i));
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i) - 2, caret_line, get_caret_column(i));
+ if (_get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i) - 1) != pre_brace_pair) {
+ set_caret_column(get_caret_column(i) - 1, i == 0, i);
+ }
}
}
}
-
end_complex_operation();
cancel_code_completion();
- if (code_completion_prefixes.has(last_completion_char)) {
+ if (code_completion_prefixes.has(caret_last_completion_char)) {
request_code_completion();
}
}
@@ -2089,15 +2153,15 @@ String CodeEdit::get_text_for_symbol_lookup() {
StringBuilder lookup_text;
const int text_size = get_line_count();
for (int i = 0; i < text_size; i++) {
- String text = get_line(i);
+ String line_text = get_line(i);
if (i == line) {
- lookup_text += text.substr(0, col);
+ lookup_text += line_text.substr(0, col);
/* Not unicode, represents the cursor. */
lookup_text += String::chr(0xFFFF);
- lookup_text += text.substr(col, text.size());
+ lookup_text += line_text.substr(col, line_text.size());
} else {
- lookup_text += text;
+ lookup_text += line_text;
}
if (i != text_size - 1) {
@@ -2399,6 +2463,7 @@ void CodeEdit::_gutter_clicked(int p_line, int p_gutter) {
}
if (p_gutter == line_number_gutter) {
+ remove_secondary_carets();
set_selection_mode(TextEdit::SelectionMode::SELECTION_MODE_LINE, p_line, 0);
select(p_line, 0, p_line + 1, 0);
set_caret_line(p_line + 1);
@@ -2757,6 +2822,7 @@ void CodeEdit::_update_scroll_selected_line(float p_mouse_y) {
percent = CLAMP(percent, 0.0f, 1.0f);
code_completion_current_selected = (int)(percent * (code_completion_options.size() - 1));
+ code_completion_force_item_center = -1;
}
void CodeEdit::_filter_code_completion_candidates_impl() {
@@ -2808,12 +2874,15 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
offset = line_height;
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
code_completion_options.push_back(option);
}
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
return;
@@ -2919,7 +2988,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (string_to_complete.length() == 0) {
code_completion_options.push_back(option);
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
continue;
}
@@ -3025,7 +3096,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_matches);
completion_options_subseq.push_back(option);
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
} else if (!*ssq_lower) { // Matched the whole subsequence in s_lower.
option.matches.clear();
@@ -3042,7 +3115,9 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_lower_matches);
completion_options_subseq_casei.push_back(option);
}
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (font.is_valid()) {
+ max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ }
}
}
@@ -3064,6 +3139,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
code_completion_current_selected = 0;
+ code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
}
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 2065f3e681..cbbc13480e 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -214,6 +214,7 @@ private:
Vector<ScriptLanguage::CodeCompletionOption> code_completion_options;
int code_completion_line_ofs = 0;
int code_completion_current_selected = 0;
+ int code_completion_force_item_center = -1;
int code_completion_longest_line = 0;
Rect2i code_completion_rect;
Rect2i code_completion_scroll_rect;
@@ -261,8 +262,8 @@ protected:
/* Text manipulation */
// Overridable actions
- virtual void _handle_unicode_input_internal(const uint32_t p_unicode) override;
- virtual void _backspace_internal() override;
+ virtual void _handle_unicode_input_internal(const uint32_t p_unicode, int p_caret) override;
+ virtual void _backspace_internal(int p_caret) override;
GDVIRTUAL1(_confirm_code_completion, bool)
GDVIRTUAL1(_request_code_completion, bool)
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index ebd86e0937..a063cd344a 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -73,10 +73,10 @@ void ColorModeRGB::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 4 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->get_theme_default_base_scale();
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -97,10 +97,10 @@ void ColorModeRGB::slider_draw(int p_which) {
col.set(1, right_color);
col.set(2, right_color);
col.set(3, left_color);
- pos.set(0, Vector2(0, margin));
- pos.set(1, Vector2(size.x, margin));
- pos.set(2, Vector2(size.x, margin * 2));
- pos.set(3, Vector2(0, margin * 2));
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x, 0));
+ pos.set(2, Vector2(size.x, margin));
+ pos.set(3, Vector2(0, margin));
slider->draw_polygon(pos, col);
}
@@ -147,10 +147,10 @@ void ColorModeHSV::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 4 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->get_theme_default_base_scale();
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -159,7 +159,7 @@ void ColorModeHSV::slider_draw(int p_which) {
} else if (p_which == 0) {
Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false);
+ slider->draw_texture_rect(hue, Rect2(Vector2(margin * -1, 0), Vector2(margin, size.x)), false);
return;
} else {
Color s_col;
@@ -174,10 +174,10 @@ void ColorModeHSV::slider_draw(int p_which) {
col.set(1, right_color);
col.set(2, right_color);
col.set(3, left_color);
- pos.set(0, Vector2(0, margin));
- pos.set(1, Vector2(size.x, margin));
- pos.set(2, Vector2(size.x, margin * 2));
- pos.set(3, Vector2(0, margin * 2));
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x, 0));
+ pos.set(2, Vector2(size.x, margin));
+ pos.set(3, Vector2(0, margin));
slider->draw_polygon(pos, col);
}
@@ -216,10 +216,10 @@ void ColorModeRAW::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 4 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->get_theme_default_base_scale();
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -230,10 +230,10 @@ void ColorModeRAW::slider_draw(int p_which) {
col.set(1, right_color);
col.set(2, right_color);
col.set(3, left_color);
- pos.set(0, Vector2(0, margin));
- pos.set(1, Vector2(size.x, margin));
- pos.set(2, Vector2(size.x, margin * 2));
- pos.set(3, Vector2(0, margin * 2));
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x, 0));
+ pos.set(2, Vector2(size.x, margin));
+ pos.set(3, Vector2(0, margin));
slider->draw_polygon(pos, col);
}
@@ -245,8 +245,7 @@ bool ColorModeRAW::apply_theme() const {
slider->remove_theme_icon_override("grabber");
slider->remove_theme_icon_override("grabber_highlight");
slider->remove_theme_style_override("slider");
- slider->remove_theme_style_override("grabber_area");
- slider->remove_theme_style_override("grabber_area_highlight");
+ slider->remove_theme_constant_override("grabber_offset");
}
return true;
@@ -285,46 +284,68 @@ Color ColorModeOKHSL::get_color() const {
}
void ColorModeOKHSL::slider_draw(int p_which) {
- Vector<Vector2> pos;
- pos.resize(4);
- Vector<Color> col;
- col.resize(4);
HSlider *slider = color_picker->get_slider(p_which);
Size2 size = slider->get_size();
+ const real_t margin = 16 * color_picker->get_theme_default_base_scale();
+
+ if (p_which == 0) { // H
+ Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
+ slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
+ slider->draw_texture_rect(hue, Rect2(Vector2(margin * -1, 0), Vector2(margin, size.x)), false);
+ return;
+ }
+
+ Vector<Vector2> pos;
+ Vector<Color> col;
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 4 * color_picker->get_theme_default_base_scale();
- if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+ if (p_which == 2) { // L
+ pos.resize(6);
+ col.resize(6);
+ left_color = Color(0, 0, 0);
+ Color middle_color;
+ middle_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 0.5);
+ right_color.set_ok_hsl(color.get_ok_hsl_h(), color.get_ok_hsl_s(), 1);
- left_color = color;
- left_color.a = 0;
- right_color = color;
- right_color.a = 1;
- } else if (p_which == 0) {
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
- slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false);
- return;
- } else {
- Color s_col;
- Color v_col;
- s_col.set_ok_hsl(color.get_h(), 0, color.get_v());
- left_color = (p_which == 1) ? s_col : Color(0, 0, 0);
- s_col.set_ok_hsl(color.get_h(), 1, color.get_v());
- v_col.set_ok_hsl(color.get_h(), color.get_s(), 1);
- right_color = (p_which == 1) ? s_col : v_col;
+ col.set(0, left_color);
+ col.set(1, middle_color);
+ col.set(2, right_color);
+ col.set(3, right_color);
+ col.set(4, middle_color);
+ col.set(5, left_color);
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x * 0.5, 0));
+ pos.set(2, Vector2(size.x, 0));
+ pos.set(3, Vector2(size.x, margin));
+ pos.set(4, Vector2(size.x * 0.5, margin));
+ pos.set(5, Vector2(0, margin));
+ } else { // A / S
+ pos.resize(4);
+ col.resize(4);
+
+ if (p_which == ColorPicker::SLIDER_COUNT) {
+ slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+
+ left_color = color;
+ left_color.a = 0;
+ right_color = color;
+ right_color.a = 1;
+ } else {
+ left_color.set_ok_hsl(color.get_ok_hsl_h(), 0, color.get_ok_hsl_l());
+ right_color.set_ok_hsl(color.get_ok_hsl_h(), 1, color.get_ok_hsl_l());
+ }
+
+ col.set(0, left_color);
+ col.set(1, right_color);
+ col.set(2, right_color);
+ col.set(3, left_color);
+ pos.set(0, Vector2(0, 0));
+ pos.set(1, Vector2(size.x, 0));
+ pos.set(2, Vector2(size.x, margin));
+ pos.set(3, Vector2(0, margin));
}
- col.set(0, left_color);
- col.set(1, right_color);
- col.set(2, right_color);
- col.set(3, left_color);
- pos.set(0, Vector2(0, margin));
- pos.set(1, Vector2(size.x, margin));
- pos.set(2, Vector2(size.x, margin * 2));
- pos.set(3, Vector2(0, margin * 2));
slider->draw_polygon(pos, col);
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 5751c54877..1b87c1d709 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -44,6 +44,7 @@
#include "thirdparty/misc/ok_color_shader.h"
List<Color> ColorPicker::preset_cache;
+List<Color> ColorPicker::recent_preset_cache;
void ColorPicker::_notification(int p_what) {
switch (p_what) {
@@ -61,14 +62,31 @@ void ColorPicker::_notification(int p_what) {
for (int i = 0; i < preset_cache.size(); i++) {
presets.push_back(preset_cache[i]);
}
+
+ if (recent_preset_cache.is_empty()) {
+ PackedColorArray saved_recent_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "recent_presets", PackedColorArray());
+ for (int i = 0; i < saved_recent_presets.size(); i++) {
+ recent_preset_cache.push_back(saved_recent_presets[i]);
+ }
+ }
+
+ for (int i = 0; i < recent_preset_cache.size(); i++) {
+ recent_presets.push_back(recent_preset_cache[i]);
+ }
}
#endif
[[fallthrough]];
}
case NOTIFICATION_THEME_CHANGED: {
btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
+ _update_drop_down_arrow(btn_preset->is_pressed(), btn_preset);
+ _update_drop_down_arrow(btn_recent_preset->is_pressed(), btn_recent_preset);
btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
+ btn_pick->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0));
+ btn_shape->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0));
+ btn_mode->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0));
+
uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0));
@@ -90,12 +108,13 @@ void ColorPicker::_notification(int p_what) {
}
_update_presets();
+ _update_recent_presets();
_update_controls();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
Popup *p = Object::cast_to<Popup>(get_parent());
- if (p) {
+ if (p && is_visible_in_tree()) {
p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant(SNAME("margin")) * 2, get_combined_minimum_size().height + get_theme_constant(SNAME("margin")) * 2));
}
} break;
@@ -262,6 +281,11 @@ void ColorPicker::_update_controls() {
}
void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
+ if (text_changed) {
+ add_recent_preset(color);
+ text_changed = false;
+ }
+
color = p_color;
if (color != last_color) {
_copy_color_to_hsv();
@@ -330,55 +354,61 @@ void ColorPicker::_value_changed(double) {
void ColorPicker::add_mode(ColorMode *p_mode) {
modes.push_back(p_mode);
- mode_option_button->add_item(RTR(p_mode->get_name()));
}
void ColorPicker::create_slider(GridContainer *gc, int idx) {
- Label *l = memnew(Label());
- l->set_v_size_flags(SIZE_SHRINK_CENTER);
- gc->add_child(l);
+ Label *lbl = memnew(Label());
+ lbl->set_v_size_flags(SIZE_SHRINK_CENTER);
+ gc->add_child(lbl);
- HSlider *s = memnew(HSlider);
- s->set_v_size_flags(SIZE_SHRINK_CENTER);
- s->set_focus_mode(FOCUS_NONE);
- gc->add_child(s);
+ HSlider *slider = memnew(HSlider);
+ slider->set_v_size_flags(SIZE_SHRINK_CENTER);
+ slider->set_focus_mode(FOCUS_NONE);
+ gc->add_child(slider);
- SpinBox *v = memnew(SpinBox);
- s->share(v);
- gc->add_child(v);
- v->get_line_edit()->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter));
- v->get_line_edit()->connect("focus_exited", callable_mp(this, &ColorPicker::_focus_exit));
+ SpinBox *val = memnew(SpinBox);
+ slider->share(val);
+ val->set_select_all_on_focus(true);
+ gc->add_child(val);
- s->set_h_size_flags(SIZE_EXPAND_FILL);
+ LineEdit *vle = val->get_line_edit();
+ vle->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
+ vle->connect("gui_input", callable_mp(this, &ColorPicker::_line_edit_input));
+ vle->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- s->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed));
- s->connect("draw", callable_mp(this, &ColorPicker::_slider_draw).bind(idx));
+ val->connect("gui_input", callable_mp(this, &ColorPicker::_slider_or_spin_input));
+
+ slider->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ slider->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed));
+ slider->connect("draw", callable_mp(this, &ColorPicker::_slider_draw).bind(idx));
+ slider->connect("gui_input", callable_mp(this, &ColorPicker::_slider_or_spin_input));
if (idx < SLIDER_COUNT) {
- sliders[idx] = s;
- values[idx] = v;
- labels[idx] = l;
+ sliders[idx] = slider;
+ values[idx] = val;
+ labels[idx] = lbl;
} else {
- alpha_slider = s;
- alpha_value = v;
- alpha_label = l;
+ alpha_slider = slider;
+ alpha_value = val;
+ alpha_label = lbl;
}
}
-HSlider *ColorPicker::get_slider(int idx) {
- if (idx < SLIDER_COUNT) {
- return sliders[idx];
+HSlider *ColorPicker::get_slider(int p_idx) {
+ if (p_idx < SLIDER_COUNT) {
+ return sliders[p_idx];
}
return alpha_slider;
}
Vector<float> ColorPicker::get_active_slider_values() {
- Vector<float> values;
+ Vector<float> cur_values;
for (int i = 0; i < current_slider_count; i++) {
- values.push_back(sliders[i]->get_value());
+ cur_values.push_back(sliders[i]->get_value());
}
- values.push_back(alpha_slider->get_value());
- return values;
+ cur_values.push_back(alpha_slider->get_value());
+ return cur_values;
}
void ColorPicker::_copy_color_to_hsv() {
@@ -401,25 +431,53 @@ void ColorPicker::_copy_hsv_to_color() {
}
}
+void ColorPicker::_select_from_preset_container(const Color &p_color) {
+ if (preset_group->get_pressed_button()) {
+ preset_group->get_pressed_button()->set_pressed(false);
+ }
+
+ for (int i = 1; i < preset_container->get_child_count(); i++) {
+ ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
+ if (current_btn && p_color == current_btn->get_preset_color()) {
+ current_btn->set_pressed(true);
+ break;
+ }
+ }
+}
+
+bool ColorPicker::_select_from_recent_preset_hbc(const Color &p_color) {
+ for (int i = 0; i < recent_preset_hbc->get_child_count(); i++) {
+ ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(recent_preset_hbc->get_child(i));
+ if (current_btn && p_color == current_btn->get_preset_color()) {
+ current_btn->set_pressed(true);
+ return true;
+ }
+ }
+ return false;
+}
+
ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const {
return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape;
}
void ColorPicker::_reset_theme() {
- Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
-
+ Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
+ style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
+ style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
for (int i = 0; i < SLIDER_COUNT; i++) {
sliders[i]->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker")));
sliders[i]->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker")));
- sliders[i]->add_theme_style_override("slider", style_box_empty);
- sliders[i]->add_theme_style_override("grabber_area", style_box_empty);
- sliders[i]->add_theme_style_override("grabber_area_highlight", style_box_empty);
+ sliders[i]->add_theme_constant_override("grabber_offset", 8 * get_theme_default_base_scale());
+ if (!colorize_sliders) {
+ sliders[i]->add_theme_style_override("slider", style_box_flat);
+ }
}
alpha_slider->add_theme_icon_override("grabber", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker")));
alpha_slider->add_theme_icon_override("grabber_highlight", get_theme_icon(SNAME("bar_arrow"), SNAME("ColorPicker")));
- alpha_slider->add_theme_style_override("slider", style_box_empty);
- alpha_slider->add_theme_style_override("grabber_area", style_box_empty);
- alpha_slider->add_theme_style_override("grabber_area_highlight", style_box_empty);
+ alpha_slider->add_theme_constant_override("grabber_offset", 8 * get_theme_default_base_scale());
+ if (!colorize_sliders) {
+ alpha_slider->add_theme_style_override("slider", style_box_flat);
+ }
}
void ColorPicker::_html_submitted(const String &p_html) {
@@ -484,13 +542,41 @@ void ColorPicker::_update_presets() {
cpb->set_custom_minimum_size(Size2(preset_size, preset_size));
}
}
- // Only load preset buttons when the only child is the add-preset button.
- if (preset_container->get_child_count() == 1) {
- for (int i = 0; i < preset_cache.size(); i++) {
- _add_preset_button(preset_size, preset_cache[i]);
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // Only load preset buttons when the only child is the add-preset button.
+ if (preset_container->get_child_count() == 1) {
+ for (int i = 0; i < preset_cache.size(); i++) {
+ _add_preset_button(preset_size, preset_cache[i]);
+ }
+ _notification(NOTIFICATION_VISIBILITY_CHANGED);
+ }
+ }
+#endif
+}
+
+void ColorPicker::_update_recent_presets() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ int recent_preset_count = recent_preset_hbc->get_child_count();
+ for (int i = 0; i < recent_preset_count; i++) {
+ memdelete(recent_preset_hbc->get_child(0));
+ }
+
+ recent_presets.clear();
+ for (int i = 0; i < recent_preset_cache.size(); i++) {
+ recent_presets.push_back(recent_preset_cache[i]);
+ }
+
+ int preset_size = _get_preset_size();
+ for (int i = 0; i < recent_presets.size(); i++) {
+ _add_recent_preset_button(preset_size, recent_presets[i]);
}
+
_notification(NOTIFICATION_VISIBILITY_CHANGED);
}
+#endif
}
void ColorPicker::_text_type_toggled() {
@@ -500,11 +586,13 @@ void ColorPicker::_text_type_toggled() {
text_type->set_icon(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")));
c_text->set_editable(false);
+ c_text->set_h_size_flags(SIZE_EXPAND_FILL);
} else {
text_type->set_text("#");
text_type->set_icon(nullptr);
c_text->set_editable(true);
+ c_text->set_h_size_flags(SIZE_FILL);
}
_update_color();
}
@@ -515,9 +603,14 @@ Color ColorPicker::get_pick_color() const {
void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
ERR_FAIL_INDEX(p_shape, SHAPE_MAX);
- if (current_shape == p_shape) {
+ if (p_shape == current_shape) {
return;
}
+ shape_popup->set_item_checked(current_shape, false);
+ shape_popup->set_item_checked(p_shape, true);
+
+ btn_shape->set_icon(shape_popup->get_item_icon(p_shape));
+
current_shape = p_shape;
_copy_color_to_hsv();
@@ -531,45 +624,105 @@ ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const {
}
inline int ColorPicker::_get_preset_size() {
- return (int(get_minimum_size().width) - (preset_container->get_theme_constant(SNAME("h_separation")) * (preset_column_count - 1))) / preset_column_count;
+ return (int(get_minimum_size().width) - (preset_container->get_theme_constant(SNAME("h_separation")) * (PRESET_COLUMN_COUNT - 1))) / PRESET_COLUMN_COUNT;
}
void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
- ColorPresetButton *btn_preset = memnew(ColorPresetButton(p_color));
- btn_preset->set_preset_color(p_color);
- btn_preset->set_custom_minimum_size(Size2(p_size, p_size));
- btn_preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input).bind(p_color));
- btn_preset->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
- preset_container->add_child(btn_preset);
+ ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));
+ btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
+ btn_preset_new->set_drag_forwarding(this);
+ btn_preset_new->set_button_group(preset_group);
+ preset_container->add_child(btn_preset_new);
+ btn_preset_new->set_pressed(true);
+ btn_preset_new->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input).bind(p_color));
+}
+
+void ColorPicker::_add_recent_preset_button(int p_size, const Color &p_color) {
+ ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));
+ btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color"), p_color.to_html(p_color.a < 1)));
+ btn_preset_new->set_button_group(recent_preset_group);
+ recent_preset_hbc->add_child(btn_preset_new);
+ recent_preset_hbc->move_child(btn_preset_new, 0);
+ btn_preset_new->set_pressed(true);
+ btn_preset_new->connect("toggled", callable_mp(this, &ColorPicker::_recent_preset_pressed).bind(btn_preset_new));
+}
+
+void ColorPicker::_show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container) {
+ if (p_is_btn_pressed) {
+ p_preset_container->show();
+ } else {
+ p_preset_container->hide();
+ }
+ _update_drop_down_arrow(p_is_btn_pressed, p_btn_preset);
}
-void ColorPicker::_set_color_mode(ColorModeType p_mode) {
- if (slider_theme_modified) {
- _reset_theme();
+void ColorPicker::_update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset) {
+ if (p_is_btn_pressed) {
+ p_btn_preset->set_icon(get_theme_icon(SNAME("expanded_arrow"), SNAME("ColorPicker")));
+ } else {
+ p_btn_preset->set_icon(get_theme_icon(SNAME("folded_arrow"), SNAME("ColorPicker")));
}
+}
- current_mode = p_mode;
+void ColorPicker::_set_mode_popup_value(ColorModeType p_mode) {
+ ERR_FAIL_INDEX(p_mode, MODE_MAX + 1);
- if (!is_inside_tree()) {
+ if (p_mode == MODE_MAX) {
+ set_colorize_sliders(!colorize_sliders);
+ } else {
+ set_color_mode(p_mode);
+ }
+}
+
+Variant ColorPicker::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) {
+ ColorPresetButton *dragged_preset_button = Object::cast_to<ColorPresetButton>(p_from_control);
+
+ if (!dragged_preset_button) {
+ return Variant();
+ }
+
+ ColorPresetButton *drag_preview = memnew(ColorPresetButton(dragged_preset_button->get_preset_color(), _get_preset_size()));
+ set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "color_preset";
+ drag_data["color_preset"] = dragged_preset_button->get_index();
+
+ return drag_data;
+}
+
+bool ColorPicker::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const {
+ Dictionary d = p_data;
+ if (!d.has("type") || String(d["type"]) != "color_preset") {
+ return false;
+ }
+ return true;
+}
+
+void ColorPicker::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) {
+ Dictionary d = p_data;
+ if (!d.has("type")) {
return;
}
- _update_controls();
- _update_color();
+ if (String(d["type"]) == "color_preset") {
+ int preset_from_id = d["color_preset"];
+ int hover_now = p_from_control->get_index();
+
+ if (preset_from_id == hover_now || hover_now == -1) {
+ return;
+ }
+ preset_container->move_child(preset_container->get_child(preset_from_id), hover_now);
+ }
}
void ColorPicker::add_preset(const Color &p_color) {
- if (presets.find(p_color)) {
- presets.move_to_back(presets.find(p_color));
+ List<Color>::Element *e = presets.find(p_color);
+ if (e) {
+ presets.move_to_back(e);
+ preset_cache.move_to_back(preset_cache.find(p_color));
- // Find button to move to the end.
- for (int i = 1; i < preset_container->get_child_count(); i++) {
- ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
- if (current_btn && p_color == current_btn->get_preset_color()) {
- preset_container->move_child(current_btn, preset_container->get_child_count() - 1);
- break;
- }
- }
+ preset_container->move_child(preset_group->get_pressed_button(), preset_container->get_child_count() - 1);
} else {
presets.push_back(p_color);
preset_cache.push_back(p_color);
@@ -585,16 +738,38 @@ void ColorPicker::add_preset(const Color &p_color) {
#endif
}
+void ColorPicker::add_recent_preset(const Color &p_color) {
+ if (!_select_from_recent_preset_hbc(p_color)) {
+ if (recent_preset_hbc->get_child_count() >= PRESET_COLUMN_COUNT) {
+ recent_preset_cache.pop_front();
+ recent_presets.pop_front();
+ recent_preset_hbc->get_child(PRESET_COLUMN_COUNT - 1)->queue_free();
+ }
+ recent_presets.push_back(p_color);
+ recent_preset_cache.push_back(p_color);
+ _add_recent_preset_button(_get_preset_size(), p_color);
+ }
+ _select_from_preset_container(p_color);
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ PackedColorArray arr_to_save = get_recent_presets();
+ EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save);
+ }
+#endif
+}
+
void ColorPicker::erase_preset(const Color &p_color) {
- if (presets.find(p_color)) {
- presets.erase(presets.find(p_color));
+ List<Color>::Element *e = presets.find(p_color);
+ if (e) {
+ presets.erase(e);
preset_cache.erase(preset_cache.find(p_color));
// Find preset button to remove.
for (int i = 1; i < preset_container->get_child_count(); i++) {
ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
if (current_btn && p_color == current_btn->get_preset_color()) {
- current_btn->queue_delete();
+ current_btn->queue_free();
break;
}
}
@@ -608,6 +783,30 @@ void ColorPicker::erase_preset(const Color &p_color) {
}
}
+void ColorPicker::erase_recent_preset(const Color &p_color) {
+ List<Color>::Element *e = recent_presets.find(p_color);
+ if (e) {
+ recent_presets.erase(e);
+ recent_preset_cache.erase(recent_preset_cache.find(p_color));
+
+ // Find recent preset button to remove.
+ for (int i = 1; i < recent_preset_hbc->get_child_count(); i++) {
+ ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(recent_preset_hbc->get_child(i));
+ if (current_btn && p_color == current_btn->get_preset_color()) {
+ current_btn->queue_free();
+ break;
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ PackedColorArray arr_to_save = get_recent_presets();
+ EditorSettings::get_singleton()->set_project_metadata("color_picker", "recent_presets", arr_to_save);
+ }
+#endif
+ }
+}
+
PackedColorArray ColorPicker::get_presets() const {
PackedColorArray arr;
arr.resize(presets.size());
@@ -617,16 +816,84 @@ PackedColorArray ColorPicker::get_presets() const {
return arr;
}
+PackedColorArray ColorPicker::get_recent_presets() const {
+ PackedColorArray arr;
+ arr.resize(recent_presets.size());
+ for (int i = 0; i < recent_presets.size(); i++) {
+ arr.set(i, recent_presets[i]);
+ }
+ return arr;
+}
+
void ColorPicker::set_color_mode(ColorModeType p_mode) {
ERR_FAIL_INDEX(p_mode, MODE_MAX);
- mode_option_button->select(p_mode);
- _set_color_mode(p_mode);
+
+ if (current_mode == p_mode) {
+ return;
+ }
+
+ if (slider_theme_modified) {
+ _reset_theme();
+ }
+
+ mode_popup->set_item_checked(current_mode, false);
+ mode_popup->set_item_checked(p_mode, true);
+
+ if (p_mode < MODE_BUTTON_COUNT) {
+ mode_btns[p_mode]->set_pressed(true);
+ } else if (current_mode < MODE_BUTTON_COUNT) {
+ mode_btns[current_mode]->set_pressed(false);
+ }
+
+ current_mode = p_mode;
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ _update_controls();
+ _update_color();
}
ColorPicker::ColorModeType ColorPicker::get_color_mode() const {
return current_mode;
}
+void ColorPicker::set_colorize_sliders(bool p_colorize_sliders) {
+ if (colorize_sliders == p_colorize_sliders) {
+ return;
+ }
+
+ colorize_sliders = p_colorize_sliders;
+ mode_popup->set_item_checked(MODE_MAX + 1, colorize_sliders);
+
+ if (colorize_sliders) {
+ Ref<StyleBoxEmpty> style_box_empty(memnew(StyleBoxEmpty));
+
+ if (!slider_theme_modified) {
+ for (int i = 0; i < SLIDER_COUNT; i++) {
+ sliders[i]->add_theme_style_override("slider", style_box_empty);
+ }
+ }
+ alpha_slider->add_theme_style_override("slider", style_box_empty);
+ } else {
+ Ref<StyleBoxFlat> style_box_flat(memnew(StyleBoxFlat));
+ style_box_flat->set_default_margin(SIDE_TOP, 16 * get_theme_default_base_scale());
+ style_box_flat->set_bg_color(Color(0.2, 0.23, 0.31).lerp(Color(0, 0, 0, 1), 0.3).clamp());
+
+ if (!slider_theme_modified) {
+ for (int i = 0; i < SLIDER_COUNT; i++) {
+ sliders[i]->add_theme_style_override("slider", style_box_flat);
+ }
+ }
+ alpha_slider->add_theme_style_override("slider", style_box_flat);
+ }
+}
+
+bool ColorPicker::is_colorizing_sliders() const {
+ return colorize_sliders;
+}
+
void ColorPicker::set_deferred_mode(bool p_enabled) {
deferred_mode_enabled = p_enabled;
}
@@ -636,7 +903,7 @@ bool ColorPicker::is_deferred_mode() const {
}
void ColorPicker::_update_text_value() {
- bool visible = true;
+ bool text_visible = true;
if (text_is_constructor) {
String t = "Color(" + String::num(color.r) + ", " + String::num(color.g) + ", " + String::num(color.b);
if (edit_alpha && color.a < 1) {
@@ -648,13 +915,13 @@ void ColorPicker::_update_text_value() {
}
if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) {
- visible = false;
+ text_visible = false;
} else if (!text_is_constructor) {
c_text->set_text(color.to_html(edit_alpha && color.a < 1));
}
- text_type->set_visible(visible);
- c_text->set_visible(visible);
+ text_type->set_visible(text_visible);
+ c_text->set_visible(text_visible);
}
void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
@@ -819,16 +1086,24 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
Vector<Color> colors;
Color col;
col.set_ok_hsl(h, s, 1);
- points.resize(4);
- colors.resize(4);
- points.set(0, Vector2());
- points.set(1, Vector2(c->get_size().x, 0));
+ Color col2;
+ col2.set_ok_hsl(h, s, 0.5);
+ Color col3;
+ col3.set_ok_hsl(h, s, 0);
+ points.resize(6);
+ colors.resize(6);
+ points.set(0, Vector2(c->get_size().x, 0));
+ points.set(1, Vector2(c->get_size().x, c->get_size().y * 0.5));
points.set(2, c->get_size());
points.set(3, Vector2(0, c->get_size().y));
+ points.set(4, Vector2(0, c->get_size().y * 0.5));
+ points.set(5, Vector2());
colors.set(0, col);
- colors.set(1, col);
- colors.set(2, Color(0, 0, 0));
- colors.set(3, Color(0, 0, 0));
+ colors.set(1, col2);
+ colors.set(2, col3);
+ colors.set(3, col3);
+ colors.set(4, col2);
+ colors.set(5, col);
c->draw_polygon(points, colors);
int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
col.set_ok_hsl(h, 1, v);
@@ -862,17 +1137,19 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
}
void ColorPicker::_slider_draw(int p_which) {
- modes[current_mode]->slider_draw(p_which);
+ if (colorize_sliders) {
+ modes[current_mode]->slider_draw(p_which);
+ }
}
void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
Ref<InputEventMouseButton> bev = p_event;
- PickerShapeType current_picker = _get_actual_shape();
+ PickerShapeType actual_shape = _get_actual_shape();
if (bev.is_valid()) {
if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
Vector2 center = c->get_size() / 2.0;
- if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) {
+ if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
real_t dist = center.distance_to(bev->get_position());
if (dist <= center.x) {
real_t rad = center.angle_to_point(bev->get_position());
@@ -920,8 +1197,11 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
- } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
- emit_signal(SNAME("color_changed"), color);
+ } else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
+ if (deferred_mode_enabled) {
+ emit_signal(SNAME("color_changed"), color);
+ }
+ add_recent_preset(color);
changing_color = false;
spinning = false;
} else {
@@ -938,7 +1218,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
}
Vector2 center = c->get_size() / 2.0;
- if (current_picker == SHAPE_VHS_CIRCLE || current_picker == SHAPE_OKHSL_CIRCLE) {
+ if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
real_t dist = center.distance_to(mev->get_position());
real_t rad = center.angle_to_point(mev->get_position());
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
@@ -993,9 +1273,10 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
set_pick_color(color);
_update_color();
- if (!deferred_mode_enabled) {
+ if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
+ add_recent_preset(color);
emit_signal(SNAME("color_changed"), color);
- } else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
+ } else if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
}
@@ -1024,12 +1305,31 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
}
}
+void ColorPicker::_slider_or_spin_input(const Ref<InputEvent> &p_event) {
+ if (line_edit_mouse_release) {
+ line_edit_mouse_release = false;
+ return;
+ }
+ Ref<InputEventMouseButton> bev = p_event;
+ if (bev.is_valid() && !bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
+ add_recent_preset(color);
+ }
+}
+
+void ColorPicker::_line_edit_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseButton> bev = p_event;
+ if (bev.is_valid() && !bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
+ line_edit_mouse_release = true;
+ }
+}
+
void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_color) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
set_pick_color(p_color);
+ add_recent_preset(color);
emit_signal(SNAME("color_changed"), p_color);
} else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && presets_enabled) {
erase_preset(p_color);
@@ -1038,6 +1338,22 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_c
}
}
+void ColorPicker::_recent_preset_pressed(const bool p_pressed, ColorPresetButton *p_preset) {
+ if (!p_pressed) {
+ return;
+ }
+ set_pick_color(p_preset->get_preset_color());
+
+ recent_presets.move_to_back(recent_presets.find(p_preset->get_preset_color()));
+ List<Color>::Element *e = recent_preset_cache.find(p_preset->get_preset_color());
+ if (e) {
+ recent_preset_cache.move_to_back(e);
+ }
+
+ recent_preset_hbc->move_child(p_preset, 0);
+ emit_signal(SNAME("color_changed"), p_preset->get_preset_color());
+}
+
void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
if (!is_inside_tree()) {
return;
@@ -1058,7 +1374,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
Ref<Image> img = r->get_texture()->get_image();
if (img.is_valid() && !img->is_empty()) {
- Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
+ Vector2 ofs = mev->get_global_position();
Color c = img->get_pixel(ofs.x, ofs.y);
set_pick_color(c);
@@ -1066,6 +1382,10 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
}
}
+void ColorPicker::_text_changed(const String &) {
+ text_changed = true;
+}
+
void ColorPicker::_add_preset_pressed() {
add_preset(color);
emit_signal(SNAME("preset_added"), color);
@@ -1090,53 +1410,15 @@ void ColorPicker::_screen_pick_pressed() {
screen->show();
}
screen->move_to_front();
-#ifndef _MSC_VER
-#warning show modal no longer works, needs to be converted to a popup
-#endif
+ // TODO: show modal no longer works, needs to be converted to a popup.
//screen->show_modal();
}
-void ColorPicker::_focus_enter() {
- bool has_ctext_focus = c_text->has_focus();
- if (has_ctext_focus) {
- c_text->select_all();
- } else {
- c_text->select(0, 0);
- }
-
- for (int i = 0; i < current_slider_count; i++) {
- if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) {
- values[i]->get_line_edit()->select_all();
- } else {
- values[i]->get_line_edit()->select(0, 0);
- }
- }
- if (alpha_value->get_line_edit()->has_focus() && !has_ctext_focus) {
- alpha_value->get_line_edit()->select_all();
- } else {
- alpha_value->get_line_edit()->select(0, 0);
- }
-}
-
-void ColorPicker::_focus_exit() {
- for (int i = 0; i < current_slider_count; i++) {
- if (!values[i]->get_line_edit()->get_menu()->is_visible()) {
- values[i]->get_line_edit()->select(0, 0);
- }
- }
- if (!alpha_value->get_line_edit()->get_menu()->is_visible()) {
- alpha_value->get_line_edit()->select(0, 0);
- }
-
- c_text->select(0, 0);
-}
-
void ColorPicker::_html_focus_exit() {
if (c_text->is_menu_visible()) {
return;
}
_html_submitted(c_text->get_text());
- _focus_exit();
}
void ColorPicker::set_presets_enabled(bool p_enabled) {
@@ -1162,7 +1444,6 @@ void ColorPicker::set_presets_visible(bool p_visible) {
return;
}
presets_visible = p_visible;
- preset_separator->set_visible(p_visible);
preset_container->set_visible(p_visible);
}
@@ -1186,9 +1467,16 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
+ ClassDB::bind_method(D_METHOD("add_recent_preset", "color"), &ColorPicker::add_recent_preset);
+ ClassDB::bind_method(D_METHOD("erase_recent_preset", "color"), &ColorPicker::erase_recent_preset);
+ ClassDB::bind_method(D_METHOD("get_recent_presets"), &ColorPicker::get_recent_presets);
ClassDB::bind_method(D_METHOD("set_picker_shape", "shape"), &ColorPicker::set_picker_shape);
ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ColorPicker::_get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ColorPicker::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ColorPicker::_drop_data_fw);
+
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL"), "set_color_mode", "get_color_mode");
@@ -1216,7 +1504,7 @@ ColorPicker::ColorPicker() :
BoxContainer(true) {
HBoxContainer *hb_edit = memnew(HBoxContainer);
add_child(hb_edit, false, INTERNAL_MODE_FRONT);
- hb_edit->set_v_size_flags(SIZE_EXPAND_FILL);
+ hb_edit->set_v_size_flags(SIZE_SHRINK_BEGIN);
uv_edit = memnew(Control);
hb_edit->add_child(uv_edit);
@@ -1229,24 +1517,82 @@ ColorPicker::ColorPicker() :
HBoxContainer *hb_smpl = memnew(HBoxContainer);
add_child(hb_smpl, false, INTERNAL_MODE_FRONT);
+ btn_pick = memnew(Button);
+ hb_smpl->add_child(btn_pick);
+ btn_pick->set_toggle_mode(true);
+ btn_pick->set_tooltip_text(RTR("Pick a color from the editor window."));
+ btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
+
sample = memnew(TextureRect);
hb_smpl->add_child(sample);
sample->set_h_size_flags(SIZE_EXPAND_FILL);
sample->connect("gui_input", callable_mp(this, &ColorPicker::_sample_input));
sample->connect("draw", callable_mp(this, &ColorPicker::_sample_draw));
- btn_pick = memnew(Button);
- btn_pick->set_flat(true);
- hb_smpl->add_child(btn_pick);
- btn_pick->set_toggle_mode(true);
- btn_pick->set_tooltip_text(RTR("Pick a color from the editor window."));
- btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
+ btn_shape = memnew(MenuButton);
+ btn_shape->set_flat(false);
+ hb_smpl->add_child(btn_shape);
+ btn_shape->set_toggle_mode(true);
+ btn_shape->set_tooltip_text(RTR("Select a picker shape."));
+
+ current_shape = SHAPE_HSV_RECTANGLE;
+
+ shape_popup = btn_shape->get_popup();
+ shape_popup->add_icon_radio_check_item(get_theme_icon(SNAME("shape_rect"), SNAME("ColorPicker")), "HSV Rectangle", SHAPE_HSV_RECTANGLE);
+ shape_popup->add_icon_radio_check_item(get_theme_icon(SNAME("shape_rect_wheel"), SNAME("ColorPicker")), "HSV Wheel", SHAPE_HSV_WHEEL);
+ shape_popup->add_icon_radio_check_item(get_theme_icon(SNAME("shape_circle"), SNAME("ColorPicker")), "VHS Circle", SHAPE_VHS_CIRCLE);
+ shape_popup->add_icon_radio_check_item(get_theme_icon(SNAME("shape_circle"), SNAME("ColorPicker")), "OKHSL Circle", SHAPE_OKHSL_CIRCLE);
+ shape_popup->set_item_checked(current_shape, true);
+ shape_popup->connect("id_pressed", callable_mp(this, &ColorPicker::set_picker_shape));
+
+ btn_shape->set_icon(shape_popup->get_item_icon(current_shape));
+
+ add_mode(new ColorModeRGB(this));
+ add_mode(new ColorModeHSV(this));
+ add_mode(new ColorModeRAW(this));
+ add_mode(new ColorModeOKHSL(this));
+ HBoxContainer *mode_hbc = memnew(HBoxContainer);
+ add_child(mode_hbc, false, INTERNAL_MODE_FRONT);
+
+ mode_group.instantiate();
+
+ for (int i = 0; i < MODE_BUTTON_COUNT; i++) {
+ mode_btns[i] = memnew(Button);
+ mode_hbc->add_child(mode_btns[i]);
+ mode_btns[i]->set_focus_mode(FOCUS_NONE);
+ mode_btns[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ mode_btns[i]->add_theme_style_override("pressed", get_theme_stylebox("tab_selected", "TabContainer"));
+ mode_btns[i]->add_theme_style_override("normal", get_theme_stylebox("tab_unselected", "TabContainer"));
+ mode_btns[i]->add_theme_style_override("hover", get_theme_stylebox("tab_selected", "TabContainer"));
+ mode_btns[i]->set_toggle_mode(true);
+ mode_btns[i]->set_text(modes[i]->get_name());
+ mode_btns[i]->set_button_group(mode_group);
+ mode_btns[i]->connect("pressed", callable_mp(this, &ColorPicker::set_color_mode).bind((ColorModeType)i));
+ }
+ mode_btns[0]->set_pressed(true);
+
+ btn_mode = memnew(MenuButton);
+ btn_mode->set_text("...");
+ btn_mode->set_flat(false);
+ mode_hbc->add_child(btn_mode);
+ btn_mode->set_toggle_mode(true);
+ btn_mode->set_tooltip_text(RTR("Select a picker mode."));
+
+ current_mode = MODE_RGB;
+
+ mode_popup = btn_mode->get_popup();
+ for (int i = 0; i < modes.size(); i++) {
+ mode_popup->add_radio_check_item(modes[i]->get_name(), i);
+ }
+ mode_popup->add_separator();
+ mode_popup->add_check_item("Colorized Sliders", MODE_MAX);
+ mode_popup->set_item_checked(current_mode, true);
+ mode_popup->set_item_checked(MODE_MAX + 1, true);
+ mode_popup->connect("id_pressed", callable_mp(this, &ColorPicker::_set_mode_popup_value));
VBoxContainer *vbl = memnew(VBoxContainer);
add_child(vbl, false, INTERNAL_MODE_FRONT);
- add_child(memnew(HSeparator), false, INTERNAL_MODE_FRONT);
-
VBoxContainer *vbr = memnew(VBoxContainer);
add_child(vbr, false, INTERNAL_MODE_FRONT);
@@ -1265,16 +1611,10 @@ ColorPicker::ColorPicker() :
alpha_label->set_text("A");
HBoxContainer *hhb = memnew(HBoxContainer);
+ hhb->set_alignment(ALIGNMENT_BEGIN);
vbr->add_child(hhb);
- mode_option_button = memnew(OptionButton);
-
- hhb->add_child(mode_option_button);
- add_mode(new ColorModeRGB(this));
- add_mode(new ColorModeHSV(this));
- add_mode(new ColorModeRAW(this));
- add_mode(new ColorModeOKHSL(this));
- mode_option_button->connect("item_selected", callable_mp(this, &ColorPicker::_set_color_mode));
+ hhb->add_child(memnew(Label("Hex")));
text_type = memnew(Button);
hhb->add_child(text_type);
@@ -1289,9 +1629,9 @@ ColorPicker::ColorPicker() :
c_text = memnew(LineEdit);
hhb->add_child(c_text);
- c_text->set_h_size_flags(SIZE_EXPAND_FILL);
+ c_text->set_select_all_on_focus(true);
c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted));
- c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter));
+ c_text->connect("text_changed", callable_mp(this, &ColorPicker::_text_changed));
c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit));
wheel_edit = memnew(AspectRatioContainer);
@@ -1328,16 +1668,43 @@ ColorPicker::ColorPicker() :
_update_controls();
updating = false;
- set_pick_color(Color(1, 1, 1));
-
- preset_separator = memnew(HSeparator);
- add_child(preset_separator, false, INTERNAL_MODE_FRONT);
-
preset_container = memnew(GridContainer);
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
- preset_container->set_columns(preset_column_count);
+ preset_container->set_columns(PRESET_COLUMN_COUNT);
+ preset_container->hide();
+
+ preset_group.instantiate();
+
+ btn_preset = memnew(Button);
+ btn_preset->set_text("Swatches");
+ btn_preset->set_flat(true);
+ btn_preset->set_toggle_mode(true);
+ btn_preset->set_focus_mode(FOCUS_NONE);
+ btn_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ btn_preset->connect("toggled", callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_preset, preset_container));
+ add_child(btn_preset, false, INTERNAL_MODE_FRONT);
+
add_child(preset_container, false, INTERNAL_MODE_FRONT);
+ recent_preset_hbc = memnew(HBoxContainer);
+ recent_preset_hbc->set_v_size_flags(SIZE_SHRINK_BEGIN);
+ recent_preset_hbc->hide();
+
+ recent_preset_group.instantiate();
+
+ btn_recent_preset = memnew(Button);
+ btn_recent_preset->set_text("Recent Colors");
+ btn_recent_preset->set_flat(true);
+ btn_recent_preset->set_toggle_mode(true);
+ btn_recent_preset->set_focus_mode(FOCUS_NONE);
+ btn_recent_preset->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ btn_recent_preset->connect("toggled", callable_mp(this, &ColorPicker::_show_hide_preset).bind(btn_recent_preset, recent_preset_hbc));
+ add_child(btn_recent_preset, false, INTERNAL_MODE_FRONT);
+
+ add_child(recent_preset_hbc, false, INTERNAL_MODE_FRONT);
+
+ set_pick_color(Color(1, 1, 1));
+
btn_add_preset = memnew(Button);
btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
btn_add_preset->set_tooltip_text(RTR("Add current color as a preset."));
@@ -1378,6 +1745,7 @@ void ColorPickerButton::pressed() {
popup->reset_size();
picker->_update_presets();
+ picker->_update_recent_presets();
Rect2i usable_rect = popup->get_usable_parent_rect();
//let's try different positions to see which one we can use
@@ -1484,6 +1852,7 @@ void ColorPickerButton::_update_picker() {
picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed));
popup->connect("about_to_popup", callable_mp(this, &ColorPickerButton::_about_to_popup));
popup->connect("popup_hide", callable_mp(this, &ColorPickerButton::_modal_closed));
+ picker->connect("minimum_size_changed", callable_mp((Window *)popup, &Window::reset_size));
picker->set_pick_color(color);
picker->set_edit_alpha(edit_alpha);
picker->set_display_old_color(true);
@@ -1523,6 +1892,13 @@ void ColorPresetButton::_notification(int p_what) {
Ref<StyleBoxTexture> sb_texture = sb_raw;
if (sb_flat.is_valid()) {
+ sb_flat->set_border_width(SIDE_BOTTOM, 2);
+ if (get_draw_mode() == DRAW_PRESSED || get_draw_mode() == DRAW_HOVER_PRESSED) {
+ sb_flat->set_border_color(Color(1, 1, 1, 1));
+ } else {
+ sb_flat->set_border_color(Color(0, 0, 0, 1));
+ }
+
if (preset_color.a < 1) {
// Draw a background pattern when the color is transparent.
sb_flat->set_bg_color(Color(1, 1, 1));
@@ -1566,8 +1942,10 @@ Color ColorPresetButton::get_preset_color() const {
return preset_color;
}
-ColorPresetButton::ColorPresetButton(Color p_color) {
+ColorPresetButton::ColorPresetButton(Color p_color, int p_size) {
preset_color = p_color;
+ set_toggle_mode(true);
+ set_custom_minimum_size(Size2(p_size, p_size));
}
ColorPresetButton::~ColorPresetButton() {
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 05b760b109..a0843d6fa2 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -38,6 +38,7 @@
#include "scene/gui/grid_container.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/popup.h"
#include "scene/gui/separator.h"
@@ -63,7 +64,7 @@ public:
void set_preset_color(const Color &p_color);
Color get_preset_color() const;
- ColorPresetButton(Color p_color);
+ ColorPresetButton(Color p_color, int p_size);
~ColorPresetButton();
};
@@ -96,8 +97,10 @@ private:
static Ref<Shader> circle_shader;
static Ref<Shader> circle_ok_color_shader;
static List<Color> preset_cache;
+ static List<Color> recent_preset_cache;
int current_slider_count = SLIDER_COUNT;
+ static const int MODE_BUTTON_COUNT = 3;
bool slider_theme_modified = true;
@@ -114,9 +117,20 @@ private:
Control *wheel_uv = nullptr;
TextureRect *sample = nullptr;
GridContainer *preset_container = nullptr;
- HSeparator *preset_separator = nullptr;
+ HBoxContainer *recent_preset_hbc = nullptr;
Button *btn_add_preset = nullptr;
Button *btn_pick = nullptr;
+ Button *btn_preset = nullptr;
+ Button *btn_recent_preset = nullptr;
+ PopupMenu *shape_popup = nullptr;
+ PopupMenu *mode_popup = nullptr;
+ MenuButton *btn_shape = nullptr;
+ MenuButton *btn_mode = nullptr;
+ Button *mode_btns[MODE_BUTTON_COUNT];
+ Ref<ButtonGroup> mode_group = nullptr;
+ ColorPresetButton *selected_recent_preset = nullptr;
+ Ref<ButtonGroup> preset_group;
+ Ref<ButtonGroup> recent_preset_group;
OptionButton *mode_option_button = nullptr;
@@ -135,10 +149,13 @@ private:
bool text_is_constructor = false;
PickerShapeType current_shape = SHAPE_HSV_RECTANGLE;
ColorModeType current_mode = MODE_RGB;
+ bool colorize_sliders = true;
- const int preset_column_count = 9;
+ const int PRESET_COLUMN_COUNT = 9;
int prev_preset_size = 0;
+ int prev_rencet_preset_size = 0;
List<Color> presets;
+ List<Color> recent_presets;
Color color;
Color old_color;
@@ -150,6 +167,8 @@ private:
bool spinning = false;
bool presets_enabled = true;
bool presets_visible = true;
+ bool line_edit_mouse_release = false;
+ bool text_changed = false;
float h = 0.0;
float s = 0.0;
@@ -175,18 +194,28 @@ private:
void _uv_input(const Ref<InputEvent> &p_event, Control *c);
void _w_input(const Ref<InputEvent> &p_event);
+ void _slider_or_spin_input(const Ref<InputEvent> &p_event);
+ void _line_edit_input(const Ref<InputEvent> &p_event);
void _preset_input(const Ref<InputEvent> &p_event, const Color &p_color);
+ void _recent_preset_pressed(const bool pressed, ColorPresetButton *p_preset);
void _screen_input(const Ref<InputEvent> &p_event);
+ void _text_changed(const String &p_new_text);
void _add_preset_pressed();
void _screen_pick_pressed();
- void _focus_enter();
- void _focus_exit();
void _html_focus_exit();
inline int _get_preset_size();
void _add_preset_button(int p_size, const Color &p_color);
+ void _add_recent_preset_button(int p_size, const Color &p_color);
- void _set_color_mode(ColorModeType p_mode);
+ void _show_hide_preset(const bool &p_is_btn_pressed, Button *p_btn_preset, Container *p_preset_container);
+ void _update_drop_down_arrow(const bool &p_is_btn_pressed, Button *p_btn_preset);
+
+ void _set_mode_popup_value(ColorModeType p_mode);
+
+ Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control);
+ bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const;
+ void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control);
protected:
void _notification(int);
@@ -218,13 +247,23 @@ public:
PickerShapeType get_picker_shape() const;
void add_preset(const Color &p_color);
+ void add_recent_preset(const Color &p_color);
void erase_preset(const Color &p_color);
+ void erase_recent_preset(const Color &p_color);
PackedColorArray get_presets() const;
+ PackedColorArray get_recent_presets() const;
void _update_presets();
+ void _update_recent_presets();
+
+ void _select_from_preset_container(const Color &p_color);
+ bool _select_from_recent_preset_hbc(const Color &p_color);
void set_color_mode(ColorModeType p_mode);
ColorModeType get_color_mode() const;
+ void set_colorize_sliders(bool p_colorize_sliders);
+ bool is_colorizing_sliders() const;
+
void set_deferred_mode(bool p_enabled);
bool is_deferred_mode() const;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index dc9294df6d..c5cb7157e8 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -633,7 +633,7 @@ Rect2 Control::get_parent_anchorable_rect() const {
#ifdef TOOLS_ENABLED
Node *edited_root = get_tree()->get_edited_scene_root();
if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) {
- parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/viewport_width"), ProjectSettings::get_singleton()->get("display/window/size/viewport_height"));
+ parent_rect.size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
} else {
parent_rect = get_viewport()->get_visible_rect();
}
@@ -1436,13 +1436,6 @@ Rect2 Control::get_screen_rect() const {
return r;
}
-Rect2 Control::get_window_rect() const {
- ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2 gr = get_global_rect();
- gr.position += get_viewport()->get_visible_rect().position;
- return gr;
-}
-
Rect2 Control::get_anchorable_rect() const {
return Rect2(Point2(), get_size());
}
@@ -1558,13 +1551,11 @@ bool Control::is_minimum_size_adjust_blocked() const {
Size2 Control::get_minimum_size() const {
Vector2 ms;
- if (GDVIRTUAL_CALL(_get_minimum_size, ms)) {
- return ms;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_get_minimum_size, ms);
+ return ms;
}
-void Control::set_custom_minimum_size(const Size2i &p_custom) {
+void Control::set_custom_minimum_size(const Size2 &p_custom) {
if (p_custom == data.custom_minimum_size) {
return;
}
@@ -1572,7 +1563,7 @@ void Control::set_custom_minimum_size(const Size2i &p_custom) {
update_minimum_size();
}
-Size2i Control::get_custom_minimum_size() const {
+Size2 Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
@@ -1759,6 +1750,34 @@ void Control::warp_mouse(const Point2 &p_position) {
get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position));
}
+void Control::set_shortcut_context(const Node *p_node) {
+ if (p_node != nullptr) {
+ data.shortcut_context = p_node->get_instance_id();
+ } else {
+ data.shortcut_context = ObjectID();
+ }
+}
+
+Node *Control::get_shortcut_context() const {
+ Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context);
+ Node *ctx_node = Object::cast_to<Node>(ctx_obj);
+
+ return ctx_node;
+}
+
+bool Control::is_focus_owner_in_shortcut_context() const {
+ if (data.shortcut_context == ObjectID()) {
+ // No context, therefore global - always "in" context.
+ return true;
+ }
+
+ const Node *ctx_node = get_shortcut_context();
+ const Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
+
+ // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
+ return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+}
+
// Drag and drop handling.
void Control::set_drag_forwarding(Object *p_target) {
@@ -1778,11 +1797,8 @@ Variant Control::get_drag_data(const Point2 &p_point) {
}
Variant dd;
- if (GDVIRTUAL_CALL(_get_drag_data, p_point, dd)) {
- return dd;
- }
-
- return Variant();
+ GDVIRTUAL_CALL(_get_drag_data, p_point, dd);
+ return dd;
}
bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
@@ -1793,11 +1809,9 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
}
}
- bool ret;
- if (GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret);
+ return ret;
}
void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
@@ -2704,11 +2718,8 @@ void Control::end_bulk_theme_override() {
TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
TypedArray<Vector2i> ret;
- if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) {
- return ret;
- } else {
- return TypedArray<Vector2i>();
- }
+ GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
+ return ret;
} else {
return TS->parse_structured_text(p_parser_type, p_args, p_text);
}
@@ -2793,10 +2804,8 @@ String Control::get_tooltip(const Point2 &p_pos) const {
Control *Control::make_custom_tooltip(const String &p_text) const {
Object *ret = nullptr;
- if (GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret)) {
- return Object::cast_to<Control>(ret);
- }
- return nullptr;
+ GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret);
+ return Object::cast_to<Control>(ret);
}
// Base object overrides.
@@ -2885,8 +2894,8 @@ void Control::_notification(int p_notification) {
if (data.parent_canvas_item) {
data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed));
data.parent_canvas_item = nullptr;
- } else if (!is_set_as_top_level()) {
- //disconnect viewport
+ } else {
+ // Disconnect viewport.
Viewport *viewport = get_viewport();
ERR_FAIL_COND(!viewport);
viewport->disconnect("size_changed", callable_mp(this, &Control::_size_changed));
@@ -3133,6 +3142,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse);
+ ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context);
+ ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context);
+
ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size);
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Control::set_layout_direction);
@@ -3144,7 +3156,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
@@ -3206,6 +3218,9 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
+ ADD_GROUP("Input", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+
ADD_GROUP("Theme", "theme_");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation");
diff --git a/scene/gui/control.h b/scene/gui/control.h
index ee6443c81c..72e870930d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -159,6 +159,7 @@ private:
}
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
// Global relations.
@@ -200,7 +201,7 @@ private:
int h_size_flags = SIZE_FILL;
int v_size_flags = SIZE_FILL;
real_t expand = 1.0;
- Point2i custom_minimum_size;
+ Point2 custom_minimum_size;
// Input events and rendering.
@@ -218,6 +219,8 @@ private:
NodePath focus_next;
NodePath focus_prev;
+ ObjectID shortcut_context;
+
// Theming.
ThemeOwner *theme_owner = nullptr;
@@ -442,7 +445,6 @@ public:
Rect2 get_rect() const;
Rect2 get_global_rect() const;
Rect2 get_screen_rect() const;
- Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the rendering server
Rect2 get_anchorable_rect() const override;
void set_scale(const Vector2 &p_scale);
@@ -460,8 +462,8 @@ public:
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
- void set_custom_minimum_size(const Size2i &p_custom);
- Size2i get_custom_minimum_size() const;
+ void set_custom_minimum_size(const Size2 &p_custom);
+ Size2 get_custom_minimum_size() const;
// Container sizing.
@@ -487,6 +489,10 @@ public:
void warp_mouse(const Point2 &p_position);
+ bool is_focus_owner_in_shortcut_context() const;
+ void set_shortcut_context(const Node *p_node);
+ Node *get_shortcut_context() const;
+
// Drag and drop handling.
virtual void set_drag_forwarding(Object *p_target);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index f5edaf02d8..bf4dd3d245 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -208,24 +208,24 @@ void AcceptDialog::register_text_enter(Control *p_line_edit) {
}
void AcceptDialog::_update_child_rects() {
- Size2 size = get_size();
+ Size2 dlg_size = get_size();
float h_margins = theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT);
float v_margins = theme_cache.panel_style->get_margin(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_BOTTOM);
// Fill the entire size of the window with the background.
bg_panel->set_position(Point2());
- bg_panel->set_size(size);
+ bg_panel->set_size(dlg_size);
// Place the buttons from the bottom edge to their minimum required size.
Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size();
- Size2 buttons_size = Size2(size.x - h_margins, buttons_minsize.y);
- Point2 buttons_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), size.y - theme_cache.panel_style->get_margin(SIDE_BOTTOM) - buttons_size.y);
+ Size2 buttons_size = Size2(dlg_size.x - h_margins, buttons_minsize.y);
+ Point2 buttons_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), dlg_size.y - theme_cache.panel_style->get_margin(SIDE_BOTTOM) - buttons_size.y);
buttons_hbox->set_position(buttons_position);
buttons_hbox->set_size(buttons_size);
// Place the content from the top to fill the rest of the space (minus the separation).
Point2 content_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), theme_cache.panel_style->get_margin(SIDE_TOP));
- Size2 content_size = Size2(size.x - h_margins, size.y - v_margins - buttons_size.y - theme_cache.buttons_separation);
+ Size2 content_size = Size2(dlg_size.x - h_margins, dlg_size.y - v_margins - buttons_size.y - theme_cache.buttons_separation);
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index cf7f439aef..cade65108c 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -743,10 +743,10 @@ void FileDialog::set_current_path(const String &p_path) {
if (pos == -1) {
set_current_file(p_path);
} else {
- String dir = p_path.substr(0, pos);
- String file = p_path.substr(pos + 1, p_path.length());
- set_current_dir(dir);
- set_current_file(file);
+ String path_dir = p_path.substr(0, pos);
+ String path_file = p_path.substr(pos + 1, p_path.length());
+ set_current_dir(path_dir);
+ set_current_file(path_file);
}
}
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index b0d15aa7f4..44c5ec62f8 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -152,6 +152,28 @@ void FlowContainer::_resort() {
line_data = lines_data[current_line_idx];
}
+ // The first child of each line adds the offset caused by the alignment,
+ // but only if the line doesn't contain a child that expands.
+ if (child_idx_in_line == 0 && Math::is_equal_approx(line_data.stretch_ratio_total, 0)) {
+ int alignment_ofs = 0;
+ switch (alignment) {
+ case ALIGNMENT_CENTER:
+ alignment_ofs = line_data.stretch_avail / 2;
+ break;
+ case ALIGNMENT_END:
+ alignment_ofs = line_data.stretch_avail;
+ break;
+ default:
+ break;
+ }
+
+ if (vertical) { /* VERTICAL */
+ ofs.y += alignment_ofs;
+ } else { /* HORIZONTAL */
+ ofs.x += alignment_ofs;
+ }
+ }
+
if (vertical) { /* VERTICAL */
if (child->get_h_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)) {
child_size.width = line_data.min_line_height;
@@ -282,6 +304,18 @@ int FlowContainer::get_line_count() const {
return cached_line_count;
}
+void FlowContainer::set_alignment(AlignmentMode p_alignment) {
+ if (alignment == p_alignment) {
+ return;
+ }
+ alignment = p_alignment;
+ _resort();
+}
+
+FlowContainer::AlignmentMode FlowContainer::get_alignment() const {
+ return alignment;
+}
+
void FlowContainer::set_vertical(bool p_vertical) {
ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
vertical = p_vertical;
@@ -300,8 +334,15 @@ FlowContainer::FlowContainer(bool p_vertical) {
void FlowContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count);
+ ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &FlowContainer::set_alignment);
+ ClassDB::bind_method(D_METHOD("get_alignment"), &FlowContainer::get_alignment);
ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical);
ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical);
+ BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN);
+ BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
+ BIND_ENUM_CONSTANT(ALIGNMENT_END);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h
index 536df27ad6..6a61e9b904 100644
--- a/scene/gui/flow_container.h
+++ b/scene/gui/flow_container.h
@@ -36,11 +36,19 @@
class FlowContainer : public Container {
GDCLASS(FlowContainer, Container);
+public:
+ enum AlignmentMode {
+ ALIGNMENT_BEGIN,
+ ALIGNMENT_CENTER,
+ ALIGNMENT_END
+ };
+
private:
int cached_size = 0;
int cached_line_count = 0;
bool vertical = false;
+ AlignmentMode alignment = ALIGNMENT_BEGIN;
struct ThemeCache {
int h_separation = 0;
@@ -61,6 +69,9 @@ protected:
public:
int get_line_count() const;
+ void set_alignment(AlignmentMode p_alignment);
+ AlignmentMode get_alignment() const;
+
void set_vertical(bool p_vertical);
bool is_vertical() const;
@@ -88,4 +99,6 @@ public:
FlowContainer(true) { is_fixed = true; }
};
+VARIANT_ENUM_CAST(FlowContainer::AlignmentMode);
+
#endif // FLOW_CONTAINER_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 7295ab9e9d..46b712379d 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -92,8 +92,8 @@ void GraphEditMinimap::update_minimap() {
Rect2 GraphEditMinimap::get_camera_rect() {
Vector2 camera_center = _convert_from_graph_position(camera_position + camera_size / 2) + minimap_offset;
Vector2 camera_viewport = _convert_from_graph_position(camera_size);
- Vector2 camera_position = (camera_center - camera_viewport / 2);
- return Rect2(camera_position, camera_viewport);
+ Vector2 camera_pos = (camera_center - camera_viewport / 2);
+ return Rect2(camera_pos, camera_viewport);
}
Vector2 GraphEditMinimap::_get_render_size() {
@@ -1385,16 +1385,16 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (p_ev->is_pressed()) {
- if (p_ev->is_action("ui_graph_duplicate")) {
+ if (p_ev->is_action("ui_graph_duplicate", true)) {
emit_signal(SNAME("duplicate_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_copy")) {
+ } else if (p_ev->is_action("ui_copy", true)) {
emit_signal(SNAME("copy_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_paste")) {
+ } else if (p_ev->is_action("ui_paste", true)) {
emit_signal(SNAME("paste_nodes_request"));
accept_event();
- } else if (p_ev->is_action("ui_graph_delete")) {
+ } else if (p_ev->is_action("ui_graph_delete", true)) {
TypedArray<StringName> nodes;
for (int i = 0; i < get_child_count(); i++) {
@@ -1475,11 +1475,9 @@ void GraphEdit::force_connection_drag_end() {
}
bool GraphEdit::is_node_hover_valid(const StringName &p_from, const int p_from_port, const StringName &p_to, const int p_to_port) {
- bool valid;
- if (GDVIRTUAL_CALL(_is_node_hover_valid, p_from, p_from_port, p_to, p_to_port, valid)) {
- return valid;
- }
- return true;
+ bool valid = true;
+ GDVIRTUAL_CALL(_is_node_hover_valid, p_from, p_from_port, p_to, p_to_port, valid);
+ return valid;
}
void GraphEdit::set_panning_scheme(PanningScheme p_scheme) {
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 21c0b5a842..5df4c066e4 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -294,14 +294,14 @@ void GraphNode::_resort() {
bool GraphNode::has_point(const Point2 &p_point) const {
if (comment) {
- Ref<StyleBox> comment = get_theme_stylebox(SNAME("comment"));
+ Ref<StyleBox> comment_sb = get_theme_stylebox(SNAME("comment"));
Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
if (Rect2(get_size() - resizer->get_size(), resizer->get_size()).has_point(p_point)) {
return true;
}
- if (Rect2(0, 0, get_size().width, comment->get_margin(SIDE_TOP)).has_point(p_point)) {
+ if (Rect2(0, 0, get_size().width, comment_sb->get_margin(SIDE_TOP)).has_point(p_point)) {
return true;
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 357f2480bd..d6b5557a3f 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -728,12 +728,12 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
if (p_event->is_pressed() && items.size() > 0) {
- if (p_event->is_action("ui_up")) {
+ if (p_event->is_action("ui_up", true)) {
if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
+ if (diff < uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec")) * 2) {
for (int i = current - 1; i >= 0; i--) {
if (CAN_SELECT(i) && items[i].text.begins_with(search_string)) {
set_current(i);
@@ -766,12 +766,12 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_down")) {
+ } else if (p_event->is_action("ui_down", true)) {
if (!search_string.is_empty()) {
uint64_t now = OS::get_singleton()->get_ticks_msec();
uint64_t diff = now - search_time_msec;
- if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
+ if (diff < uint64_t(GLOBAL_GET("gui/timers/incremental_search_max_interval_msec")) * 2) {
for (int i = current + 1; i < items.size(); i++) {
if (CAN_SELECT(i) && items[i].text.begins_with(search_string)) {
set_current(i);
@@ -803,7 +803,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_page_up")) {
+ } else if (p_event->is_action("ui_page_up", true)) {
search_string = ""; //any mousepress cancels
for (int i = 4; i > 0; i--) {
@@ -817,7 +817,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
break;
}
}
- } else if (p_event->is_action("ui_page_down")) {
+ } else if (p_event->is_action("ui_page_down", true)) {
search_string = ""; //any mousepress cancels
for (int i = 4; i > 0; i--) {
@@ -832,7 +832,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
break;
}
}
- } else if (p_event->is_action("ui_left")) {
+ } else if (p_event->is_action("ui_left", true)) {
search_string = ""; //any mousepress cancels
if (current % current_columns != 0) {
@@ -852,7 +852,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_right")) {
+ } else if (p_event->is_action("ui_right", true)) {
search_string = ""; //any mousepress cancels
if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
@@ -872,9 +872,9 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
}
accept_event();
}
- } else if (p_event->is_action("ui_cancel")) {
+ } else if (p_event->is_action("ui_cancel", true)) {
search_string = "";
- } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) {
+ } else if (p_event->is_action("ui_select", true) && select_mode == SELECT_MULTI) {
if (current >= 0 && current < items.size()) {
if (items[current].selectable && !items[current].disabled && !items[current].selected) {
select(current, false);
@@ -884,7 +884,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("multi_selected"), current, false);
}
}
- } else if (p_event->is_action("ui_accept")) {
+ } else if (p_event->is_action("ui_accept", true)) {
search_string = ""; //any mousepress cancels
if (current >= 0 && current < items.size()) {
@@ -1296,9 +1296,9 @@ void ItemList::_notification(int p_what) {
draw_rect.size = adj.size;
}
- Color modulate = items[i].icon_modulate;
+ Color icon_modulate = items[i].icon_modulate;
if (items[i].disabled) {
- modulate.a *= 0.5;
+ icon_modulate.a *= 0.5;
}
// If the icon is transposed, we have to switch the size so that it is drawn correctly
@@ -1313,7 +1313,7 @@ void ItemList::_notification(int p_what) {
if (rtl) {
draw_rect.position.x = size.width - draw_rect.position.x - draw_rect.size.x;
}
- draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed);
+ draw_texture_rect_region(items[i].icon, draw_rect, region, icon_modulate, items[i].icon_transposed);
}
if (items[i].tag_icon.is_valid()) {
@@ -1336,9 +1336,9 @@ void ItemList::_notification(int p_what) {
max_len = size2.x;
}
- Color modulate = items[i].selected ? theme_cache.font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : theme_cache.font_color);
+ Color txt_modulate = items[i].selected ? theme_cache.font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : theme_cache.font_color);
if (items[i].disabled) {
- modulate.a *= 0.5;
+ txt_modulate.a *= 0.5;
}
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
@@ -1355,7 +1355,7 @@ void ItemList::_notification(int p_what) {
items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color);
}
- items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
+ items[i].text_buf->draw(get_canvas_item(), text_ofs, txt_modulate);
} else {
if (fixed_column_width > 0) {
size2.x = MIN(size2.x, fixed_column_width);
@@ -1387,7 +1387,7 @@ void ItemList::_notification(int p_what) {
}
if (width - text_ofs.x > 0) {
- items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate);
+ items[i].text_buf->draw(get_canvas_item(), text_ofs, txt_modulate);
}
}
}
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 306ca3d340..2203573bbc 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -102,12 +102,12 @@ void Label::_shape() {
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
ERR_FAIL_COND(font.is_null());
- String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
+ String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
- text = text.substr(0, visible_chars);
+ txt = txt.substr(0, visible_chars);
}
if (dirty) {
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), language);
} else {
int spans = TS->shaped_get_span_count(text_rid);
for (int i = 0; i < spans; i++) {
@@ -117,7 +117,7 @@ void Label::_shape() {
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
+ TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, txt));
dirty = false;
font_dirty = false;
lines_dirty = true;
@@ -288,6 +288,36 @@ void Label::_update_theme_item_cache() {
theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
}
+PackedStringArray Label::get_configuration_warnings() const {
+ PackedStringArray warnings = Control::get_configuration_warnings();
+
+ // Ensure that the font can render all of the required glyphs.
+ Ref<Font> font;
+ if (settings.is_valid()) {
+ font = settings->get_font();
+ }
+ if (font.is_null()) {
+ font = theme_cache.font;
+ }
+
+ if (font.is_valid()) {
+ if (dirty || font_dirty || lines_dirty) {
+ const_cast<Label *>(this)->_shape();
+ }
+
+ const Glyph *glyph = TS->shaped_text_get_glyphs(text_rid);
+ int64_t glyph_count = TS->shaped_text_get_glyph_count(text_rid);
+ for (int64_t i = 0; i < glyph_count; i++) {
+ if (glyph[i].font_rid == RID()) {
+ warnings.push_back(RTR("The current font does not support rendering one or more characters used in this Label's text."));
+ break;
+ }
+ }
+ }
+
+ return warnings;
+}
+
void Label::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -302,6 +332,7 @@ void Label::_notification(int p_what) {
dirty = true;
queue_redraw();
+ update_configuration_warnings();
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
@@ -674,6 +705,7 @@ void Label::set_text(const String &p_string) {
}
queue_redraw();
update_minimum_size();
+ update_configuration_warnings();
}
void Label::_invalidate() {
diff --git a/scene/gui/label.h b/scene/gui/label.h
index b79c94a5ba..41d7049b22 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -93,6 +93,7 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
+ virtual PackedStringArray get_configuration_warnings() const override;
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index be94337c89..fb5ab9f923 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -372,6 +372,11 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.drag_attempt = false;
}
+ if (pending_select_all_on_focus) {
+ select_all();
+ pending_select_all_on_focus = false;
+ }
+
show_virtual_keyboard();
}
@@ -971,7 +976,18 @@ void LineEdit::_notification(int p_what) {
} else {
if (caret.l_caret != Rect2() && caret.l_dir == TextServer::DIRECTION_AUTO) {
// Draw extra marker on top of mid caret.
- Rect2 trect = Rect2(caret.l_caret.position.x - 3 * caret_width, caret.l_caret.position.y, 6 * caret_width, caret_width);
+ Rect2 trect = Rect2(caret.l_caret.position.x - 2.5 * caret_width, caret.l_caret.position.y, 6 * caret_width, caret_width);
+ trect.position += ofs;
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
+ } else if (caret.l_caret != Rect2() && caret.t_caret != Rect2() && caret.l_dir != caret.t_dir) {
+ // Draw extra direction marker on top of split caret.
+ float d = (caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
+ Rect2 trect = Rect2(caret.l_caret.position.x + d * caret_width, caret.l_caret.position.y + caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width);
+ trect.position += ofs;
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
+
+ d = (caret.t_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
+ trect = Rect2(caret.t_caret.position.x + d * caret_width, caret.t_caret.position.y, 3 * caret_width, caret_width);
trect.position += ofs;
RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
}
@@ -1045,10 +1061,19 @@ void LineEdit::_notification(int p_what) {
}
}
+ if (select_all_on_focus) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+ // Select all when the mouse button is up.
+ pending_select_all_on_focus = true;
+ } else {
+ select_all();
+ }
+ }
+
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- Point2 caret_column = Point2(get_caret_column(), 1) * get_minimum_size().height;
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + caret_column, get_viewport()->get_window_id());
+ Point2 column = Point2(get_caret_column(), 1) * get_minimum_size().height;
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + column, get_viewport()->get_window_id());
}
show_virtual_keyboard();
@@ -2153,6 +2178,18 @@ bool LineEdit::is_flat() const {
return flat;
}
+void LineEdit::set_select_all_on_focus(bool p_enabled) {
+ select_all_on_focus = p_enabled;
+}
+
+bool LineEdit::is_select_all_on_focus() const {
+ return select_all_on_focus;
+}
+
+void LineEdit::clear_pending_select_all_on_focus() {
+ pending_select_all_on_focus = false;
+}
+
void LineEdit::_text_changed() {
_emit_text_change();
_clear_redo();
@@ -2164,6 +2201,12 @@ void LineEdit::_emit_text_change() {
}
void LineEdit::_shape() {
+ const Ref<Font> &font = theme_cache.font;
+ int font_size = theme_cache.font_size;
+ if (font.is_null()) {
+ return;
+ }
+
Size2 old_size = TS->shaped_text_get_size(text_rid);
TS->shaped_text_clear(text_rid);
@@ -2186,9 +2229,6 @@ void LineEdit::_shape() {
}
TS->shaped_text_set_preserve_control(text_rid, draw_control_chars);
- const Ref<Font> &font = theme_cache.font;
- int font_size = theme_cache.font_size;
- ERR_FAIL_COND(font.is_null());
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
@@ -2353,6 +2393,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon);
ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &LineEdit::set_flat);
ClassDB::bind_method(D_METHOD("is_flat"), &LineEdit::is_flat);
+ ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &LineEdit::set_select_all_on_focus);
+ ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &LineEdit::is_select_all_on_focus);
ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
ADD_SIGNAL(MethodInfo("text_change_rejected", PropertyInfo(Variant::STRING, "rejected_substring")));
@@ -2416,6 +2458,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index a4d5205f81..e0a079b623 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -174,6 +174,9 @@ private:
double caret_blink_timer = 0.0;
bool caret_blinking = false;
+ bool pending_select_all_on_focus = false;
+ bool select_all_on_focus = false;
+
struct ThemeCache {
Ref<StyleBox> normal;
Ref<StyleBox> read_only;
@@ -199,8 +202,6 @@ private:
float base_scale = 1.0;
} theme_cache;
- bool _is_over_clear_button(const Point2 &p_pos) const;
-
void _clear_undo_stack();
void _clear_redo();
void _create_undo_state();
@@ -240,6 +241,7 @@ private:
void _ensure_menu();
protected:
+ bool _is_over_clear_button(const Point2 &p_pos) const;
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
@@ -366,6 +368,10 @@ public:
void set_flat(bool p_enabled);
bool is_flat() const;
+ void set_select_all_on_focus(bool p_enabled);
+ bool is_select_all_on_focus() const;
+ void clear_pending_select_all_on_focus(); // For other controls, e.g. SpinBox.
+
virtual bool is_text_field() const override;
void show_virtual_keyboard();
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 75592a1b99..82ef53e317 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -41,7 +41,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
}
MutexLock lock(mutex);
- if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
int new_sel = selected_menu;
int old_sel = (selected_menu < 0) ? 0 : selected_menu;
do {
@@ -63,7 +63,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
_open_popup(selected_menu, true);
}
return;
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
int new_sel = selected_menu;
int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu;
do {
@@ -149,10 +149,6 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) {
void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (disable_shortcuts) {
return;
}
@@ -175,34 +171,6 @@ void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
}
}
-void MenuBar::set_shortcut_context(Node *p_node) {
- if (p_node != nullptr) {
- shortcut_context = p_node->get_instance_id();
- } else {
- shortcut_context = ObjectID();
- }
-}
-
-Node *MenuBar::get_shortcut_context() const {
- Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
- Node *ctx_node = Object::cast_to<Node>(ctx_obj);
-
- return ctx_node;
-}
-
-bool MenuBar::_is_focus_owner_in_shortcut_context() const {
- if (shortcut_context == ObjectID()) {
- // No context, therefore global - always "in" context.
- return true;
- }
-
- Node *ctx_node = get_shortcut_context();
- Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
-
- // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
- return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
-}
-
void MenuBar::_popup_visibility_changed(bool p_visible) {
if (!p_visible) {
active_menu = -1;
@@ -213,19 +181,19 @@ void MenuBar::_popup_visibility_changed(bool p_visible) {
}
if (switch_on_hover) {
- Window *window = Object::cast_to<Window>(get_viewport());
- if (window) {
- mouse_pos_adjusted = window->get_position();
-
- if (window->is_embedded()) {
- Window *window_parent = Object::cast_to<Window>(window->get_parent()->get_viewport());
- while (window_parent) {
- if (!window_parent->is_embedded()) {
- mouse_pos_adjusted += window_parent->get_position();
+ Window *wnd = Object::cast_to<Window>(get_viewport());
+ if (wnd) {
+ mouse_pos_adjusted = wnd->get_position();
+
+ if (wnd->is_embedded()) {
+ Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport());
+ while (wnd_parent) {
+ if (!wnd_parent->is_embedded()) {
+ mouse_pos_adjusted += wnd_parent->get_position();
break;
}
- window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport());
+ wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport());
}
}
@@ -694,16 +662,12 @@ void MenuBar::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden);
ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden);
- ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context);
- ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context);
-
ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
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_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/menu_bar.h b/scene/gui/menu_bar.h
index f7ef19e98b..c057a7c96f 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -118,8 +118,6 @@ class MenuBar : public Control {
void _clear_menu();
void _update_menu();
- bool _is_focus_owner_in_shortcut_context() const;
-
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
@@ -170,9 +168,6 @@ public:
void set_menu_hidden(int p_menu, bool p_hidden);
bool is_menu_hidden(int p_menu) const;
- void set_shortcut_context(Node *p_node);
- Node *get_shortcut_context() const;
-
PopupMenu *get_menu_popup(int p_menu) const;
virtual void get_translatable_strings(List<String> *p_strings) const override;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index fa8df48412..786f23873e 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -36,10 +36,6 @@
void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!_is_focus_owner_in_shortcut_context()) {
- return;
- }
-
if (disable_shortcuts) {
return;
}
@@ -61,19 +57,19 @@ void MenuButton::_popup_visibility_changed(bool p_visible) {
}
if (switch_on_hover) {
- Window *window = Object::cast_to<Window>(get_viewport());
- if (window) {
- mouse_pos_adjusted = window->get_position();
-
- if (window->is_embedded()) {
- Window *window_parent = Object::cast_to<Window>(window->get_parent()->get_viewport());
- while (window_parent) {
- if (!window_parent->is_embedded()) {
- mouse_pos_adjusted += window_parent->get_position();
+ Window *wnd = Object::cast_to<Window>(get_viewport());
+ if (wnd) {
+ mouse_pos_adjusted = wnd->get_position();
+
+ if (wnd->is_embedded()) {
+ Window *wnd_parent = Object::cast_to<Window>(wnd->get_parent()->get_viewport());
+ while (wnd_parent) {
+ if (!wnd_parent->is_embedded()) {
+ mouse_pos_adjusted += wnd_parent->get_position();
break;
}
- window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport());
+ wnd_parent = Object::cast_to<Window>(wnd_parent->get_parent()->get_viewport());
}
}
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index ceae3791f3..434eb87e7a 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -77,28 +77,36 @@ void Popup::_update_theme_item_cache() {
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_visible()) {
- _initialize_visible_parents();
- } else {
- _deinitialize_visible_parents();
- emit_signal(SNAME("popup_hide"));
- popped_up = false;
+ if (!is_in_edited_scene_root()) {
+ if (is_visible()) {
+ _initialize_visible_parents();
+ } else {
+ _deinitialize_visible_parents();
+ emit_signal(SNAME("popup_hide"));
+ popped_up = false;
+ }
}
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
- if (has_focus()) {
- popped_up = true;
+ if (!is_in_edited_scene_root()) {
+ if (has_focus()) {
+ popped_up = true;
+ }
}
} break;
case NOTIFICATION_EXIT_TREE: {
- _deinitialize_visible_parents();
+ if (!is_in_edited_scene_root()) {
+ _deinitialize_visible_parents();
+ }
} break;
case NOTIFICATION_WM_CLOSE_REQUEST:
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
- _close_pressed();
+ if (!is_in_edited_scene_root()) {
+ _close_pressed();
+ }
} break;
}
}
@@ -126,52 +134,62 @@ void Popup::_bind_methods() {
ADD_SIGNAL(MethodInfo("popup_hide"));
}
+void Popup::_validate_property(PropertyInfo &p_property) const {
+ if (
+ p_property.name == "transient" ||
+ p_property.name == "exclusive" ||
+ p_property.name == "popup_window" ||
+ p_property.name == "unfocusable") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+}
+
Rect2i Popup::_popup_adjust_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2i parent = get_usable_parent_rect();
+ Rect2i parent_rect = get_usable_parent_rect();
- if (parent == Rect2i()) {
+ if (parent_rect == Rect2i()) {
return Rect2i();
}
Rect2i current(get_position(), get_size());
- if (current.position.x + current.size.x > parent.position.x + parent.size.x) {
- current.position.x = parent.position.x + parent.size.x - current.size.x;
+ if (current.position.x + current.size.x > parent_rect.position.x + parent_rect.size.x) {
+ current.position.x = parent_rect.position.x + parent_rect.size.x - current.size.x;
}
- if (current.position.x < parent.position.x) {
- current.position.x = parent.position.x;
+ if (current.position.x < parent_rect.position.x) {
+ current.position.x = parent_rect.position.x;
}
- if (current.position.y + current.size.y > parent.position.y + parent.size.y) {
- current.position.y = parent.position.y + parent.size.y - current.size.y;
+ if (current.position.y + current.size.y > parent_rect.position.y + parent_rect.size.y) {
+ current.position.y = parent_rect.position.y + parent_rect.size.y - current.size.y;
}
- if (current.position.y < parent.position.y) {
- current.position.y = parent.position.y;
+ if (current.position.y < parent_rect.position.y) {
+ current.position.y = parent_rect.position.y;
}
- if (current.size.y > parent.size.y) {
- current.size.y = parent.size.y;
+ if (current.size.y > parent_rect.size.y) {
+ current.size.y = parent_rect.size.y;
}
- if (current.size.x > parent.size.x) {
- current.size.x = parent.size.x;
+ if (current.size.x > parent_rect.size.x) {
+ current.size.x = parent_rect.size.x;
}
// Early out if max size not set.
- Size2i max_size = get_max_size();
- if (max_size <= Size2()) {
+ Size2i popup_max_size = get_max_size();
+ if (popup_max_size <= Size2()) {
return current;
}
- if (current.size.x > max_size.x) {
- current.size.x = max_size.x;
+ if (current.size.x > popup_max_size.x) {
+ current.size.x = popup_max_size.x;
}
- if (current.size.y > max_size.y) {
- current.size.y = max_size.y;
+ if (current.size.y > popup_max_size.y) {
+ current.size.y = popup_max_size.y;
}
return current;
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 0d6ca25c18..57b811cadb 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -59,6 +59,7 @@ protected:
virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
virtual void _parent_focused();
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 10e13042a7..9a411ef7ed 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -58,20 +58,20 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
bool has_check = false;
for (int i = 0; i < items.size(); i++) {
- Size2 size;
+ Size2 item_size;
Size2 icon_size = items[i].get_icon_size();
- size.height = _get_item_height(i);
+ item_size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
- size.width += items[i].indent * theme_cache.indent;
+ item_size.width += items[i].indent * theme_cache.indent;
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
}
- size.width += items[i].text_buf->get_size().x;
- size.height += theme_cache.v_separation;
+ item_size.width += items[i].text_buf->get_size().x;
+ item_size.height += theme_cache.v_separation;
if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) {
int accel_w = theme_cache.h_separation * 2;
@@ -80,12 +80,12 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
}
if (!items[i].submenu.is_empty()) {
- size.width += theme_cache.submenu->get_width();
+ item_size.width += theme_cache.submenu->get_width();
}
- max_w = MAX(max_w, size.width);
+ max_w = MAX(max_w, item_size.width);
- minsize.height += size.height;
+ minsize.height += item_size.height;
}
int item_side_padding = theme_cache.item_start_padding + theme_cache.item_end_padding;
@@ -273,7 +273,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!items.is_empty()) {
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_down", true) && p_event->is_pressed()) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
search_from = 0;
@@ -305,7 +305,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_up", true) && p_event->is_pressed()) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
@@ -337,7 +337,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
}
}
}
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
Node *n = get_parent();
if (n) {
if (Object::cast_to<PopupMenu>(n)) {
@@ -349,7 +349,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
set_input_as_handled();
@@ -361,7 +361,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) {
if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index c9516ed6b9..0dece1c287 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -56,10 +56,8 @@ Variant RichTextEffect::get_bbcode() const {
bool RichTextEffect::_process_effect_impl(Ref<CharFXTransform> p_cfx) {
bool return_value = false;
- if (GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value)) {
- return return_value;
- }
- return false;
+ GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value);
+ return return_value;
}
RichTextEffect::RichTextEffect() {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 7ea46a0b4f..7f487175dc 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -167,17 +167,17 @@ String RichTextLabel::_roman(int p_num, bool p_capitalize) const {
};
String s;
if (p_capitalize) {
- const String M[] = { "", "M", "MM", "MMM" };
- const String C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
- const String X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
- const String I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
- s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
+ const String roman_M[] = { "", "M", "MM", "MMM" };
+ const String roman_C[] = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
+ const String roman_X[] = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
+ const String roman_I[] = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
+ s = roman_M[p_num / 1000] + roman_C[(p_num % 1000) / 100] + roman_X[(p_num % 100) / 10] + roman_I[p_num % 10];
} else {
- const String M[] = { "", "m", "mm", "mmm" };
- const String C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
- const String X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
- const String I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
- s = M[p_num / 1000] + C[(p_num % 1000) / 100] + X[(p_num % 100) / 10] + I[p_num % 10];
+ const String roman_M[] = { "", "m", "mm", "mmm" };
+ const String roman_C[] = { "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
+ const String roman_X[] = { "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
+ const String roman_I[] = { "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
+ s = roman_M[p_num / 1000] + roman_C[(p_num % 1000) / 100] + roman_X[(p_num % 100) / 10] + roman_I[p_num % 10];
}
return s;
}
@@ -468,7 +468,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
// Shape current paragraph.
- String text;
+ String txt;
Item *it_to = (p_line + 1 < (int)p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
int remaining_characters = visible_characters - l.char_offset;
for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
@@ -502,7 +502,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
font_size = font_size_it->font_size;
}
l.text_buf->add_string("\n", font, font_size);
- text += "\n";
+ txt += "\n";
l.char_count++;
remaining_characters--;
} break;
@@ -532,13 +532,13 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
remaining_characters -= tx.length();
l.text_buf->add_string(tx, font, font_size, lang, (uint64_t)it);
- text += tx;
+ txt += tx;
l.char_count += tx.length();
} break;
case ITEM_IMAGE: {
ItemImage *img = static_cast<ItemImage *>(it);
l.text_buf->add_object((uint64_t)it, img->size, img->inline_align, 1);
- text += String::chr(0xfffc);
+ txt += String::chr(0xfffc);
l.char_count++;
remaining_characters--;
} break;
@@ -693,15 +693,15 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
l.text_buf->add_object((uint64_t)it, Size2(table->total_width, table->total_height), table->inline_align, t_char_count);
- text += String::chr(0xfffc).repeat(t_char_count);
+ txt += String::chr(0xfffc).repeat(t_char_count);
} break;
default:
break;
}
}
- //Apply BiDi override.
- l.text_buf->set_bidi_override(structured_text_parser(_find_stt(l.from), st_args, text));
+ // Apply BiDi override.
+ l.text_buf->set_bidi_override(structured_text_parser(_find_stt(l.from), st_args, txt));
*r_char_offset = l.char_offset + l.char_count;
@@ -987,7 +987,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
font_shadow_color.a = faded_visibility;
}
- bool visible = (font_outline_color.a != 0) || (font_shadow_color.a != 0);
+ bool txt_visible = (font_outline_color.a != 0) || (font_shadow_color.a != 0);
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
@@ -1002,7 +1002,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (!custom_effect.is_null()) {
charfx->elapsed_time = item_custom->elapsed_time;
charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
- charfx->visibility = visible;
+ charfx->visibility = txt_visible;
charfx->outline = true;
charfx->font = frid;
charfx->glyph_index = gl;
@@ -1018,7 +1018,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
font_color = charfx->color;
frid = charfx->font;
gl = charfx->glyph_index;
- visible &= charfx->visibility;
+ txt_visible &= charfx->visibility;
}
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
@@ -1062,7 +1062,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
const Color modulated_outline_color = font_outline_color * Color(1, 1, 1, font_color.a);
const Color modulated_shadow_color = font_shadow_color * Color(1, 1, 1, font_color.a);
for (int j = 0; j < glyphs[i].repeat; j++) {
- if (visible) {
+ if (txt_visible) {
bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs));
if (!skip && frid != RID()) {
if (modulated_shadow_color.a > 0) {
@@ -1087,7 +1087,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
_draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0);
// Draw main text.
- Color selection_fg = theme_cache.font_selected_color;
Color selection_bg = theme_cache.selection_color;
int sel_start = -1;
@@ -1205,7 +1204,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
font_color.a = faded_visibility;
}
- bool visible = (font_color.a != 0);
+ bool txt_visible = (font_color.a != 0);
for (int j = 0; j < fx_stack.size(); j++) {
ItemFX *item_fx = fx_stack[j];
@@ -1220,7 +1219,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (!custom_effect.is_null()) {
charfx->elapsed_time = item_custom->elapsed_time;
charfx->range = Vector2i(l.char_offset + glyphs[i].start, l.char_offset + glyphs[i].end);
- charfx->visibility = visible;
+ charfx->visibility = txt_visible;
charfx->outline = false;
charfx->font = frid;
charfx->glyph_index = gl;
@@ -1236,7 +1235,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
font_color = charfx->color;
frid = charfx->font;
gl = charfx->glyph_index;
- visible &= charfx->visibility;
+ txt_visible &= charfx->visibility;
}
} else if (item_fx->type == ITEM_SHAKE) {
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
@@ -1276,19 +1275,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
- if (selected) {
- font_color = override_selected_font_color ? selection_fg : font_color;
+ if (selected && use_selected_font_color) {
+ font_color = theme_cache.font_selected_color;
}
// Draw glyphs.
for (int j = 0; j < glyphs[i].repeat; j++) {
bool skip = (trim_chars && l.char_offset + glyphs[i].end > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs));
- if (visible) {
+ if (txt_visible) {
if (!skip) {
if (frid != RID()) {
- TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ TS->font_draw_glyph(frid, ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, selected ? selection_fg : font_color);
+ TS->draw_hex_code_box(ci, glyphs[i].font_size, p_ofs + fx_offset + off, gl, font_color);
}
}
r_processed_glyphs++;
@@ -1688,6 +1687,7 @@ void RichTextLabel::_update_theme_item_cache() {
theme_cache.default_color = get_theme_color(SNAME("default_color"));
theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
+ use_selected_font_color = theme_cache.font_selected_color != Color(0, 0, 0, 0);
theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
@@ -2019,36 +2019,36 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
if (k->is_pressed()) {
bool handled = false;
- if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_page_up", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() - vscroll->get_page());
handled = true;
}
- if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_page_down", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() + vscroll->get_page());
handled = true;
}
- if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_up", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
- if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size));
handled = true;
}
- if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(0);
handled = true;
}
- if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) {
+ if (k->is_action("ui_end", true) && vscroll->is_visible_in_tree()) {
vscroll->set_value(vscroll->get_max());
handled = true;
}
if (is_shortcut_keys_enabled()) {
- if (k->is_action("ui_text_select_all")) {
+ if (k->is_action("ui_text_select_all", true)) {
select_all();
handled = true;
}
- if (k->is_action("ui_copy")) {
+ if (k->is_action("ui_copy", true)) {
selection_copy();
handled = true;
}
@@ -2956,7 +2956,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
memdelete(p_item);
}
-void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment) {
+void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment, const Rect2 &p_region) {
_stop_thread();
MutexLock data_lock(data_mutex);
@@ -2969,7 +2969,15 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
ERR_FAIL_COND(p_image->get_height() == 0);
ItemImage *item = memnew(ItemImage);
- item->image = p_image;
+ if (p_region.has_area()) {
+ Ref<AtlasTexture> atlas_tex = memnew(AtlasTexture);
+ atlas_tex->set_atlas(p_image);
+ atlas_tex->set_region(p_region);
+ item->image = atlas_tex;
+ } else {
+ item->image = p_image;
+ }
+
item->color = p_color;
item->inline_align = p_alignment;
@@ -2981,17 +2989,30 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width,
item->size.height = p_height;
} else {
// calculate height to keep aspect ratio
- item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ if (p_region.has_area()) {
+ item->size.height = p_region.get_size().height * p_width / p_region.get_size().width;
+ } else {
+ item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ }
}
} else {
if (p_height > 0) {
// custom height
item->size.height = p_height;
// calculate width to keep aspect ratio
- item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ if (p_region.has_area()) {
+ item->size.width = p_region.get_size().width * p_height / p_region.get_size().height;
+ } else {
+ item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ }
} else {
- // keep original width and height
- item->size = p_image->get_size();
+ if (p_region.has_area()) {
+ // if the image has a region, keep the region size
+ item->size = p_region.get_size();
+ } else {
+ // keep original width and height
+ item->size = p_image->get_size();
+ }
}
}
@@ -3543,14 +3564,6 @@ bool RichTextLabel::is_hint_underlined() const {
return underline_hint;
}
-void RichTextLabel::set_override_selected_font_color(bool p_override_selected_font_color) {
- override_selected_font_color = p_override_selected_font_color;
-}
-
-bool RichTextLabel::is_overriding_selected_font_color() const {
- return override_selected_font_color;
-}
-
void RichTextLabel::set_offset(int p_pixel) {
vscroll->set_value(p_pixel);
}
@@ -3609,21 +3622,21 @@ void RichTextLabel::append_text(const String &p_bbcode) {
brk_pos = p_bbcode.length();
}
- String text = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : "";
+ String txt = brk_pos > pos ? p_bbcode.substr(pos, brk_pos - pos) : "";
// Trim the first newline character, it may be added later as needed.
if (after_list_close_tag || after_list_open_tag) {
- text = text.trim_prefix("\n");
+ txt = txt.trim_prefix("\n");
}
if (brk_pos == p_bbcode.length()) {
// For tags that are not properly closed.
- if (text.is_empty() && after_list_open_tag) {
- text = "\n";
+ if (txt.is_empty() && after_list_open_tag) {
+ txt = "\n";
}
- if (!text.is_empty()) {
- add_text(text);
+ if (!txt.is_empty()) {
+ add_text(txt);
}
break; //nothing else to add
}
@@ -3632,8 +3645,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
if (brk_end == -1) {
//no close, add the rest
- text += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos);
- add_text(text);
+ txt += p_bbcode.substr(brk_pos, p_bbcode.length() - brk_pos);
+ add_text(txt);
break;
}
@@ -3679,36 +3692,36 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
if (!tag_ok) {
- text += "[" + tag;
- add_text(text);
+ txt += "[" + tag;
+ add_text(txt);
after_list_open_tag = false;
after_list_close_tag = false;
pos = brk_end;
continue;
}
- if (text.is_empty() && after_list_open_tag) {
- text = "\n"; // Make empty list have at least one item.
+ if (txt.is_empty() && after_list_open_tag) {
+ txt = "\n"; // Make empty list have at least one item.
}
after_list_open_tag = false;
if (tag == "/ol" || tag == "/ul") {
- if (!text.is_empty()) {
+ if (!txt.is_empty()) {
// Make sure text ends with a newline character, that is, the last item
// will wrap at the end of block.
- if (!text.ends_with("\n")) {
- text += "\n";
+ if (!txt.ends_with("\n")) {
+ txt += "\n";
}
} else if (!after_list_close_tag) {
- text = "\n"; // Make the innermost list item wrap at the end of lists.
+ txt = "\n"; // Make the innermost list item wrap at the end of lists.
}
after_list_close_tag = true;
} else {
after_list_close_tag = false;
}
- if (!text.is_empty()) {
- add_text(text);
+ if (!txt.is_empty()) {
+ add_text(txt);
}
tag_stack.pop_front();
@@ -3720,15 +3733,15 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
if (tag == "ol" || tag.begins_with("ol ") || tag == "ul" || tag.begins_with("ul ")) {
- if (text.is_empty() && after_list_open_tag) {
- text = "\n"; // Make each list have at least one item at the beginning.
+ if (txt.is_empty() && after_list_open_tag) {
+ txt = "\n"; // Make each list have at least one item at the beginning.
}
after_list_open_tag = true;
} else {
after_list_open_tag = false;
}
- if (!text.is_empty()) {
- add_text(text);
+ if (!txt.is_empty()) {
+ add_text(txt);
}
after_list_close_tag = false;
@@ -3970,7 +3983,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
Control::TextDirection dir = Control::TEXT_DIRECTION_INHERITED;
String lang;
- TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
+ TextServer::StructuredTextParser st_parser_type = TextServer::STRUCTURED_TEXT_DEFAULT;
for (int i = 0; i < subtag.size(); i++) {
Vector<String> subtag_a = subtag[i].split("=");
if (subtag_a.size() == 2) {
@@ -3996,24 +4009,24 @@ void RichTextLabel::append_text(const String &p_bbcode) {
lang = subtag_a[1];
} else if (subtag_a[0] == "st" || subtag_a[0] == "bidi_override") {
if (subtag_a[1] == "d" || subtag_a[1] == "default") {
- st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
+ st_parser_type = TextServer::STRUCTURED_TEXT_DEFAULT;
} else if (subtag_a[1] == "u" || subtag_a[1] == "uri") {
- st_parser = TextServer::STRUCTURED_TEXT_URI;
+ st_parser_type = TextServer::STRUCTURED_TEXT_URI;
} else if (subtag_a[1] == "f" || subtag_a[1] == "file") {
- st_parser = TextServer::STRUCTURED_TEXT_FILE;
+ st_parser_type = TextServer::STRUCTURED_TEXT_FILE;
} else if (subtag_a[1] == "e" || subtag_a[1] == "email") {
- st_parser = TextServer::STRUCTURED_TEXT_EMAIL;
+ st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL;
} else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
- st_parser = TextServer::STRUCTURED_TEXT_LIST;
+ st_parser_type = TextServer::STRUCTURED_TEXT_LIST;
} else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
- st_parser = TextServer::STRUCTURED_TEXT_NONE;
+ st_parser_type = TextServer::STRUCTURED_TEXT_NONE;
} else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
- st_parser = TextServer::STRUCTURED_TEXT_CUSTOM;
+ st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM;
}
}
}
}
- push_paragraph(alignment, dir, lang, st_parser);
+ push_paragraph(alignment, dir, lang, st_parser_type);
pos = brk_end + 1;
tag_stack.push_front("p");
} else if (tag == "url") {
@@ -4079,9 +4092,9 @@ void RichTextLabel::append_text(const String &p_bbcode) {
end = p_bbcode.length();
}
- String txt = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
+ String dc_txt = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
- push_dropcap(txt, f, fs, dropcap_margins, color, outline_size, outline_color);
+ push_dropcap(dc_txt, f, fs, dropcap_margins, color, outline_size, outline_color);
pos = end;
tag_stack.push_front(bbcode_name);
@@ -4126,6 +4139,18 @@ void RichTextLabel::append_text(const String &p_bbcode) {
Ref<Texture2D> texture = ResourceLoader::load(image, "Texture2D");
if (texture.is_valid()) {
+ Rect2 region;
+ OptionMap::Iterator region_option = bbcode_options.find("region");
+ if (region_option) {
+ Vector<String> region_values = region_option->value.split(",", false);
+ if (region_values.size() == 4) {
+ region.position.x = region_values[0].to_float();
+ region.position.y = region_values[1].to_float();
+ region.size.x = region_values[2].to_float();
+ region.size.y = region_values[3].to_float();
+ }
+ }
+
Color color = Color(1.0, 1.0, 1.0);
OptionMap::Iterator color_option = bbcode_options.find("color");
if (color_option) {
@@ -4154,7 +4179,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
}
- add_image(texture, width, height, color, (InlineAlignment)alignment);
+ add_image(texture, width, height, color, (InlineAlignment)alignment, region);
}
pos = end;
@@ -4668,19 +4693,19 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
Line &l = p_frame->lines[p_line];
- String text;
+ String txt;
Item *it_to = (p_line + 1 < (int)p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
switch (it->type) {
case ITEM_NEWLINE: {
- text += "\n";
+ txt += "\n";
} break;
case ITEM_TEXT: {
ItemText *t = static_cast<ItemText *>(it);
- text += t->text;
+ txt += t->text;
} break;
case ITEM_IMAGE: {
- text += " ";
+ txt += " ";
} break;
case ITEM_TABLE: {
ItemTable *table = static_cast<ItemTable *>(it);
@@ -4696,9 +4721,9 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p
int sp = -1;
if (p_reverse_search) {
- sp = text.rfindn(p_string, p_char_idx);
+ sp = txt.rfindn(p_string, p_char_idx);
} else {
- sp = text.findn(p_string, p_char_idx);
+ sp = txt.findn(p_string, p_char_idx);
}
if (sp != -1) {
@@ -4802,10 +4827,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
}
String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
- String text;
+ String txt;
- ERR_FAIL_COND_V(p_frame == nullptr, text);
- ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), text);
+ ERR_FAIL_COND_V(p_frame == nullptr, txt);
+ ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), txt);
Line &l = p_frame->lines[p_line];
@@ -4825,7 +4850,7 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
ERR_CONTINUE(E->type != ITEM_FRAME); // Children should all be frames.
ItemFrame *frame = static_cast<ItemFrame *>(E);
for (int i = 0; i < (int)frame->lines.size(); i++) {
- text += _get_line_text(frame, i, p_selection);
+ txt += _get_line_text(frame, i, p_selection);
}
}
}
@@ -4837,23 +4862,23 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p
}
if (it->type == ITEM_DROPCAP) {
const ItemDropcap *dc = static_cast<ItemDropcap *>(it);
- text += dc->text;
+ txt += dc->text;
} else if (it->type == ITEM_TEXT) {
const ItemText *t = static_cast<ItemText *>(it);
- text += t->text;
+ txt += t->text;
} else if (it->type == ITEM_NEWLINE) {
- text += "\n";
+ txt += "\n";
} else if (it->type == ITEM_IMAGE) {
- text += " ";
+ txt += " ";
}
}
if ((l.from != nullptr) && (p_frame == p_selection.to_frame) && (p_selection.to_item != nullptr) && (p_selection.to_item->index >= l.from->index) && (p_selection.to_item->index < end_idx)) {
- text = text.substr(0, p_selection.to_char);
+ txt = txt.substr(0, p_selection.to_char);
}
if ((l.from != nullptr) && (p_frame == p_selection.from_frame) && (p_selection.from_item != nullptr) && (p_selection.from_item->index >= l.from->index) && (p_selection.from_item->index < end_idx)) {
- text = text.substr(p_selection.from_char, -1);
+ txt = txt.substr(p_selection.from_char, -1);
}
- return text;
+ return txt;
}
void RichTextLabel::set_context_menu_enabled(bool p_enabled) {
@@ -4887,12 +4912,12 @@ String RichTextLabel::get_selected_text() const {
return "";
}
- String text;
+ String txt;
int to_line = main->first_invalid_line.load();
for (int i = 0; i < to_line; i++) {
- text += _get_line_text(main, i, selection);
+ txt += _get_line_text(main, i, selection);
}
- return text;
+ return txt;
}
void RichTextLabel::deselect() {
@@ -4901,10 +4926,10 @@ void RichTextLabel::deselect() {
}
void RichTextLabel::selection_copy() {
- String text = get_selected_text();
+ String txt = get_selected_text();
- if (!text.is_empty()) {
- DisplayServer::get_singleton()->clipboard_set(text);
+ if (!txt.is_empty()) {
+ DisplayServer::get_singleton()->clipboard_set(txt);
}
}
@@ -5018,25 +5043,25 @@ bool RichTextLabel::is_using_bbcode() const {
}
String RichTextLabel::get_parsed_text() const {
- String text = "";
+ String txt = "";
Item *it = main;
while (it) {
if (it->type == ITEM_DROPCAP) {
ItemDropcap *dc = static_cast<ItemDropcap *>(it);
- text += dc->text;
+ txt += dc->text;
} else if (it->type == ITEM_TEXT) {
ItemText *t = static_cast<ItemText *>(it);
- text += t->text;
+ txt += t->text;
} else if (it->type == ITEM_NEWLINE) {
- text += "\n";
+ txt += "\n";
} else if (it->type == ITEM_IMAGE) {
- text += " ";
+ txt += " ";
} else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) {
- text += "\t";
+ txt += "\t";
}
it = _get_next_item(it, true);
}
- return text;
+ return txt;
}
void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) {
@@ -5209,7 +5234,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_parsed_text"), &RichTextLabel::get_parsed_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
- ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER));
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font);
@@ -5261,9 +5286,6 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hint_underline", "enable"), &RichTextLabel::set_hint_underline);
ClassDB::bind_method(D_METHOD("is_hint_underlined"), &RichTextLabel::is_hint_underlined);
- ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &RichTextLabel::set_override_selected_font_color);
- ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &RichTextLabel::is_overriding_selected_font_color);
-
ClassDB::bind_method(D_METHOD("set_scroll_active", "active"), &RichTextLabel::set_scroll_active);
ClassDB::bind_method(D_METHOD("is_scroll_active"), &RichTextLabel::is_scroll_active);
@@ -5373,7 +5395,6 @@ void RichTextLabel::_bind_methods() {
ADD_GROUP("Text Selection", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
ADD_GROUP("Displayed Text", "");
@@ -5622,6 +5643,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
Vector2i fbg_index = Vector2i(end, start);
Color last_color = Color(0, 0, 0, 0);
bool draw_box = false;
+ int hpad = get_theme_constant(SNAME("text_highlight_h_padding"));
+ int vpad = get_theme_constant(SNAME("text_highlight_v_padding"));
// Draw a box based on color tags associated with glyphs
for (int i = start; i < end; i++) {
Item *it = _get_item_at_pos(it_from, it_to, i);
@@ -5651,8 +5674,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (draw_box) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, fbg_index.y);
for (int j = 0; j < sel.size(); j++) {
- Vector2 rect_off = line_off + Vector2(sel[j].x, -TS->shaped_text_get_ascent(p_rid));
- Vector2 rect_size = Vector2(sel[j].y - sel[j].x, TS->shaped_text_get_size(p_rid).y);
+ Vector2 rect_off = line_off + Vector2(sel[j].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
+ Vector2 rect_size = Vector2(sel[j].y - sel[j].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
fbg_index = Vector2i(end, start);
@@ -5670,8 +5693,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (last_color.a > 0) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, end);
for (int i = 0; i < sel.size(); i++) {
- Vector2 rect_off = line_off + Vector2(sel[i].x, -TS->shaped_text_get_ascent(p_rid));
- Vector2 rect_size = Vector2(sel[i].y - sel[i].x, TS->shaped_text_get_size(p_rid).y);
+ Vector2 rect_off = line_off + Vector2(sel[i].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
+ Vector2 rect_size = Vector2(sel[i].y - sel[i].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 71123602ad..d30baaa8d3 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -301,14 +301,14 @@ private:
_current_rng = Math::rand();
}
- uint64_t offset_random(int index) {
- return (_current_rng >> (index % 64)) |
- (_current_rng << (64 - (index % 64)));
+ uint64_t offset_random(int p_index) {
+ return (_current_rng >> (p_index % 64)) |
+ (_current_rng << (64 - (p_index % 64)));
}
- uint64_t offset_previous_random(int index) {
- return (_previous_rng >> (index % 64)) |
- (_previous_rng << (64 - (index % 64)));
+ uint64_t offset_previous_random(int p_index) {
+ return (_previous_rng >> (p_index % 64)) |
+ (_previous_rng << (64 - (p_index % 64)));
}
};
@@ -396,7 +396,7 @@ private:
int tab_size = 4;
bool underline_meta = true;
bool underline_hint = true;
- bool override_selected_font_color = false;
+ bool use_selected_font_color = false;
HorizontalAlignment default_alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -569,7 +569,7 @@ private:
public:
String get_parsed_text() const;
void add_text(const String &p_text);
- void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER);
+ void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0));
void add_newline();
bool remove_line(const int p_line);
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));
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 6c05b171e3..6899178885 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -183,35 +183,35 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
if (p_event->is_pressed()) {
- if (p_event->is_action("ui_left")) {
+ if (p_event->is_action("ui_left", true)) {
if (orientation != HORIZONTAL) {
return;
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_right")) {
+ } else if (p_event->is_action("ui_right", true)) {
if (orientation != HORIZONTAL) {
return;
}
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_up")) {
+ } else if (p_event->is_action("ui_up", true)) {
if (orientation != VERTICAL) {
return;
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_down")) {
+ } else if (p_event->is_action("ui_down", true)) {
if (orientation != VERTICAL) {
return;
}
set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- } else if (p_event->is_action("ui_home")) {
+ } else if (p_event->is_action("ui_home", true)) {
set_value(get_min());
- } else if (p_event->is_action("ui_end")) {
+ } else if (p_event->is_action("ui_end", true)) {
set_value(get_max());
}
}
@@ -338,7 +338,7 @@ void ScrollBar::_notification(int p_what) {
if (scrolling) {
if (get_value() != target_scroll) {
double target = target_scroll - get_value();
- double dist = sqrt(target * target);
+ double dist = abs(target);
double vel = ((target / dist) * 500) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 761072c5bc..ec34a8d26d 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -107,45 +107,65 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
double prev_v_scroll = v_scroll->get_value();
double prev_h_scroll = h_scroll->get_value();
+ bool h_scroll_enabled = horizontal_scroll_mode != SCROLL_MODE_DISABLED;
+ bool v_scroll_enabled = vertical_scroll_mode != SCROLL_MODE_DISABLED;
Ref<InputEventMouseButton> mb = p_gui_input;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_pressed()) {
- // only horizontal is enabled, scroll horizontally
- if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) {
- h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor());
- } else if (v_scroll->is_visible_in_tree()) {
- v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8 * mb->get_factor());
+ if (mb->is_pressed()) {
+ bool scroll_value_modified = false;
+
+ bool v_scroll_hidden = !v_scroll->is_visible() && vertical_scroll_mode != SCROLL_MODE_SHOW_NEVER;
+ if (mb->get_button_index() == MouseButton::WHEEL_UP) {
+ // By default, the vertical orientation takes precedence. This is an exception.
+ if ((h_scroll_enabled && mb->is_shift_pressed()) || v_scroll_hidden) {
+ h_scroll->set_value(prev_h_scroll - h_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ } else if (v_scroll_enabled) {
+ v_scroll->set_value(prev_v_scroll - v_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ }
}
- }
-
- if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_pressed()) {
- // only horizontal is enabled, scroll horizontally
- if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->is_shift_pressed())) {
- h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor());
- } else if (v_scroll->is_visible()) {
- v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8 * mb->get_factor());
+ if (mb->get_button_index() == MouseButton::WHEEL_DOWN) {
+ if ((h_scroll_enabled && mb->is_shift_pressed()) || v_scroll_hidden) {
+ h_scroll->set_value(prev_h_scroll + h_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ } else if (v_scroll_enabled) {
+ v_scroll->set_value(prev_v_scroll + v_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ }
}
- }
- if (mb->get_button_index() == MouseButton::WHEEL_LEFT && mb->is_pressed()) {
- if (h_scroll->is_visible_in_tree()) {
- h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb->get_factor() / 8);
+ bool h_scroll_hidden = !h_scroll->is_visible() && horizontal_scroll_mode != SCROLL_MODE_SHOW_NEVER;
+ if (mb->get_button_index() == MouseButton::WHEEL_LEFT) {
+ // By default, the horizontal orientation takes precedence. This is an exception.
+ if ((v_scroll_enabled && mb->is_shift_pressed()) || h_scroll_hidden) {
+ v_scroll->set_value(prev_v_scroll - v_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ } else if (h_scroll_enabled) {
+ h_scroll->set_value(prev_h_scroll - h_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ }
}
- }
-
- if (mb->get_button_index() == MouseButton::WHEEL_RIGHT && mb->is_pressed()) {
- if (h_scroll->is_visible_in_tree()) {
- h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * mb->get_factor() / 8);
+ if (mb->get_button_index() == MouseButton::WHEEL_RIGHT) {
+ if ((v_scroll_enabled && mb->is_shift_pressed()) || h_scroll_hidden) {
+ v_scroll->set_value(prev_v_scroll + v_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ } else if (h_scroll_enabled) {
+ h_scroll->set_value(prev_h_scroll + h_scroll->get_page() / 8 * mb->get_factor());
+ scroll_value_modified = true;
+ }
}
- }
- if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
- accept_event(); //accept event if scroll changed
+ if (scroll_value_modified && (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll)) {
+ accept_event(); // Accept event if scroll changed.
+ return;
+ }
}
- if (!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()))) {
+ bool screen_is_touchscreen = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
+ if (!screen_is_touchscreen) {
return;
}
@@ -161,8 +181,8 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
drag_speed = Vector2();
drag_accum = Vector2();
last_drag_accum = Vector2();
- drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value());
- drag_touching = !DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id()));
+ drag_from = Vector2(prev_h_scroll, prev_v_scroll);
+ drag_touching = screen_is_touchscreen;
drag_touching_deaccel = false;
beyond_deadzone = false;
time_since_motion = 0;
@@ -180,6 +200,7 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
}
+ return;
}
Ref<InputEventMouseMotion> mm = p_gui_input;
@@ -189,22 +210,22 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
Vector2 motion = mm->get_relative();
drag_accum -= motion;
- if (beyond_deadzone || (horizontal_scroll_mode != SCROLL_MODE_DISABLED && Math::abs(drag_accum.x) > deadzone) || (vertical_scroll_mode != SCROLL_MODE_DISABLED && Math::abs(drag_accum.y) > deadzone)) {
+ if (beyond_deadzone || (h_scroll_enabled && Math::abs(drag_accum.x) > deadzone) || (v_scroll_enabled && Math::abs(drag_accum.y) > deadzone)) {
if (!beyond_deadzone) {
propagate_notification(NOTIFICATION_SCROLL_BEGIN);
emit_signal(SNAME("scroll_started"));
beyond_deadzone = true;
- // resetting drag_accum here ensures smooth scrolling after reaching deadzone
+ // Resetting drag_accum here ensures smooth scrolling after reaching deadzone.
drag_accum = -motion;
}
Vector2 diff = drag_from + drag_accum;
- if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) {
+ if (h_scroll_enabled) {
h_scroll->set_value(diff.x);
} else {
drag_accum.x = 0;
}
- if (vertical_scroll_mode != SCROLL_MODE_DISABLED) {
+ if (v_scroll_enabled) {
v_scroll->set_value(diff.y);
} else {
drag_accum.y = 0;
@@ -212,20 +233,26 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
time_since_motion = 0;
}
}
+
+ if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
+ accept_event(); // Accept event if scroll changed.
+ }
+ return;
}
Ref<InputEventPanGesture> pan_gesture = p_gui_input;
if (pan_gesture.is_valid()) {
- if (h_scroll->is_visible_in_tree()) {
- h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * pan_gesture->get_delta().x / 8);
+ if (h_scroll_enabled) {
+ h_scroll->set_value(prev_h_scroll + h_scroll->get_page() * pan_gesture->get_delta().x / 8);
}
- if (v_scroll->is_visible_in_tree()) {
- v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
+ if (v_scroll_enabled) {
+ v_scroll->set_value(prev_v_scroll + v_scroll->get_page() * pan_gesture->get_delta().y / 8);
}
- }
- if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
- accept_event(); //accept event if scroll changed
+ if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) {
+ accept_event(); // Accept event if scroll changed.
+ }
+ return;
}
}
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index ff3adfb9ac..6cbacf0dd3 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -138,10 +138,10 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
accept_event();
- } else if (p_event->is_action("ui_home") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_home", true) && p_event->is_pressed()) {
set_value(get_min());
accept_event();
- } else if (p_event->is_action("ui_end") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_end", true) && p_event->is_pressed()) {
set_value(get_max());
accept_event();
}
@@ -227,7 +227,7 @@ void Slider::_notification(int p_what) {
tick->draw(ci, Point2i((size.width - widget_width) / 2, ofs));
}
}
- grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2, size.height - ratio * areasize - grabber->get_size().height));
+ grabber->draw(ci, Point2i(size.width / 2 - grabber->get_size().width / 2 + get_theme_constant(SNAME("grabber_offset")), size.height - ratio * areasize - grabber->get_size().height));
} else {
int widget_height = style->get_minimum_size().height + style->get_center_size().height;
double areasize = size.width - grabber->get_size().width;
@@ -245,7 +245,7 @@ void Slider::_notification(int p_what) {
tick->draw(ci, Point2i(ofs, (size.height - widget_height) / 2));
}
}
- grabber->draw(ci, Point2i(ratio * areasize, size.height / 2 - grabber->get_size().height / 2));
+ grabber->draw(ci, Point2i(ratio * areasize, size.height / 2 - grabber->get_size().height / 2 + get_theme_constant(SNAME("grabber_offset"))));
}
} break;
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index fe14049d93..c4000120c8 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -168,6 +168,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
range_click_timer->stop();
_release_mouse();
drag.allowed = false;
+ line_edit->clear_pending_select_all_on_focus();
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -190,6 +191,11 @@ void SpinBox::_line_edit_focus_enter() {
int col = line_edit->get_caret_column();
_value_changed(0); // Update the LineEdit's text.
line_edit->set_caret_column(col);
+
+ // LineEdit text might change and it clears any selection. Have to re-select here.
+ if (line_edit->is_select_all_on_focus() && !Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
+ line_edit->select_all();
+ }
}
void SpinBox::_line_edit_focus_exit() {
@@ -308,6 +314,14 @@ bool SpinBox::get_update_on_text_changed() const {
return update_on_text_changed;
}
+void SpinBox::set_select_all_on_focus(bool p_enabled) {
+ line_edit->set_select_all_on_focus(p_enabled);
+}
+
+bool SpinBox::is_select_all_on_focus() const {
+ return line_edit->is_select_all_on_focus();
+}
+
void SpinBox::set_editable(bool p_enabled) {
line_edit->set_editable(p_enabled);
}
@@ -341,6 +355,8 @@ void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable);
ClassDB::bind_method(D_METHOD("set_update_on_text_changed", "enabled"), &SpinBox::set_update_on_text_changed);
ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed);
+ ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &SpinBox::set_select_all_on_focus);
+ ClassDB::bind_method(D_METHOD("is_select_all_on_focus"), &SpinBox::is_select_all_on_focus);
ClassDB::bind_method(D_METHOD("apply"), &SpinBox::apply);
ClassDB::bind_method(D_METHOD("get_line_edit"), &SpinBox::get_line_edit);
@@ -350,6 +366,7 @@ void SpinBox::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step"), "set_custom_arrow_step", "get_custom_arrow_step");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
}
SpinBox::SpinBox() {
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index c2f2ac3f5a..00f5a95699 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -101,6 +101,9 @@ public:
void set_update_on_text_changed(bool p_enabled);
bool get_update_on_text_changed() const;
+ void set_select_all_on_focus(bool p_enabled);
+ bool is_select_all_on_focus() const;
+
void apply();
void set_custom_arrow_step(const double p_custom_arrow_step);
double get_custom_arrow_step() const;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 38302136d6..cc9fc99b9c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -151,7 +151,7 @@ void TextEdit::Text::_calculate_line_height() {
}
void TextEdit::Text::_calculate_max_line_width() {
- int width = 0;
+ int line_width = 0;
for (const Line &l : text) {
if (l.hidden) {
continue;
@@ -159,12 +159,12 @@ void TextEdit::Text::_calculate_max_line_width() {
// Found another line with the same width...nothing to update.
if (l.width == max_width) {
- width = max_width;
+ line_width = max_width;
break;
}
- width = MAX(width, l.width);
+ line_width = MAX(line_width, l.width);
}
- max_width = width;
+ max_width = line_width;
}
void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_changed, const String &p_ime_text, const Array &p_bidi_override) {
@@ -233,14 +233,14 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan
// Update width.
const int old_width = text.write[p_line].width;
- int width = get_line_width(p_line);
- text.write[p_line].width = width;
+ int line_width = get_line_width(p_line);
+ text.write[p_line].width = line_width;
// If this line has shrunk, this may no longer the the longest line.
- if (old_width == max_width && width < max_width) {
+ if (old_width == max_width && line_width < max_width) {
_calculate_max_line_width();
} else if (!is_hidden(p_line)) {
- max_width = MAX(width, max_width);
+ max_width = MAX(line_width, max_width);
}
}
@@ -464,7 +464,7 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (scrolling && get_v_scroll() != target_v_scroll) {
double target_y = target_v_scroll - get_v_scroll();
- double dist = sqrt(target_y * target_y);
+ double dist = abs(target_y);
// To ensure minimap is responsive override the speed setting.
double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time();
@@ -536,145 +536,145 @@ void TextEdit::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), background_color);
}
- int brace_open_match_line = -1;
- int brace_open_match_column = -1;
- bool brace_open_matching = false;
- bool brace_open_mismatch = false;
- int brace_close_match_line = -1;
- int brace_close_match_column = -1;
- bool brace_close_matching = false;
- bool brace_close_mismatch = false;
-
- if (highlight_matching_braces_enabled && caret.line >= 0 && caret.line < text.size() && caret.column >= 0) {
- if (caret.column < text[caret.line].length()) {
- // Check for open.
- char32_t c = text[caret.line][caret.column];
- char32_t closec = 0;
-
- if (c == '[') {
- closec = ']';
- } else if (c == '{') {
- closec = '}';
- } else if (c == '(') {
- closec = ')';
+ Vector<BraceMatchingData> brace_matching;
+ if (highlight_matching_braces_enabled) {
+ brace_matching.resize(carets.size());
+
+ for (int caret = 0; caret < carets.size(); caret++) {
+ if (get_caret_line(caret) < 0 || get_caret_line(caret) >= text.size() || get_caret_column(caret) < 0) {
+ continue;
}
- if (closec != 0) {
- int stack = 1;
-
- for (int i = caret.line; i < text.size(); i++) {
- int from = i == caret.line ? caret.column + 1 : 0;
- for (int j = from; j < text[i].length(); j++) {
- char32_t cc = text[i][j];
- // Ignore any brackets inside a string.
- if (cc == '"' || cc == '\'') {
- char32_t quotation = cc;
- do {
- j++;
- if (!(j < text[i].length())) {
- break;
- }
- cc = text[i][j];
- // Skip over escaped quotation marks inside strings.
- if (cc == '\\') {
- bool escaped = true;
- while (j + 1 < text[i].length() && text[i][j + 1] == '\\') {
- escaped = !escaped;
- j++;
+ if (get_caret_column(caret) < text[get_caret_line(caret)].length()) {
+ // Check for open.
+ char32_t c = text[get_caret_line(caret)][get_caret_column(caret)];
+ char32_t closec = 0;
+
+ if (c == '[') {
+ closec = ']';
+ } else if (c == '{') {
+ closec = '}';
+ } else if (c == '(') {
+ closec = ')';
+ }
+
+ if (closec != 0) {
+ int stack = 1;
+
+ for (int i = get_caret_line(caret); i < text.size(); i++) {
+ int from = i == get_caret_line(caret) ? get_caret_column(caret) + 1 : 0;
+ for (int j = from; j < text[i].length(); j++) {
+ char32_t cc = text[i][j];
+ // Ignore any brackets inside a string.
+ if (cc == '"' || cc == '\'') {
+ char32_t quotation = cc;
+ do {
+ j++;
+ if (!(j < text[i].length())) {
+ break;
}
- if (escaped) {
- j++;
- continue;
+ cc = text[i][j];
+ // Skip over escaped quotation marks inside strings.
+ if (cc == '\\') {
+ bool escaped = true;
+ while (j + 1 < text[i].length() && text[i][j + 1] == '\\') {
+ escaped = !escaped;
+ j++;
+ }
+ if (escaped) {
+ j++;
+ continue;
+ }
}
- }
- } while (cc != quotation);
- } else if (cc == c) {
- stack++;
- } else if (cc == closec) {
- stack--;
- }
+ } while (cc != quotation);
+ } else if (cc == c) {
+ stack++;
+ } else if (cc == closec) {
+ stack--;
+ }
- if (stack == 0) {
- brace_open_match_line = i;
- brace_open_match_column = j;
- brace_open_matching = true;
+ if (stack == 0) {
+ brace_matching.write[caret].open_match_line = i;
+ brace_matching.write[caret].open_match_column = j;
+ brace_matching.write[caret].open_matching = true;
+ break;
+ }
+ }
+ if (brace_matching.write[caret].open_match_line != -1) {
break;
}
}
- if (brace_open_match_line != -1) {
- break;
- }
- }
- if (!brace_open_matching) {
- brace_open_mismatch = true;
+ if (!brace_matching.write[caret].open_matching) {
+ brace_matching.write[caret].open_mismatch = true;
+ }
}
}
- }
- if (caret.column > 0) {
- char32_t c = text[caret.line][caret.column - 1];
- char32_t closec = 0;
+ if (get_caret_column(caret) > 0) {
+ char32_t c = text[get_caret_line(caret)][get_caret_column(caret) - 1];
+ char32_t closec = 0;
- if (c == ']') {
- closec = '[';
- } else if (c == '}') {
- closec = '{';
- } else if (c == ')') {
- closec = '(';
- }
+ if (c == ']') {
+ closec = '[';
+ } else if (c == '}') {
+ closec = '{';
+ } else if (c == ')') {
+ closec = '(';
+ }
- if (closec != 0) {
- int stack = 1;
-
- for (int i = caret.line; i >= 0; i--) {
- int from = i == caret.line ? caret.column - 2 : text[i].length() - 1;
- for (int j = from; j >= 0; j--) {
- char32_t cc = text[i][j];
- // Ignore any brackets inside a string.
- if (cc == '"' || cc == '\'') {
- char32_t quotation = cc;
- do {
- j--;
- if (!(j >= 0)) {
- break;
- }
- cc = text[i][j];
- // Skip over escaped quotation marks inside strings.
- if (cc == quotation) {
- bool escaped = false;
- while (j - 1 >= 0 && text[i][j - 1] == '\\') {
- escaped = !escaped;
- j--;
+ if (closec != 0) {
+ int stack = 1;
+
+ for (int i = get_caret_line(caret); i >= 0; i--) {
+ int from = i == get_caret_line(caret) ? get_caret_column(caret) - 2 : text[i].length() - 1;
+ for (int j = from; j >= 0; j--) {
+ char32_t cc = text[i][j];
+ // Ignore any brackets inside a string.
+ if (cc == '"' || cc == '\'') {
+ char32_t quotation = cc;
+ do {
+ j--;
+ if (!(j >= 0)) {
+ break;
}
- if (escaped) {
- cc = '\\';
- continue;
+ cc = text[i][j];
+ // Skip over escaped quotation marks inside strings.
+ if (cc == quotation) {
+ bool escaped = false;
+ while (j - 1 >= 0 && text[i][j - 1] == '\\') {
+ escaped = !escaped;
+ j--;
+ }
+ if (escaped) {
+ cc = '\\';
+ continue;
+ }
}
- }
- } while (cc != quotation);
- } else if (cc == c) {
- stack++;
- } else if (cc == closec) {
- stack--;
- }
+ } while (cc != quotation);
+ } else if (cc == c) {
+ stack++;
+ } else if (cc == closec) {
+ stack--;
+ }
- if (stack == 0) {
- brace_close_match_line = i;
- brace_close_match_column = j;
- brace_close_matching = true;
+ if (stack == 0) {
+ brace_matching.write[caret].close_match_line = i;
+ brace_matching.write[caret].close_match_column = j;
+ brace_matching.write[caret].close_matching = true;
+ break;
+ }
+ }
+ if (brace_matching.write[caret].close_match_line != -1) {
break;
}
}
- if (brace_close_match_line != -1) {
- break;
- }
- }
- if (!brace_close_matching) {
- brace_close_mismatch = true;
+ if (!brace_matching.write[caret].close_matching) {
+ brace_matching.write[caret].close_mismatch = true;
+ }
}
}
}
@@ -683,16 +683,24 @@ void TextEdit::_notification(int p_what) {
bool draw_placeholder = text.size() == 1 && text[0].length() == 0;
// Get the highlighted words.
- String highlighted_text = get_selected_text();
+ String highlighted_text = get_selected_text(0);
// Check if highlighted words contain only whitespaces (tabs or spaces).
bool only_whitespaces_highlighted = highlighted_text.strip_edges().is_empty();
- const int caret_wrap_index = get_caret_wrap_index();
+ HashMap<int, HashSet<int>> caret_line_wrap_index_map;
+ Vector<int> carets_wrap_index;
+ carets_wrap_index.resize(carets.size());
+ for (int i = 0; i < carets.size(); i++) {
+ carets.write[i].visible = false;
+ int wrap_index = get_caret_wrap_index(i);
+ caret_line_wrap_index_map[get_caret_line(i)].insert(wrap_index);
+ carets_wrap_index.write[i] = wrap_index;
+ }
- int first_visible_line = get_first_visible_line() - 1;
+ int first_vis_line = get_first_visible_line() - 1;
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
- draw_amount += draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(first_visible_line + 1);
+ draw_amount += draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(first_vis_line + 1);
// Draw minimap.
if (draw_minimap) {
@@ -703,13 +711,13 @@ void TextEdit::_notification(int p_what) {
// calculate viewport size and y offset
int viewport_height = (draw_amount - 1) * minimap_line_height;
int control_height = _get_control_height() - viewport_height;
- int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
+ int viewport_offset_y = round(get_scroll_pos_for_line(first_vis_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
// calculate the first line.
int num_lines_before = round((viewport_offset_y) / minimap_line_height);
- int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
+ int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_vis_line;
if (minimap_line >= 0) {
- minimap_line -= get_next_visible_line_index_offset_from(first_visible_line, 0, -num_lines_before).x;
+ minimap_line -= get_next_visible_line_index_offset_from(first_vis_line, 0, -num_lines_before).x;
minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
}
int minimap_draw_amount = minimap_visible_lines + get_line_wrap_count(minimap_line + 1);
@@ -783,7 +791,7 @@ void TextEdit::_notification(int p_what) {
last_wrap_column += wrap_rows[line_wrap_index - 1].length();
}
- if (minimap_line == caret.line && caret_wrap_index == line_wrap_index && highlight_current_line) {
+ if (caret_line_wrap_index_map.has(minimap_line) && caret_line_wrap_index_map[minimap_line].has(line_wrap_index) && highlight_current_line) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, i * 3, minimap_width, 2), current_line_color);
} else {
@@ -875,10 +883,9 @@ void TextEdit::_notification(int p_what) {
}
// Draw main text.
- caret.visible = false;
line_drawing_cache.clear();
int row_height = draw_placeholder ? placeholder_line_height + line_spacing : get_line_height();
- int line = first_visible_line;
+ int line = first_vis_line;
for (int i = 0; i < draw_amount; i++) {
line++;
@@ -921,7 +928,7 @@ void TextEdit::_notification(int p_what) {
}
const String &str = wrap_rows[line_wrap_index];
- int char_margin = xmargin_beg - caret.x_ofs;
+ int char_margin = xmargin_beg - first_visible_col;
int ofs_x = 0;
int ofs_y = 0;
@@ -934,7 +941,7 @@ void TextEdit::_notification(int p_what) {
}
ofs_y += i * row_height + line_spacing / 2;
- ofs_y -= caret.wrap_ofs * row_height;
+ ofs_y -= first_visible_line_wrap_ofs * row_height;
ofs_y -= _get_v_scroll_offset() * row_height;
bool clipped = false;
@@ -960,7 +967,7 @@ void TextEdit::_notification(int p_what) {
if (str.length() == 0) {
// Draw line background if empty as we won't loop at all.
- if (line == caret.line && caret_wrap_index == line_wrap_index && highlight_current_line) {
+ if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), current_line_color);
} else {
@@ -969,17 +976,19 @@ void TextEdit::_notification(int p_what) {
}
// Give visual indication of empty selected line.
- if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) {
- float char_w = font->get_char_size(' ', font_size).width;
- if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), selection_color);
- } else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, row_height), selection_color);
+ for (int c = 0; c < carets.size(); c++) {
+ if (has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c) && char_margin >= xmargin_beg) {
+ float char_w = font->get_char_size(' ', font_size).width;
+ if (rtl) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), selection_color);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, row_height), selection_color);
+ }
}
}
} else {
// If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
- if (line == caret.line && caret_wrap_index == line_wrap_index && highlight_current_line) {
+ if (caret_line_wrap_index_map.has(line) && caret_line_wrap_index_map[line].has(line_wrap_index) && highlight_current_line) {
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), current_line_color);
} else {
@@ -1003,14 +1012,14 @@ void TextEdit::_notification(int p_what) {
switch (gutter.type) {
case GUTTER_TYPE_STRING: {
- const String &text = get_line_gutter_text(line, g);
- if (text.is_empty()) {
+ const String &txt = get_line_gutter_text(line, g);
+ if (txt.is_empty()) {
break;
}
Ref<TextLine> tl;
tl.instantiate();
- tl->add_string(text, font, font_size);
+ tl->add_string(txt, font, font_size);
int yofs = ofs_y + (row_height - tl->get_size().y) / 2;
if (outline_size > 0 && outline_color.a > 0) {
@@ -1074,23 +1083,25 @@ void TextEdit::_notification(int p_what) {
char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x;
}
- if (!clipped && 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;
- Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to);
- for (int j = 0; j < sel.size(); j++) {
- Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, row_height);
- if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
- continue;
- }
- if (rect.position.x < xmargin_beg) {
- rect.size.x -= (xmargin_beg - rect.position.x);
- rect.position.x = xmargin_beg;
- }
- if (rect.position.x + rect.size.x > xmargin_end) {
- rect.size.x = xmargin_end - rect.position.x;
+ for (int c = 0; c < carets.size(); c++) {
+ if (!clipped && has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c)) { // Selection
+ int sel_from = (line > get_selection_from_line(c)) ? TS->shaped_text_get_range(rid).x : get_selection_from_column(c);
+ int sel_to = (line < get_selection_to_line(c)) ? TS->shaped_text_get_range(rid).y : get_selection_to_column(c);
+ Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to);
+ for (int j = 0; j < sel.size(); j++) {
+ Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, row_height);
+ if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
+ continue;
+ }
+ if (rect.position.x < xmargin_beg) {
+ rect.size.x -= (xmargin_beg - rect.position.x);
+ rect.position.x = xmargin_beg;
+ }
+ if (rect.position.x + rect.size.x > xmargin_end) {
+ rect.size.x = xmargin_end - rect.position.x;
+ }
+ draw_rect(rect, selection_color, true);
}
- draw_rect(rect, selection_color, true);
}
}
@@ -1203,34 +1214,38 @@ void TextEdit::_notification(int p_what) {
}
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;
+ for (int c = 0; c < carets.size(); c++) {
+ if (has_selection(c) && line >= get_selection_from_line(c) && line <= get_selection_to_line(c)) { // Selection
+ int sel_from = (line > get_selection_from_line(c)) ? TS->shaped_text_get_range(rid).x : get_selection_from_column(c);
+ int sel_to = (line < get_selection_to_line(c)) ? TS->shaped_text_get_range(rid).y : get_selection_to_column(c);
- if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) {
- gl_color = font_selected_color;
+ if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && use_selected_font_color) {
+ gl_color = font_selected_color;
+ }
}
}
float char_pos = char_ofs + char_margin + ofs_x;
if (char_pos >= xmargin_beg) {
if (highlight_matching_braces_enabled) {
- 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) {
- gl_color = brace_mismatch_color;
+ for (int c = 0; c < carets.size(); c++) {
+ if ((brace_matching[c].open_match_line == line && brace_matching[c].open_match_column == glyphs[j].start) ||
+ (get_caret_column(c) == glyphs[j].start && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index && (brace_matching[c].open_matching || brace_matching[c].open_mismatch))) {
+ if (brace_matching[c].open_mismatch) {
+ 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, gl_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, 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) {
- gl_color = brace_mismatch_color;
+ if ((brace_matching[c].close_match_line == line && brace_matching[c].close_match_column == glyphs[j].start) ||
+ (get_caret_column(c) == glyphs[j].start + 1 && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index && (brace_matching[c].close_matching || brace_matching[c].close_mismatch))) {
+ if (brace_matching[c].close_mismatch) {
+ 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, gl_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, gl_color);
}
}
@@ -1289,137 +1304,155 @@ void TextEdit::_notification(int p_what) {
// Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1).
const int caret_width = get_theme_constant(SNAME("caret_width")) * MAX(1, get_theme_default_base_scale());
- if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) {
- caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
+ for (int c = 0; c < carets.size(); c++) {
+ if (!clipped && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index) {
+ carets.write[c].draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
- if (ime_text.length() == 0) {
- CaretInfo ts_caret;
- if (str.length() != 0) {
- // Get carets.
- ts_caret = TS->shaped_text_get_carets(rid, caret.column);
- } else {
- // No carets, add one at the start.
- int h = font->get_height(font_size);
- if (rtl) {
- ts_caret.l_dir = TextServer::DIRECTION_RTL;
- ts_caret.l_caret = Rect2(Vector2(xmargin_end - char_margin + ofs_x, -h / 2), Size2(caret_width * 4, h));
+ if (ime_text.length() == 0) {
+ CaretInfo ts_caret;
+ if (str.length() != 0) {
+ // Get carets.
+ ts_caret = TS->shaped_text_get_carets(rid, get_caret_column(c));
} else {
- ts_caret.l_dir = TextServer::DIRECTION_LTR;
- ts_caret.l_caret = Rect2(Vector2(char_ofs, -h / 2), Size2(caret_width * 4, h));
+ // No carets, add one at the start.
+ int h = font->get_height(font_size);
+ if (rtl) {
+ ts_caret.l_dir = TextServer::DIRECTION_RTL;
+ ts_caret.l_caret = Rect2(Vector2(xmargin_end - char_margin + ofs_x, -h / 2), Size2(caret_width * 4, h));
+ } else {
+ ts_caret.l_dir = TextServer::DIRECTION_LTR;
+ ts_caret.l_caret = Rect2(Vector2(char_ofs, -h / 2), Size2(caret_width * 4, h));
+ }
}
- }
- if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) {
- caret.draw_pos.x = char_margin + ofs_x + ts_caret.l_caret.position.x;
- } else {
- caret.draw_pos.x = char_margin + ofs_x + ts_caret.t_caret.position.x;
- }
+ if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) {
+ carets.write[c].draw_pos.x = char_margin + ofs_x + ts_caret.l_caret.position.x;
+ } else {
+ carets.write[c].draw_pos.x = char_margin + ofs_x + ts_caret.t_caret.position.x;
+ }
- if (caret.draw_pos.x >= xmargin_beg && caret.draw_pos.x < xmargin_end) {
- caret.visible = true;
- if (draw_caret || drag_caret_force_displayed) {
- if (caret_type == CaretType::CARET_TYPE_BLOCK || overtype_mode) {
- //Block or underline caret, draw trailing carets at full height.
- int h = font->get_height(font_size);
-
- if (ts_caret.t_caret != Rect2()) {
- if (overtype_mode) {
- ts_caret.t_caret.position.y = TS->shaped_text_get_descent(rid);
- ts_caret.t_caret.size.y = caret_width;
- } else {
- ts_caret.t_caret.position.y = -TS->shaped_text_get_ascent(rid);
- ts_caret.t_caret.size.y = h;
- }
- ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- draw_rect(ts_caret.t_caret, caret_color, overtype_mode);
+ if (get_caret_draw_pos(c).x >= xmargin_beg && get_caret_draw_pos(c).x < xmargin_end) {
+ carets.write[c].visible = true;
+ if (draw_caret || drag_caret_force_displayed) {
+ if (caret_type == CaretType::CARET_TYPE_BLOCK || overtype_mode) {
+ //Block or underline caret, draw trailing carets at full height.
+ int h = font->get_height(font_size);
- if (ts_caret.l_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
- ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- ts_caret.l_caret.size.x = caret_width;
- draw_rect(ts_caret.l_caret, caret_color * Color(1, 1, 1, 0.5));
- }
- } else { // End of the line.
- if (gl_size > 0) {
- // Adjust for actual line dimensions.
+ if (ts_caret.t_caret != Rect2()) {
if (overtype_mode) {
- ts_caret.l_caret.position.y = TS->shaped_text_get_descent(rid);
+ ts_caret.t_caret.position.y = TS->shaped_text_get_descent(rid);
+ ts_caret.t_caret.size.y = caret_width;
+ } else {
+ ts_caret.t_caret.position.y = -TS->shaped_text_get_ascent(rid);
+ ts_caret.t_caret.size.y = h;
+ }
+ ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ draw_rect(ts_caret.t_caret, caret_color, overtype_mode);
+
+ if (ts_caret.l_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
+ // Draw split caret (leading part).
+ ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ ts_caret.l_caret.size.x = caret_width;
+ draw_rect(ts_caret.l_caret, caret_color);
+ // Draw extra direction marker on top of split caret.
+ float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
+ Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
+ }
+ } else { // End of the line.
+ if (gl_size > 0) {
+ // Adjust for actual line dimensions.
+ if (overtype_mode) {
+ ts_caret.l_caret.position.y = TS->shaped_text_get_descent(rid);
+ ts_caret.l_caret.size.y = caret_width;
+ } else {
+ ts_caret.l_caret.position.y = -TS->shaped_text_get_ascent(rid);
+ ts_caret.l_caret.size.y = h;
+ }
+ } else if (overtype_mode) {
+ ts_caret.l_caret.position.y += ts_caret.l_caret.size.y;
ts_caret.l_caret.size.y = caret_width;
+ }
+ if (ts_caret.l_caret.position.x >= TS->shaped_text_get_size(rid).x) {
+ ts_caret.l_caret.size.x = font->get_char_size('m', font_size).x;
} else {
- ts_caret.l_caret.position.y = -TS->shaped_text_get_ascent(rid);
- ts_caret.l_caret.size.y = h;
+ ts_caret.l_caret.size.x = 3 * caret_width;
+ }
+ ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ if (ts_caret.l_dir == TextServer::DIRECTION_RTL) {
+ ts_caret.l_caret.position.x -= ts_caret.l_caret.size.x;
}
- } else if (overtype_mode) {
- ts_caret.l_caret.position.y += ts_caret.l_caret.size.y;
- ts_caret.l_caret.size.y = caret_width;
+ draw_rect(ts_caret.l_caret, caret_color, overtype_mode);
}
- if (ts_caret.l_caret.position.x >= TS->shaped_text_get_size(rid).x) {
- ts_caret.l_caret.size.x = font->get_char_size('m', font_size).x;
- } else {
- ts_caret.l_caret.size.x = 3 * caret_width;
+ } else {
+ // Normal caret.
+ if (ts_caret.l_caret != Rect2() && ts_caret.l_dir == TextServer::DIRECTION_AUTO) {
+ // Draw extra marker on top of mid caret.
+ Rect2 trect = Rect2(ts_caret.l_caret.position.x - 2.5 * caret_width, ts_caret.l_caret.position.y, 6 * caret_width, caret_width);
+ trect.position += Vector2(char_margin + ofs_x, ofs_y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
+ } else if (ts_caret.l_caret != Rect2() && ts_caret.t_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) {
+ // Draw extra direction marker on top of split caret.
+ float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
+ Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width);
+ trect.position += Vector2(char_margin + ofs_x, ofs_y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
+
+ d = (ts_caret.t_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3;
+ trect = Rect2(ts_caret.t_caret.position.x + d * caret_width, ts_caret.t_caret.position.y, 3 * caret_width, caret_width);
+ trect.position += Vector2(char_margin + ofs_x, ofs_y);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
}
ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- if (ts_caret.l_dir == TextServer::DIRECTION_RTL) {
- ts_caret.l_caret.position.x -= ts_caret.l_caret.size.x;
- }
- draw_rect(ts_caret.l_caret, caret_color, overtype_mode);
- }
- } else {
- // Normal caret.
- if (ts_caret.l_caret != Rect2() && ts_caret.l_dir == TextServer::DIRECTION_AUTO) {
- // Draw extra marker on top of mid caret.
- Rect2 trect = Rect2(ts_caret.l_caret.position.x - 3 * caret_width, ts_caret.l_caret.position.y, 6 * caret_width, caret_width);
- trect.position += Vector2(char_margin + ofs_x, ofs_y);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
- }
- ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- ts_caret.l_caret.size.x = caret_width;
+ ts_caret.l_caret.size.x = caret_width;
- draw_rect(ts_caret.l_caret, caret_color);
+ draw_rect(ts_caret.l_caret, caret_color);
- ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
- ts_caret.t_caret.size.x = caret_width;
+ ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y);
+ ts_caret.t_caret.size.x = caret_width;
- draw_rect(ts_caret.t_caret, caret_color);
+ draw_rect(ts_caret.t_caret, caret_color);
+ }
}
}
- }
- } else {
- {
- // IME Intermediate text range.
- Vector<Vector2> sel = TS->shaped_text_get_selection(rid, caret.column, caret.column + ime_text.length());
- for (int j = 0; j < sel.size(); j++) {
- Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
- if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
- continue;
- }
- if (rect.position.x < xmargin_beg) {
- rect.size.x -= (xmargin_beg - rect.position.x);
- rect.position.x = xmargin_beg;
- } else if (rect.position.x + rect.size.x > xmargin_end) {
- rect.size.x = xmargin_end - rect.position.x;
+ } else {
+ {
+ // IME Intermediate text range.
+ Vector<Vector2> sel = TS->shaped_text_get_selection(rid, get_caret_column(c), get_caret_column(c) + ime_text.length());
+ for (int j = 0; j < sel.size(); j++) {
+ Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
+ if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
+ continue;
+ }
+ if (rect.position.x < xmargin_beg) {
+ rect.size.x -= (xmargin_beg - rect.position.x);
+ rect.position.x = xmargin_beg;
+ } else if (rect.position.x + rect.size.x > xmargin_end) {
+ rect.size.x = xmargin_end - rect.position.x;
+ }
+ rect.size.y = caret_width;
+ draw_rect(rect, caret_color);
+ carets.write[c].draw_pos.x = rect.position.x;
}
- rect.size.y = caret_width;
- draw_rect(rect, caret_color);
- caret.draw_pos.x = rect.position.x;
}
- }
- {
- // IME caret.
- Vector<Vector2> sel = TS->shaped_text_get_selection(rid, caret.column + ime_selection.x, caret.column + ime_selection.x + ime_selection.y);
- for (int j = 0; j < sel.size(); j++) {
- Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
- if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
- continue;
- }
- if (rect.position.x < xmargin_beg) {
- rect.size.x -= (xmargin_beg - rect.position.x);
- rect.position.x = xmargin_beg;
- } else if (rect.position.x + rect.size.x > xmargin_end) {
- rect.size.x = xmargin_end - rect.position.x;
+ {
+ // IME caret.
+ Vector<Vector2> sel = TS->shaped_text_get_selection(rid, get_caret_column(c) + ime_selection.x, get_caret_column(c) + ime_selection.x + ime_selection.y);
+ for (int j = 0; j < sel.size(); j++) {
+ Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height);
+ if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) {
+ continue;
+ }
+ if (rect.position.x < xmargin_beg) {
+ rect.size.x -= (xmargin_beg - rect.position.x);
+ rect.position.x = xmargin_beg;
+ } else if (rect.position.x + rect.size.x > xmargin_end) {
+ rect.size.x = xmargin_end - rect.position.x;
+ }
+ rect.size.y = caret_width * 3;
+ draw_rect(rect, caret_color);
+ carets.write[c].draw_pos.x = rect.position.x;
}
- rect.size.y = caret_width * 3;
- draw_rect(rect, caret_color);
- caret.draw_pos.x = rect.position.x;
}
}
}
@@ -1434,7 +1467,7 @@ void TextEdit::_notification(int p_what) {
if (has_focus()) {
if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + caret.draw_pos, get_viewport()->get_window_id());
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + get_caret_draw_pos(), get_viewport()->get_window_id());
}
}
} break;
@@ -1455,13 +1488,13 @@ void TextEdit::_notification(int p_what) {
int caret_start = -1;
int caret_end = -1;
- if (!selection.active) {
- String full_text = _base_get_text(0, 0, caret.line, caret.column);
+ if (!has_selection(0)) {
+ String full_text = _base_get_text(0, 0, get_caret_line(), get_caret_column());
caret_start = full_text.length();
} else {
- String pre_text = _base_get_text(0, 0, selection.from_line, selection.from_column);
- String post_text = get_selected_text();
+ String pre_text = _base_get_text(0, 0, get_selection_from_line(), get_selection_from_column());
+ String post_text = get_selected_text(0);
caret_start = pre_text.length();
caret_end = caret_start + post_text.length();
@@ -1483,14 +1516,16 @@ void TextEdit::_notification(int p_what) {
if (!ime_text.is_empty()) {
ime_text = "";
ime_selection = Point2();
- text.invalidate_cache(caret.line, caret.column, true, ime_text);
+ for (int i = 0; i < carets.size(); i++) {
+ text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, ime_text);
+ }
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
}
- if (deselect_on_focus_loss_enabled && !selection.drag_attempt) {
+ if (deselect_on_focus_loss_enabled && !selection_drag_attempt) {
deselect();
}
} break;
@@ -1500,20 +1535,21 @@ void TextEdit::_notification(int p_what) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
- String t;
- if (caret.column >= 0) {
- t = text[caret.line].substr(0, caret.column) + ime_text + text[caret.line].substr(caret.column, text[caret.line].length());
- } else {
- t = ime_text;
+ for (int i = 0; i < carets.size(); i++) {
+ String t;
+ if (get_caret_column(i) >= 0) {
+ t = text[get_caret_line(i)].substr(0, get_caret_column(i)) + ime_text + text[get_caret_line(i)].substr(get_caret_column(i), text[get_caret_line(i)].length());
+ } else {
+ t = ime_text;
+ }
+ text.invalidate_cache(get_caret_line(i), get_caret_column(i), true, t, structured_text_parser(st_parser, st_args, t));
}
-
- text.invalidate_cache(caret.line, caret.column, true, t, structured_text_parser(st_parser, st_args, t));
queue_redraw();
}
} break;
case NOTIFICATION_DRAG_BEGIN: {
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
+ selecting_mode = SelectionMode::SELECTION_MODE_NONE;
drag_action = true;
dragging_minimap = false;
dragging_selection = false;
@@ -1523,8 +1559,8 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_DRAG_END: {
if (is_drag_successful()) {
- if (selection.drag_attempt) {
- selection.drag_attempt = false;
+ if (selection_drag_attempt) {
+ selection_drag_attempt = false;
if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
delete_selection();
} else if (deselect_on_focus_loss_enabled) {
@@ -1532,7 +1568,7 @@ void TextEdit::_notification(int p_what) {
}
}
} else {
- selection.drag_attempt = false;
+ selection_drag_attempt = false;
}
drag_action = false;
drag_caret_force_displayed = false;
@@ -1656,7 +1692,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
continue;
}
- if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) {
+ if (mpos.x >= left_margin && mpos.x <= left_margin + gutters[i].width) {
emit_signal(SNAME("gutter_clicked"), row, i);
return;
}
@@ -1672,77 +1708,103 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- int prev_col = caret.column;
- int prev_line = caret.line;
-
- set_caret_line(row, false, false);
- set_caret_column(col);
- selection.drag_attempt = false;
-
- if (selecting_enabled && mb->is_shift_pressed() && (caret.column != prev_col || caret.line != prev_line)) {
- if (!selection.active) {
- selection.active = true;
- selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
- selection.from_column = prev_col;
- selection.from_line = prev_line;
- selection.to_column = caret.column;
- selection.to_line = caret.line;
-
- if (selection.from_line > selection.to_line || (selection.from_line == selection.to_line && selection.from_column > selection.to_column)) {
- SWAP(selection.from_column, selection.to_column);
- SWAP(selection.from_line, selection.to_line);
- selection.shiftclick_left = false;
+ int caret = carets.size() - 1;
+ int prev_col = get_caret_column(caret);
+ int prev_line = get_caret_line(caret);
+
+ const int triple_click_timeout = 600;
+ const int triple_click_tolerance = 5;
+ bool is_triple_click = (!mb->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && mb->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance);
+
+ if (!is_mouse_over_selection() && !mb->is_double_click() && !is_triple_click) {
+ if (mb->is_alt_pressed()) {
+ prev_line = row;
+ prev_col = col;
+
+ caret = add_caret(row, col);
+ if (caret == -1) {
+ return;
+ }
+
+ carets.write[caret].selection.selecting_line = row;
+ carets.write[caret].selection.selecting_column = col;
+
+ last_dblclk = 0;
+ } else if (!mb->is_shift_pressed()) {
+ caret = 0;
+ remove_secondary_carets();
+ }
+ }
+
+ set_caret_line(row, false, true, 0, caret);
+ set_caret_column(col, false, caret);
+ selection_drag_attempt = false;
+
+ if (selecting_enabled && mb->is_shift_pressed() && (get_caret_column(caret) != prev_col || get_caret_line(caret) != prev_line)) {
+ if (!has_selection(caret)) {
+ carets.write[caret].selection.active = true;
+ selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
+ carets.write[caret].selection.from_column = prev_col;
+ carets.write[caret].selection.from_line = prev_line;
+ carets.write[caret].selection.to_column = carets[caret].column;
+ carets.write[caret].selection.to_line = carets[caret].line;
+
+ if (carets[caret].selection.from_line > carets[caret].selection.to_line || (carets[caret].selection.from_line == carets[caret].selection.to_line && carets[caret].selection.from_column > carets[caret].selection.to_column)) {
+ SWAP(carets.write[caret].selection.from_column, carets.write[caret].selection.to_column);
+ SWAP(carets.write[caret].selection.from_line, carets.write[caret].selection.to_line);
+ carets.write[caret].selection.shiftclick_left = false;
} else {
- selection.shiftclick_left = true;
+ carets.write[caret].selection.shiftclick_left = true;
}
- selection.selecting_line = prev_line;
- selection.selecting_column = prev_col;
+ carets.write[caret].selection.selecting_line = prev_line;
+ carets.write[caret].selection.selecting_column = prev_col;
+ caret_index_edit_dirty = true;
+ merge_overlapping_carets();
queue_redraw();
} else {
- if (caret.line < selection.selecting_line || (caret.line == selection.selecting_line && caret.column < selection.selecting_column)) {
- if (selection.shiftclick_left) {
- selection.shiftclick_left = !selection.shiftclick_left;
+ if (carets[caret].line < carets[caret].selection.selecting_line || (carets[caret].line == carets[caret].selection.selecting_line && carets[caret].column < carets[caret].selection.selecting_column)) {
+ if (carets[caret].selection.shiftclick_left) {
+ carets.write[caret].selection.shiftclick_left = !carets[caret].selection.shiftclick_left;
}
- selection.from_column = caret.column;
- selection.from_line = caret.line;
-
- } else if (caret.line > selection.selecting_line || (caret.line == selection.selecting_line && caret.column > selection.selecting_column)) {
- if (!selection.shiftclick_left) {
- SWAP(selection.from_column, selection.to_column);
- SWAP(selection.from_line, selection.to_line);
- selection.shiftclick_left = !selection.shiftclick_left;
+ carets.write[caret].selection.from_column = carets[caret].column;
+ carets.write[caret].selection.from_line = carets[caret].line;
+
+ } else if (carets[caret].line > carets[caret].selection.selecting_line || (carets[caret].line == carets[caret].selection.selecting_line && carets[caret].column > carets[caret].selection.selecting_column)) {
+ if (!carets[caret].selection.shiftclick_left) {
+ SWAP(carets.write[caret].selection.from_column, carets.write[caret].selection.to_column);
+ SWAP(carets.write[caret].selection.from_line, carets.write[caret].selection.to_line);
+ carets.write[caret].selection.shiftclick_left = !carets[caret].selection.shiftclick_left;
}
- selection.to_column = caret.column;
- selection.to_line = caret.line;
+ carets.write[caret].selection.to_column = carets[caret].column;
+ carets.write[caret].selection.to_line = carets[caret].line;
} else {
- selection.active = false;
+ deselect(caret);
}
-
+ caret_index_edit_dirty = true;
+ merge_overlapping_carets();
queue_redraw();
}
} else if (drag_and_drop_selection_enabled && is_mouse_over_selection()) {
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- selection.drag_attempt = true;
- } else {
- selection.active = false;
- selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER;
- selection.selecting_line = row;
- selection.selecting_column = col;
+ set_selection_mode(SelectionMode::SELECTION_MODE_NONE, get_selection_line(caret), get_selection_column(caret), caret);
+ // We use the main caret for dragging, so reset this one.
+ set_caret_line(prev_line, false, true, 0, caret);
+ set_caret_column(prev_col, false, caret);
+ selection_drag_attempt = true;
+ } else if (caret == 0) {
+ deselect();
+ set_selection_mode(SelectionMode::SELECTION_MODE_POINTER, row, col);
}
- const int triple_click_timeout = 600;
- const int triple_click_tolerance = 5;
-
- if (!mb->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && mb->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance) {
+ if (is_triple_click) {
// Triple-click select line.
- selection.selecting_mode = SelectionMode::SELECTION_MODE_LINE;
- selection.drag_attempt = false;
+ selecting_mode = SelectionMode::SELECTION_MODE_LINE;
+ selection_drag_attempt = false;
_update_selection_mode_line();
last_dblclk = 0;
- } else if (mb->is_double_click() && text[caret.line].length()) {
+ } else if (mb->is_double_click() && text[get_caret_line(caret)].length()) {
// Double-click select word.
- selection.selecting_mode = SelectionMode::SELECTION_MODE_WORD;
+ selecting_mode = SelectionMode::SELECTION_MODE_WORD;
_update_selection_mode_word();
last_dblclk = OS::get_singleton()->get_ticks_msec();
last_dblclk_pos = mb->get_position();
@@ -1760,23 +1822,25 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
Point2i pos = get_line_column_at_pos(mpos);
int row = pos.y;
int col = pos.x;
+ int caret = carets.size() - 1;
if (is_move_caret_on_right_click_enabled()) {
- if (has_selection()) {
- int from_line = get_selection_from_line();
- int to_line = get_selection_to_line();
- int from_column = get_selection_from_column();
- int to_column = get_selection_to_column();
+ if (has_selection(caret)) {
+ int from_line = get_selection_from_line(caret);
+ int to_line = get_selection_to_line(caret);
+ int from_column = get_selection_from_column(caret);
+ int to_column = get_selection_to_column(caret);
if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
// Right click is outside the selected text.
- deselect();
+ deselect(caret);
}
}
- if (!has_selection()) {
- set_caret_line(row, true, false);
- set_caret_column(col);
+ if (!has_selection(caret)) {
+ set_caret_line(row, true, false, 0, caret);
+ set_caret_column(col, true, caret);
}
+ merge_overlapping_carets();
}
if (context_menu_enabled) {
@@ -1789,15 +1853,15 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
} else {
if (mb->get_button_index() == MouseButton::LEFT) {
- if (selection.drag_attempt && is_mouse_over_selection()) {
- selection.active = false;
+ if (selection_drag_attempt && is_mouse_over_selection()) {
+ deselect();
}
dragging_minimap = false;
dragging_selection = false;
can_drag_minimap = false;
click_select_held->stop();
if (!drag_action) {
- selection.drag_attempt = false;
+ selection_drag_attempt = false;
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
@@ -1841,7 +1905,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (!dragging_minimap) {
- switch (selection.selecting_mode) {
+ switch (selecting_mode) {
case SelectionMode::SELECTION_MODE_POINTER: {
_update_selection_mode_pointer();
} break;
@@ -1869,7 +1933,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
continue;
}
- if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) {
+ if (mpos.x >= left_margin && mpos.x < left_margin + gutters[i].width) {
// We are in this gutter i's horizontal area.
current_hovered_gutter = Vector2i(i, hovered_row);
break;
@@ -1887,8 +1951,8 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (drag_action && can_drop_data(mpos, get_viewport()->gui_get_drag_data())) {
drag_caret_force_displayed = true;
Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
- set_caret_line(pos.y, false);
- set_caret_column(pos.x);
+ set_caret_line(pos.y, false, true, 0, 0);
+ set_caret_column(pos.x, true, 0);
dragging_selection = true;
}
}
@@ -1923,8 +1987,6 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
// * No Modifiers are pressed (except shift)
bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
- selection.selecting_text = false;
-
// Check and handle all built in shortcuts.
// NEWLINES.
@@ -1989,7 +2051,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (is_shortcut_keys_enabled()) {
- // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE.
+ // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, CUT, COPY, PASTE.
if (k->is_action("ui_text_select_all", true)) {
select_all();
accept_event();
@@ -2000,6 +2062,16 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+ if (k->is_action("ui_text_add_selection_for_next_occurrence", true)) {
+ add_selection_for_next_occurrence();
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_remove_secondary_carets", true) && _should_remove_secondary_carets()) {
+ remove_secondary_carets();
+ accept_event();
+ return;
+ }
if (k->is_action("ui_cut", true)) {
cut();
accept_event();
@@ -2027,6 +2099,17 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
accept_event();
return;
}
+
+ if (k->is_action("ui_text_caret_add_below", true)) {
+ add_caret_at_carets(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_add_above", true)) {
+ add_caret_at_carets(false);
+ accept_event();
+ return;
+ }
}
// MISC.
@@ -2130,8 +2213,17 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- // Handle Unicode (if no modifiers active). Tab has a value of 0x09.
- if (allow_unicode_handling && editable && (k->get_unicode() >= 32 || k->get_keycode() == Key::TAB)) {
+ // Handle tab as it has no set unicode value.
+ if (k->is_action("ui_text_indent", true)) {
+ if (editable) {
+ insert_text_at_caret("\t");
+ }
+ accept_event();
+ return;
+ }
+
+ // Handle Unicode (if no modifiers active).
+ if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
handle_unicode_input(k->get_unicode());
accept_event();
return;
@@ -2146,7 +2238,9 @@ void TextEdit::_swap_current_input_direction() {
} else {
input_direction = TEXT_DIRECTION_LTR;
}
- set_caret_column(caret.column);
+ for (int i = 0; i < carets.size(); i++) {
+ set_caret_column(get_caret_column(i), i == 0, i);
+ }
queue_redraw();
}
@@ -2156,325 +2250,429 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
}
begin_complex_operation();
-
- bool first_line = false;
- if (!p_split_current_line) {
- deselect();
- if (p_above) {
- if (caret.line > 0) {
- set_caret_line(caret.line - 1, false);
- set_caret_column(text[caret.line].length());
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ bool first_line = false;
+ if (!p_split_current_line) {
+ deselect(i);
+ if (p_above) {
+ if (get_caret_line(i) > 0) {
+ set_caret_line(get_caret_line(i) - 1, false, true, 0, i);
+ set_caret_column(text[get_caret_line(i)].length(), i == 0, i);
+ } else {
+ set_caret_column(0, i == 0, i);
+ first_line = true;
+ }
} else {
- set_caret_column(0);
- first_line = true;
+ set_caret_column(text[get_caret_line(i)].length(), i == 0, i);
}
- } else {
- set_caret_column(text[caret.line].length());
}
- }
- insert_text_at_caret("\n");
+ insert_text_at_caret("\n", i);
- if (first_line) {
- set_caret_line(0);
+ if (first_line) {
+ set_caret_line(0, i == 0, true, 0, i);
+ }
}
-
end_complex_operation();
}
void TextEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
- // Handle selection
- if (p_select) {
- _pre_shift_selection();
- } else if (selection.active && !p_move_by_word) {
- // If a selection is active, move caret to start of selection
- set_caret_line(selection.from_line);
- set_caret_column(selection.from_column);
- deselect();
- return;
- } else {
- deselect();
- }
-
- if (p_move_by_word) {
- int cc = caret.column;
- // If the caret is at the start of the line, and not on the first line, move it up to the end of the previous line.
- if (cc == 0 && caret.line > 0) {
- set_caret_line(caret.line - 1);
- set_caret_column(text[caret.line].length());
+ for (int i = 0; i < carets.size(); i++) {
+ // Handle selection.
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else if (has_selection(i) && !p_move_by_word) {
+ // If a selection is active, move caret to start of selection.
+ set_caret_line(get_selection_from_line(i), false, true, 0, i);
+ set_caret_column(get_selection_from_column(i), i == 0, i);
+ deselect(i);
+ continue;
} else {
- PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- if (words.is_empty() || cc <= words[0]) {
- // This solves the scenario where there are no words but glyfs that can be ignored.
- cc = 0;
+ deselect(i);
+ }
+
+ if (p_move_by_word) {
+ int cc = get_caret_column(i);
+ // If the caret is at the start of the line, and not on the first line, move it up to the end of the previous line.
+ if (cc == 0 && get_caret_line(i) > 0) {
+ set_caret_line(get_caret_line(i) - 1, false, true, 0, i);
+ set_caret_column(text[get_caret_line(i)].length(), i == 0, i);
} else {
- for (int i = words.size() - 2; i >= 0; i = i - 2) {
- if (words[i] < cc) {
- cc = words[i];
- break;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(i))->get_rid());
+ if (words.is_empty() || cc <= words[0]) {
+ // This solves the scenario where there are no words but glyfs that can be ignored.
+ cc = 0;
+ } else {
+ for (int j = words.size() - 2; j >= 0; j = j - 2) {
+ if (words[j] < cc) {
+ cc = words[j];
+ break;
+ }
}
}
- }
- set_caret_column(cc);
- }
- } else {
- // If the caret is at the start of the line, and not on the first line, move it up to the end of the previous line.
- if (caret.column == 0) {
- if (caret.line > 0) {
- set_caret_line(caret.line - get_next_visible_line_offset_from(CLAMP(caret.line - 1, 0, text.size() - 1), -1));
- set_caret_column(text[caret.line].length());
+ set_caret_column(cc, i == 0, i);
}
} else {
- if (caret_mid_grapheme_enabled) {
- set_caret_column(get_caret_column() - 1);
+ // If the caret is at the start of the line, and not on the first line, move it up to the end of the previous line.
+ if (get_caret_column(i) == 0) {
+ if (get_caret_line(i) > 0) {
+ set_caret_line(get_caret_line(i) - get_next_visible_line_offset_from(CLAMP(get_caret_line(i) - 1, 0, text.size() - 1), -1), false, true, 0, i);
+ set_caret_column(text[get_caret_line(i)].length(), i == 0, i);
+ }
} else {
- set_caret_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(caret.line)->get_rid(), get_caret_column()));
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column(i) - 1, i == 0, i);
+ } else {
+ set_caret_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(get_caret_line(i))->get_rid(), get_caret_column(i)), i == 0, i);
+ }
}
}
- }
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
- // Handle selection
- if (p_select) {
- _pre_shift_selection();
- } else if (selection.active && !p_move_by_word) {
- // If a selection is active, move caret to end of selection
- set_caret_line(selection.to_line);
- set_caret_column(selection.to_column);
- deselect();
- return;
- } else {
- deselect();
- }
-
- if (p_move_by_word) {
- int cc = caret.column;
- // If the caret is at the end of the line, and not on the last line, move it down to the beginning of the next line.
- if (cc == text[caret.line].length() && caret.line < text.size() - 1) {
- set_caret_line(caret.line + 1);
- set_caret_column(0);
+ for (int i = 0; i < carets.size(); i++) {
+ // Handle selection
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else if (has_selection(i) && !p_move_by_word) {
+ // If a selection is active, move caret to end of selection
+ set_caret_line(get_selection_to_line(i), false, true, 0, i);
+ set_caret_column(get_selection_to_column(i), i == 0, i);
+ deselect(i);
+ continue;
} else {
- PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- if (words.is_empty() || cc >= words[words.size() - 1]) {
- // This solves the scenario where there are no words but glyfs that can be ignored.
- cc = text[caret.line].length();
+ deselect(i);
+ }
+
+ if (p_move_by_word) {
+ int cc = get_caret_column(i);
+ // If the caret is at the end of the line, and not on the last line, move it down to the beginning of the next line.
+ if (cc == text[get_caret_line(i)].length() && get_caret_line(i) < text.size() - 1) {
+ set_caret_line(get_caret_line(i) + 1, false, true, 0, i);
+ set_caret_column(0, i == 0, i);
} else {
- for (int i = 1; i < words.size(); i = i + 2) {
- if (words[i] > cc) {
- cc = words[i];
- break;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(i))->get_rid());
+ if (words.is_empty() || cc >= words[words.size() - 1]) {
+ // This solves the scenario where there are no words but glyfs that can be ignored.
+ cc = text[get_caret_line(i)].length();
+ } else {
+ for (int j = 1; j < words.size(); j = j + 2) {
+ if (words[j] > cc) {
+ cc = words[j];
+ break;
+ }
}
}
- }
- set_caret_column(cc);
- }
- } else {
- // If we are at the end of the line, move the caret to the next line down.
- if (caret.column == text[caret.line].length()) {
- if (caret.line < text.size() - 1) {
- set_caret_line(get_caret_line() + get_next_visible_line_offset_from(CLAMP(caret.line + 1, 0, text.size() - 1), 1), true, false);
- set_caret_column(0);
+ set_caret_column(cc, i == 0, i);
}
} else {
- if (caret_mid_grapheme_enabled) {
- set_caret_column(get_caret_column() + 1);
+ // If we are at the end of the line, move the caret to the next line down.
+ if (get_caret_column(i) == text[get_caret_line(i)].length()) {
+ if (get_caret_line(i) < text.size() - 1) {
+ set_caret_line(get_caret_line(i) + get_next_visible_line_offset_from(CLAMP(get_caret_line(i) + 1, 0, text.size() - 1), 1), false, false, 0, i);
+ set_caret_column(0, i == 0, i);
+ }
} else {
- set_caret_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(caret.line)->get_rid(), get_caret_column()));
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column(i) + 1, i == 0, i);
+ } else {
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(get_caret_line(i))->get_rid(), get_caret_column(i)), i == 0, i);
+ }
}
}
- }
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_up(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- int cur_wrap_index = get_caret_wrap_index();
- if (cur_wrap_index > 0) {
- set_caret_line(caret.line, true, false, cur_wrap_index - 1);
- } else if (caret.line == 0) {
- set_caret_column(0);
- } else {
- int new_line = caret.line - get_next_visible_line_offset_from(caret.line - 1, -1);
- if (is_line_wrapped(new_line)) {
- set_caret_line(new_line, true, false, get_line_wrap_count(new_line));
+ int cur_wrap_index = get_caret_wrap_index(i);
+ if (cur_wrap_index > 0) {
+ set_caret_line(get_caret_line(i), true, false, cur_wrap_index - 1, i);
+ } else if (get_caret_line(i) == 0) {
+ set_caret_column(0, i == 0, i);
} else {
- set_caret_line(new_line, true, false);
+ int new_line = get_caret_line(i) - get_next_visible_line_offset_from(get_caret_line(i) - 1, -1);
+ if (is_line_wrapped(new_line)) {
+ set_caret_line(new_line, i == 0, false, get_line_wrap_count(new_line), i);
+ } else {
+ set_caret_line(new_line, i == 0, false, 0, i);
+ }
}
- }
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_down(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- int cur_wrap_index = get_caret_wrap_index();
- if (cur_wrap_index < get_line_wrap_count(caret.line)) {
- set_caret_line(caret.line, true, false, cur_wrap_index + 1);
- } else if (caret.line == get_last_unhidden_line()) {
- set_caret_column(text[caret.line].length());
- } else {
- int new_line = caret.line + get_next_visible_line_offset_from(CLAMP(caret.line + 1, 0, text.size() - 1), 1);
- set_caret_line(new_line, true, false, 0);
- }
+ int cur_wrap_index = get_caret_wrap_index(i);
+ if (cur_wrap_index < get_line_wrap_count(get_caret_line(i))) {
+ set_caret_line(get_caret_line(i), i == 0, false, cur_wrap_index + 1, i);
+ } else if (get_caret_line(i) == get_last_unhidden_line()) {
+ set_caret_column(text[get_caret_line(i)].length());
+ } else {
+ int new_line = get_caret_line(i) + get_next_visible_line_offset_from(CLAMP(get_caret_line(i) + 1, 0, text.size() - 1), 1);
+ set_caret_line(new_line, i == 0, false, 0, i);
+ }
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_to_line_start(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- // Move caret column to start of wrapped row and then to start of text.
- Vector<String> rows = get_line_wrapped_text(caret.line);
- int wi = get_caret_wrap_index();
- int row_start_col = 0;
- for (int i = 0; i < wi; i++) {
- row_start_col += rows[i].length();
- }
- if (caret.column == row_start_col || wi == 0) {
- // Compute whitespace symbols sequence length.
- int current_line_whitespace_len = get_first_non_whitespace_column(caret.line);
- if (get_caret_column() == current_line_whitespace_len) {
- set_caret_column(0);
+ // Move caret column to start of wrapped row and then to start of text.
+ Vector<String> rows = get_line_wrapped_text(get_caret_line(i));
+ int wi = get_caret_wrap_index(i);
+ int row_start_col = 0;
+ for (int j = 0; j < wi; j++) {
+ row_start_col += rows[j].length();
+ }
+ if (get_caret_column(i) == row_start_col || wi == 0) {
+ // Compute whitespace symbols sequence length.
+ int current_line_whitespace_len = get_first_non_whitespace_column(get_caret_line(i));
+ if (get_caret_column(i) == current_line_whitespace_len) {
+ set_caret_column(0, i == 0, i);
+ } else {
+ set_caret_column(current_line_whitespace_len, i == 0, i);
+ }
} else {
- set_caret_column(current_line_whitespace_len);
+ set_caret_column(row_start_col, i == 0, i);
}
- } else {
- set_caret_column(row_start_col);
- }
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_to_line_end(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- // Move caret column to end of wrapped row and then to end of text.
- Vector<String> rows = get_line_wrapped_text(caret.line);
- int wi = get_caret_wrap_index();
- int row_end_col = -1;
- for (int i = 0; i < wi + 1; i++) {
- row_end_col += rows[i].length();
- }
- if (wi == rows.size() - 1 || caret.column == row_end_col) {
- set_caret_column(text[caret.line].length());
- } else {
- set_caret_column(row_end_col);
- }
+ // Move caret column to end of wrapped row and then to end of text.
+ Vector<String> rows = get_line_wrapped_text(get_caret_line(i));
+ int wi = get_caret_wrap_index(i);
+ int row_end_col = -1;
+ for (int j = 0; j < wi + 1; j++) {
+ row_end_col += rows[j].length();
+ }
+ if (wi == rows.size() - 1 || get_caret_column(i) == row_end_col) {
+ set_caret_column(text[get_caret_line(i)].length(), i == 0, i);
+ } else {
+ set_caret_column(row_end_col, i == 0, i);
+ }
- if (p_select) {
- _post_shift_selection();
+ carets.write[i].last_fit_x = INT_MAX;
+
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_page_up(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- Point2i next_line = get_next_visible_line_index_offset_from(caret.line, get_caret_wrap_index(), -get_visible_line_count());
- int n_line = caret.line - next_line.x + 1;
- set_caret_line(n_line, true, false, next_line.y);
+ Point2i next_line = get_next_visible_line_index_offset_from(get_caret_line(i), get_caret_wrap_index(i), -get_visible_line_count());
+ int n_line = get_caret_line(i) - next_line.x + 1;
+ set_caret_line(n_line, i == 0, false, next_line.y, i);
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_move_caret_page_down(bool p_select) {
- if (p_select) {
- _pre_shift_selection();
- } else {
- deselect();
- }
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_select) {
+ _pre_shift_selection(i);
+ } else {
+ deselect(i);
+ }
- Point2i next_line = get_next_visible_line_index_offset_from(caret.line, get_caret_wrap_index(), get_visible_line_count());
- int n_line = caret.line + next_line.x - 1;
- set_caret_line(n_line, true, false, next_line.y);
+ Point2i next_line = get_next_visible_line_index_offset_from(get_caret_line(i), get_caret_wrap_index(i), get_visible_line_count());
+ int n_line = get_caret_line(i) + next_line.x - 1;
+ set_caret_line(n_line, i == 0, false, next_line.y, i);
- if (p_select) {
- _post_shift_selection();
+ if (p_select) {
+ _post_shift_selection(i);
+ }
}
+ merge_overlapping_carets();
}
void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
- if (!editable || (caret.column == 0 && caret.line == 0 && !has_selection())) {
+ if (!editable) {
return;
}
- if (has_selection() || (!p_all_to_left && !p_word) || caret.column == 0) {
- backspace();
- return;
- }
+ start_action(EditAction::ACTION_BACKSPACE);
+ Vector<int> carets_to_remove;
- if (p_all_to_left) {
- int caret_current_column = caret.column;
- set_caret_column(0);
- _remove_text(caret.line, 0, caret.line, caret_current_column);
- return;
- }
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size(); i++) {
+ int caret_idx = caret_edit_order[i];
+ if (get_caret_column(caret_idx) == 0 && get_caret_line(caret_idx) == 0 && !has_selection(caret_idx)) {
+ continue;
+ }
- if (p_word) {
- int column = caret.column;
- // Check for the case "<word><space><caret>" and ignore the space.
- // No need to check for column being 0 since it is checked above.
- if (is_whitespace(text[caret.line][caret.column - 1])) {
- column -= 1;
+ if (has_selection(caret_idx) || (!p_all_to_left && !p_word) || get_caret_column(caret_idx) == 0) {
+ backspace(caret_idx);
+ continue;
}
- // Get a list with the indices of the word bounds of the given text line.
- const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- if (words.is_empty() || column <= words[0]) {
- // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line.
- column = 0;
- } else {
- // Otherwise search for the first word break that is smaller than the index from which we're currently deleting.
- for (int i = words.size() - 2; i >= 0; i = i - 2) {
- if (words[i] < column) {
- column = words[i];
+
+ if (p_all_to_left) {
+ int caret_current_column = get_caret_column(caret_idx);
+ set_caret_column(0, caret_idx == 0, caret_idx);
+ _remove_text(get_caret_line(caret_idx), 0, get_caret_line(caret_idx), caret_current_column);
+ adjust_carets_after_edit(caret_idx, get_caret_line(caret_idx), caret_current_column, get_caret_line(caret_idx), get_caret_column(caret_idx));
+
+ // Check for any overlapping carets since we removed the entire line.
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ // Selection only end on this line, only the one as carets cannot overlap.
+ if (has_selection(caret_edit_order[j]) && get_selection_from_line(caret_edit_order[j]) != get_caret_line(caret_idx) && get_selection_to_line(caret_edit_order[j]) == get_caret_line(caret_idx)) {
+ carets.write[caret_edit_order[j]].selection.to_column = 0;
+ break;
+ }
+
+ // Check for caret.
+ if (get_caret_line(caret_edit_order[j]) != get_caret_line(caret_idx) || (has_selection(caret_edit_order[j]) && get_selection_from_line(caret_edit_order[j]) != get_caret_line(caret_idx))) {
break;
}
+
+ deselect(caret_edit_order[j]);
+ carets_to_remove.push_back(caret_edit_order[j]);
+ set_caret_column(0, caret_idx == 0, caret_idx);
+ i = j;
}
+ continue;
}
- _remove_text(caret.line, column, caret.line, caret.column);
+ if (p_word) {
+ // Save here as the caret may change when resolving overlaps.
+ int from_column = get_caret_column(caret_idx);
+ int column = get_caret_column(caret_idx);
+ // Check for the case "<word><space><caret>" and ignore the space.
+ // No need to check for column being 0 since it is checked above.
+ if (is_whitespace(text[get_caret_line(caret_idx)][get_caret_column(caret_idx) - 1])) {
+ column -= 1;
+ }
+ // Get a list with the indices of the word bounds of the given text line.
+ const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(caret_idx))->get_rid());
+ if (words.is_empty() || column <= words[0]) {
+ // If "words" is empty, meaning no words are left, we can remove everything until the beginning of the line.
+ column = 0;
+ } else {
+ // Otherwise search for the first word break that is smaller than the index from we're currently deleting.
+ for (int c = words.size() - 2; c >= 0; c = c - 2) {
+ if (words[c] < column) {
+ column = words[c];
+ break;
+ }
+ }
+ }
+
+ // Check for any other carets in this range.
+ int overlapping_caret_index = -1;
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ // Check caret and selection in on the right line.
+ if (get_caret_line(caret_edit_order[j]) != get_caret_line(caret_idx) && (!has_selection(caret_edit_order[j]) || get_selection_to_line(caret_edit_order[j]) != get_caret_line(caret_idx))) {
+ break;
+ }
+
+ // If it has a selection, check it ends with in the range.
+ if ((has_selection(caret_edit_order[j]) && get_selection_to_column(caret_edit_order[j]) < column)) {
+ break;
+ }
- set_caret_line(caret.line, false);
- set_caret_column(column);
- return;
+ // If it has a selection and it starts outside our word, we need to adjust the selection, and handle it later to prevent overlap.
+ if ((has_selection(caret_edit_order[j]) && get_selection_from_column(caret_edit_order[j]) < column)) {
+ carets.write[caret_edit_order[j]].selection.to_column = column;
+ overlapping_caret_index = caret_edit_order[j];
+ break;
+ }
+
+ // Otherwise we can remove it.
+ if (get_caret_column(caret_edit_order[j]) > column || (has_selection(caret_edit_order[j]) && get_selection_from_column(caret_edit_order[j]) > column)) {
+ deselect(caret_edit_order[j]);
+ carets_to_remove.push_back(caret_edit_order[j]);
+ set_caret_column(0, caret_idx == 0, caret_idx);
+ i = j;
+ }
+ }
+
+ _remove_text(get_caret_line(caret_idx), column, get_caret_line(caret_idx), from_column);
+
+ set_caret_line(get_caret_line(caret_idx), false, true, 0, caret_idx);
+ set_caret_column(column, caret_idx == 0, caret_idx);
+
+ // Now we can clean up the overlaping caret.
+ if (overlapping_caret_index != -1) {
+ backspace(overlapping_caret_index);
+ i++;
+ carets_to_remove.push_back(overlapping_caret_index);
+ set_caret_column(get_caret_column(overlapping_caret_index), caret_idx == 0, caret_idx);
+ }
+ continue;
+ }
+ }
+
+ // Sort and remove backwards to preserve indexes.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ remove_caret(carets_to_remove[i]);
}
+ end_action();
}
void TextEdit::_delete(bool p_word, bool p_all_to_right) {
@@ -2482,82 +2680,196 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
return;
}
- if (has_selection()) {
- delete_selection();
- return;
- }
- int curline_len = text[caret.line].length();
-
- if (caret.line == text.size() - 1 && caret.column == curline_len) {
- return; // Last line, last column: Nothing to do.
- }
+ start_action(EditAction::ACTION_DELETE);
+ Vector<int> carets_to_remove;
- int next_line = caret.column < curline_len ? caret.line : caret.line + 1;
- int next_column;
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size(); i++) {
+ int caret_idx = caret_edit_order[i];
+ if (has_selection(caret_idx)) {
+ delete_selection(caret_idx);
+ continue;
+ }
+ int curline_len = text[get_caret_line(caret_idx)].length();
- if (p_all_to_right) {
- if (caret.column == curline_len) {
- return;
+ if (get_caret_line(caret_idx) == text.size() - 1 && get_caret_column(caret_idx) == curline_len) {
+ continue; // Last line, last column: Nothing to do.
}
- // Delete everything to right of caret
- next_column = curline_len;
- next_line = caret.line;
- } else if (p_word && caret.column < curline_len - 1) {
- // Delete next word to right of caret
- int line = caret.line;
- int column = caret.column;
+ int next_line = get_caret_column(caret_idx) < curline_len ? get_caret_line(caret_idx) : get_caret_line(caret_idx) + 1;
+ int next_column;
- PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
- for (int i = 1; i < words.size(); i = i + 2) {
- if (words[i] > column) {
- column = words[i];
- break;
+ if (p_all_to_right) {
+ // Get caret furthest to the left
+ for (int j = i + 1; j < caret_edit_order.size(); j++) {
+ if (get_caret_line(caret_edit_order[j]) != get_caret_line(caret_idx)) {
+ break;
+ }
+
+ if (has_selection(caret_edit_order[j]) && get_selection_from_line(caret_edit_order[j]) != get_caret_line(caret_idx)) {
+ break;
+ }
+
+ if (!has_selection(caret_edit_order[j])) {
+ i = j;
+ caret_idx = caret_edit_order[i];
+ }
}
- }
- next_line = line;
- next_column = column;
- } else {
- // Delete one character
- if (caret_mid_grapheme_enabled) {
- next_column = caret.column < curline_len ? (caret.column + 1) : 0;
+ if (get_caret_column(caret_idx) == curline_len) {
+ continue;
+ }
+
+ // Delete everything to right of caret
+ next_column = curline_len;
+ next_line = get_caret_line(caret_idx);
+
+ // Remove overlapping carets.
+ for (int j = i - 1; j >= 0; j--) {
+ if (get_caret_line(caret_edit_order[j]) != get_caret_line(caret_idx)) {
+ break;
+ }
+ carets_to_remove.push_back(caret_edit_order[j]);
+ }
+
+ } else if (p_word && get_caret_column(caret_idx) < curline_len - 1) {
+ // Delete next word to right of caret
+ int line = get_caret_line(caret_idx);
+ int column = get_caret_column(caret_idx);
+
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid());
+ for (int j = 1; j < words.size(); j = j + 2) {
+ if (words[j] > column) {
+ column = words[j];
+ break;
+ }
+ }
+
+ next_line = line;
+ next_column = column;
+
+ // Remove overlapping carets.
+ for (int j = i - 1; j >= 0; j--) {
+ if (get_caret_line(caret_edit_order[j]) != get_caret_line(caret_idx)) {
+ break;
+ }
+
+ if (get_caret_column(caret_edit_order[j]) > column) {
+ break;
+ }
+ carets_to_remove.push_back(caret_edit_order[j]);
+ }
} else {
- next_column = caret.column < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(caret.line)->get_rid(), (caret.column)) : 0;
+ // Delete one character
+ if (caret_mid_grapheme_enabled) {
+ next_column = get_caret_column(caret_idx) < curline_len ? (get_caret_column(caret_idx) + 1) : 0;
+ } else {
+ next_column = get_caret_column(caret_idx) < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(get_caret_line(caret_idx))->get_rid(), (get_caret_column(caret_idx))) : 0;
+ }
+
+ // Remove overlapping carets.
+ if (i > 0) {
+ int prev_caret_idx = caret_edit_order[i - 1];
+ if (get_caret_line(prev_caret_idx) == next_line && get_caret_column(prev_caret_idx) == next_column) {
+ carets_to_remove.push_back(prev_caret_idx);
+ }
+ }
}
+
+ _remove_text(get_caret_line(caret_idx), get_caret_column(caret_idx), next_line, next_column);
+ adjust_carets_after_edit(caret_idx, get_caret_line(caret_idx), get_caret_column(caret_idx), next_line, next_column);
+ }
+
+ // Sort and remove backwards to preserve indexes.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ remove_caret(carets_to_remove[i]);
}
- _remove_text(caret.line, caret.column, next_line, next_column);
+ // If we are deleting from the end of a line, due to column preservation we could still overlap with another caret.
+ merge_overlapping_carets();
+ end_action();
queue_redraw();
}
void TextEdit::_move_caret_document_start(bool p_select) {
+ remove_secondary_carets();
if (p_select) {
- _pre_shift_selection();
+ _pre_shift_selection(0);
} else {
deselect();
}
- set_caret_line(0);
+ set_caret_line(0, false);
set_caret_column(0);
if (p_select) {
- _post_shift_selection();
+ _post_shift_selection(0);
}
}
void TextEdit::_move_caret_document_end(bool p_select) {
+ remove_secondary_carets();
if (p_select) {
- _pre_shift_selection();
+ _pre_shift_selection(0);
} else {
deselect();
}
set_caret_line(get_last_unhidden_line(), true, false, 9999);
- set_caret_column(text[caret.line].length());
+ set_caret_column(text[get_caret_line()].length());
if (p_select) {
- _post_shift_selection();
+ _post_shift_selection(0);
+ }
+}
+
+bool TextEdit::_should_remove_secondary_carets() {
+ return carets.size() > 1;
+}
+
+void TextEdit::_get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x) const {
+ if (p_last_fit_x == -1) {
+ p_last_fit_x = _get_column_x_offset_for_line(p_old_column, p_old_line, p_old_column);
+ }
+
+ // Calculate the new line and wrap index
+ p_new_line = p_old_line;
+ int caret_wrap_index = p_old_wrap_index;
+ if (p_below) {
+ if (caret_wrap_index < get_line_wrap_count(p_new_line)) {
+ caret_wrap_index++;
+ } else {
+ p_new_line++;
+ caret_wrap_index = 0;
+ }
+ } else {
+ if (caret_wrap_index == 0) {
+ p_new_line--;
+ caret_wrap_index = get_line_wrap_count(p_new_line);
+ } else {
+ caret_wrap_index--;
+ }
+ }
+
+ // Boundary checks
+ if (p_new_line < 0) {
+ p_new_line = 0;
+ }
+ if (p_new_line >= text.size()) {
+ p_new_line = text.size() - 1;
+ }
+
+ p_new_column = _get_char_pos_for_line(p_last_fit_x, p_new_line, caret_wrap_index);
+ if (p_new_column != 0 && get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && caret_wrap_index < get_line_wrap_count(p_new_line)) {
+ Vector<String> rows = get_line_wrapped_text(p_new_line);
+ int row_end_col = 0;
+ for (int i = 0; i < caret_wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (p_new_column >= row_end_col) {
+ p_new_column -= 1;
+ }
}
}
@@ -2619,6 +2931,7 @@ void TextEdit::_update_caches() {
/* Selection */
font_selected_color = get_theme_color(SNAME("font_selected_color"));
selection_color = get_theme_color(SNAME("selection_color"));
+ use_selected_font_color = font_selected_color != Color(0, 0, 0, 0);
/* Visual. */
style_normal = get_theme_stylebox(SNAME("normal"));
@@ -2677,7 +2990,7 @@ bool TextEdit::is_text_field() const {
}
Variant TextEdit::get_drag_data(const Point2 &p_point) {
- if (selection.active && selection.drag_attempt) {
+ if (has_selection() && selection_drag_attempt) {
String t = get_selected_text();
Label *l = memnew(Label);
l->set_text(t);
@@ -2704,34 +3017,41 @@ void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
int caret_row_tmp = pos.y;
int caret_column_tmp = pos.x;
- if (selection.drag_attempt) {
- selection.drag_attempt = false;
+ if (selection_drag_attempt) {
+ selection_drag_attempt = false;
if (!is_mouse_over_selection(!Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ // Set caret back at selection for undo / redo.
+ set_caret_line(get_selection_to_line(), false, false);
+ set_caret_column(get_selection_to_column());
+
begin_complex_operation();
if (!Input::get_singleton()->is_key_pressed(Key::CTRL)) {
- if (caret_row_tmp > selection.to_line) {
- caret_row_tmp = caret_row_tmp - (selection.to_line - selection.from_line);
- } else if (caret_row_tmp == selection.to_line && caret_column_tmp >= selection.to_column) {
- caret_column_tmp = caret_column_tmp - (selection.to_column - selection.from_column);
+ if (caret_row_tmp > get_selection_to_line()) {
+ caret_row_tmp = caret_row_tmp - (get_selection_to_line() - get_selection_from_line());
+ } else if (caret_row_tmp == get_selection_to_line() && caret_column_tmp >= get_selection_to_column()) {
+ caret_column_tmp = caret_column_tmp - (get_selection_to_column() - get_selection_from_column());
}
delete_selection();
} else {
deselect();
}
+ remove_secondary_carets();
set_caret_line(caret_row_tmp, true, false);
set_caret_column(caret_column_tmp);
insert_text_at_caret(p_data);
end_complex_operation();
}
} else if (is_mouse_over_selection()) {
- caret_row_tmp = selection.from_line;
- caret_column_tmp = selection.from_column;
+ remove_secondary_carets();
+ caret_row_tmp = get_selection_from_line();
+ caret_column_tmp = get_selection_from_column();
set_caret_line(caret_row_tmp, true, false);
set_caret_column(caret_column_tmp);
insert_text_at_caret(p_data);
grab_focus();
} else {
+ remove_secondary_carets();
deselect();
set_caret_line(caret_row_tmp, true, false);
set_caret_column(caret_column_tmp);
@@ -2739,8 +3059,8 @@ void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
grab_focus();
}
- if (caret_row_tmp != caret.line || caret_column_tmp != caret.column) {
- select(caret_row_tmp, caret_column_tmp, caret.line, caret.column);
+ if (caret_row_tmp != get_caret_line() || caret_column_tmp != get_caret_column()) {
+ select(caret_row_tmp, caret_column_tmp, get_caret_line(), get_caret_column());
}
}
}
@@ -2757,7 +3077,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
continue;
}
- if (p_pos.x > left_margin && p_pos.x <= (left_margin + gutters[i].width) - 3) {
+ if (p_pos.x >= left_margin && p_pos.x < left_margin + gutters[i].width) {
if (gutters[i].clickable || is_line_gutter_clickable(row, i)) {
return CURSOR_POINTING_HAND;
}
@@ -2976,6 +3296,7 @@ void TextEdit::clear() {
void TextEdit::_clear() {
if (editable && undo_enabled) {
+ remove_secondary_carets();
_move_caret_document_start(false);
begin_complex_operation();
@@ -2991,13 +3312,14 @@ void TextEdit::_clear() {
clear_undo_history();
text.clear();
+ remove_secondary_carets();
set_caret_line(0, false);
set_caret_column(0);
- caret.x_ofs = 0;
- caret.line_ofs = 0;
- caret.wrap_ofs = 0;
- caret.last_fit_x = 0;
- selection.active = false;
+ first_visible_col = 0;
+ first_visible_line = 0;
+ first_visible_line_wrap_ofs = 0;
+ carets.write[0].last_fit_x = 0;
+ deselect();
emit_signal(SNAME("lines_edited_from"), old_text_size, 0);
}
@@ -3010,6 +3332,7 @@ void TextEdit::set_text(const String &p_text) {
}
if (undo_enabled) {
+ remove_secondary_carets();
set_caret_line(0);
set_caret_column(0);
@@ -3065,11 +3388,14 @@ void TextEdit::set_line(int p_line, const String &p_new_text) {
begin_complex_operation();
_remove_text(p_line, 0, p_line, text[p_line].length());
_insert_text(p_line, 0, p_new_text);
- if (caret.line == p_line && caret.column > p_new_text.length()) {
- set_caret_column(p_new_text.length(), false);
- }
- if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) {
- selection.to_column = text[p_line].length();
+ for (int i = 0; i < carets.size(); i++) {
+ if (get_caret_line(i) == p_line && get_caret_column(i) > p_new_text.length()) {
+ set_caret_column(p_new_text.length(), false, i);
+ }
+
+ if (has_selection(i) && p_line == get_selection_to_line(i) && get_selection_to_column(i) > text[p_line].length()) {
+ carets.write[i].selection.to_column = text[p_line].length();
+ }
}
end_complex_operation();
}
@@ -3136,42 +3462,54 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) {
ERR_FAIL_INDEX(p_at, text.size());
_insert_text(p_at, 0, p_text + "\n");
- if (caret.line >= p_at) {
- // offset caret when located after inserted line
- set_caret_line(caret.line + 1, false);
- }
- if (has_selection()) {
- if (selection.from_line >= p_at) {
- // offset selection when located after inserted line
- ++selection.from_line;
- ++selection.to_line;
- } else if (selection.to_line >= p_at) {
- // extend selection that includes inserted line
- ++selection.to_line;
+
+ for (int i = 0; i < carets.size(); i++) {
+ if (get_caret_line(i) >= p_at) {
+ // offset caret when located after inserted line
+ set_caret_line(get_caret_line(i) + 1, false, true, 0, i);
+ }
+ if (has_selection(i)) {
+ if (get_selection_from_line(i) >= p_at) {
+ // offset selection when located after inserted line
+ select(get_selection_from_line(i) + 1, get_selection_from_column(i), get_selection_to_line(i) + 1, get_selection_to_column(i), i);
+ } else if (get_selection_to_line(i) >= p_at) {
+ // extend selection that includes inserted line
+ select(get_selection_from_line(i), get_selection_from_column(i), get_selection_to_line(i) + 1, get_selection_to_column(i), i);
+ }
}
}
+
+ // Need to apply the above adjustments to the undo / redo carets.
+ current_op.end_carets = carets;
queue_redraw();
}
-void TextEdit::insert_text_at_caret(const String &p_text) {
- bool had_selection = has_selection();
- if (had_selection) {
- begin_complex_operation();
- }
+void TextEdit::insert_text_at_caret(const String &p_text, int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
- delete_selection();
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
- int new_column, new_line;
- _insert_text(caret.line, caret.column, p_text, &new_line, &new_column);
- _update_scrollbars();
+ delete_selection(i);
- set_caret_line(new_line, false);
- set_caret_column(new_column);
- queue_redraw();
+ int from_line = get_caret_line(i);
+ int from_col = get_caret_column(i);
- if (had_selection) {
- end_complex_operation();
+ int new_column, new_line;
+ _insert_text(from_line, from_col, p_text, &new_line, &new_column);
+ _update_scrollbars();
+
+ set_caret_line(new_line, false, true, 0, i);
+ set_caret_column(new_column, i == 0, i);
+
+ adjust_carets_after_edit(i, new_line, new_column, from_line, from_col);
}
+ end_complex_operation();
+ queue_redraw();
}
void TextEdit::remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
@@ -3295,46 +3633,46 @@ Point2i TextEdit::get_next_visible_line_index_offset_from(int p_line_from, int p
}
// Overridable actions
-void TextEdit::handle_unicode_input(const uint32_t p_unicode) {
- if (GDVIRTUAL_CALL(_handle_unicode_input, p_unicode)) {
+void TextEdit::handle_unicode_input(const uint32_t p_unicode, int p_caret) {
+ if (GDVIRTUAL_CALL(_handle_unicode_input, p_unicode, p_caret)) {
return;
}
- _handle_unicode_input_internal(p_unicode);
+ _handle_unicode_input_internal(p_unicode, p_caret);
}
-void TextEdit::backspace() {
- if (GDVIRTUAL_CALL(_backspace)) {
+void TextEdit::backspace(int p_caret) {
+ if (GDVIRTUAL_CALL(_backspace, p_caret)) {
return;
}
- _backspace_internal();
+ _backspace_internal(p_caret);
}
-void TextEdit::cut() {
- if (GDVIRTUAL_CALL(_cut)) {
+void TextEdit::cut(int p_caret) {
+ if (GDVIRTUAL_CALL(_cut, p_caret)) {
return;
}
- _cut_internal();
+ _cut_internal(p_caret);
}
-void TextEdit::copy() {
- if (GDVIRTUAL_CALL(_copy)) {
+void TextEdit::copy(int p_caret) {
+ if (GDVIRTUAL_CALL(_copy, p_caret)) {
return;
}
- _copy_internal();
+ _copy_internal(p_caret);
}
-void TextEdit::paste() {
- if (GDVIRTUAL_CALL(_paste)) {
+void TextEdit::paste(int p_caret) {
+ if (GDVIRTUAL_CALL(_paste, p_caret)) {
return;
}
- _paste_internal();
+ _paste_internal(p_caret);
}
-void TextEdit::paste_primary_clipboard() {
- if (GDVIRTUAL_CALL(_paste_primary_clipboard)) {
+void TextEdit::paste_primary_clipboard(int p_caret) {
+ if (GDVIRTUAL_CALL(_paste_primary_clipboard, p_caret)) {
return;
}
- _paste_primary_clipboard_internal();
+ _paste_primary_clipboard_internal(p_caret);
}
// Context menu.
@@ -3471,22 +3809,53 @@ void TextEdit::menu_option(int p_option) {
}
/* Versioning */
+void TextEdit::start_action(EditAction p_action) {
+ if (current_action != p_action) {
+ if (current_action != EditAction::ACTION_NONE) {
+ in_action = false;
+ pending_action_end = false;
+ end_complex_operation();
+ }
+
+ if (p_action != EditAction::ACTION_NONE) {
+ in_action = true;
+ begin_complex_operation();
+ }
+ } else if (current_action != EditAction::ACTION_NONE) {
+ pending_action_end = false;
+ }
+ current_action = p_action;
+}
+
+void TextEdit::end_action() {
+ if (current_action != EditAction::ACTION_NONE) {
+ pending_action_end = true;
+ }
+}
+
+TextEdit::EditAction TextEdit::get_current_action() const {
+ return current_action;
+}
+
void TextEdit::begin_complex_operation() {
_push_current_op();
if (complex_operation_count == 0) {
next_operation_is_complex = true;
+ current_op.start_carets = carets;
}
complex_operation_count++;
}
void TextEdit::end_complex_operation() {
_push_current_op();
- ERR_FAIL_COND(undo_stack.size() == 0);
complex_operation_count = MAX(complex_operation_count - 1, 0);
if (complex_operation_count > 0) {
return;
}
+ ERR_FAIL_COND(undo_stack.size() == 0);
+
+ undo_stack.back()->get().end_carets = carets;
if (undo_stack.back()->get().chain_forward) {
undo_stack.back()->get().chain_forward = false;
return;
@@ -3512,6 +3881,9 @@ void TextEdit::undo() {
return;
}
+ if (in_action) {
+ pending_action_end = true;
+ }
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -3546,25 +3918,36 @@ void TextEdit::undo() {
}
}
- if (op.type != TextOperation::TYPE_INSERT && (op.from_line != op.to_line || op.to_column != op.from_column + 1)) {
- select(op.from_line, op.from_column, op.to_line, op.to_column);
+ _update_scrollbars();
+ bool dirty_carets = carets.size() != undo_stack_pos->get().start_carets.size();
+ if (!dirty_carets) {
+ for (int i = 0; i < carets.size(); i++) {
+ if (carets[i].line != undo_stack_pos->get().start_carets[i].line || carets[i].column != undo_stack_pos->get().start_carets[i].column) {
+ dirty_carets = true;
+ break;
+ }
+ }
}
- _update_scrollbars();
- if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
- set_caret_line(undo_stack_pos->get().to_line, false);
- set_caret_column(undo_stack_pos->get().to_column);
- } else {
- set_caret_line(undo_stack_pos->get().from_line, false);
- set_caret_column(undo_stack_pos->get().from_column);
+ carets = undo_stack_pos->get().start_carets;
+
+ if (dirty_carets && !caret_pos_dirty) {
+ if (is_inside_tree()) {
+ MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ }
+ caret_pos_dirty = true;
}
- queue_redraw();
+ adjust_viewport_to_caret();
}
void TextEdit::redo() {
if (!editable) {
return;
}
+
+ if (in_action) {
+ pending_action_end = true;
+ }
_push_current_op();
if (undo_stack_pos == nullptr) {
@@ -3590,10 +3973,26 @@ void TextEdit::redo() {
}
_update_scrollbars();
- set_caret_line(undo_stack_pos->get().to_line, false);
- set_caret_column(undo_stack_pos->get().to_column);
+ bool dirty_carets = carets.size() != undo_stack_pos->get().end_carets.size();
+ if (!dirty_carets) {
+ for (int i = 0; i < carets.size(); i++) {
+ if (carets[i].line != undo_stack_pos->get().end_carets[i].line || carets[i].column != undo_stack_pos->get().end_carets[i].column) {
+ dirty_carets = true;
+ break;
+ }
+ }
+ }
+
+ carets = undo_stack_pos->get().end_carets;
undo_stack_pos = undo_stack_pos->next();
- queue_redraw();
+
+ if (dirty_carets && !caret_pos_dirty) {
+ if (is_inside_tree()) {
+ MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed");
+ }
+ caret_pos_dirty = true;
+ }
+ adjust_viewport_to_caret();
}
void TextEdit::clear_undo_history() {
@@ -3604,7 +4003,7 @@ void TextEdit::clear_undo_history() {
}
bool TextEdit::is_insert_text_operation() const {
- return (current_op.type == TextOperation::TYPE_INSERT);
+ return (current_op.type == TextOperation::TYPE_INSERT || current_action == EditAction::ACTION_TYPING);
}
void TextEdit::tag_saved_version() {
@@ -3793,7 +4192,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
int wrap_index = 0;
if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE || _is_hiding_enabled()) {
- Point2i f_ofs = get_next_visible_line_index_offset_from(first_vis_line, caret.wrap_ofs, rows + (1 * SIGN(rows)));
+ Point2i f_ofs = get_next_visible_line_index_offset_from(first_vis_line, first_visible_line_wrap_ofs, rows + (1 * SIGN(rows)));
wrap_index = f_ofs.y;
if (rows < 0) {
@@ -3821,7 +4220,7 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
int col = 0;
int colx = p_pos.x - (style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding);
- colx += caret.x_ofs;
+ colx += first_visible_col;
col = _get_char_pos_for_line(colx, row, wrap_index);
if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && wrap_index < get_line_wrap_count(row)) {
// Move back one if we are at the end of the row.
@@ -3896,21 +4295,21 @@ int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const {
// calculate visible lines
int minimap_visible_lines = get_minimap_visible_lines();
int visible_rows = get_visible_line_count() + 1;
- int first_visible_line = get_first_visible_line() - 1;
+ int first_vis_line = get_first_visible_line() - 1;
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
- draw_amount += get_line_wrap_count(first_visible_line + 1);
+ draw_amount += get_line_wrap_count(first_vis_line + 1);
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
// calculate viewport size and y offset
int viewport_height = (draw_amount - 1) * minimap_line_height;
int control_height = _get_control_height() - viewport_height;
- int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
+ int viewport_offset_y = round(get_scroll_pos_for_line(first_vis_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
// calculate the first line.
int num_lines_before = round((viewport_offset_y) / minimap_line_height);
- int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
- if (first_visible_line > 0 && minimap_line >= 0) {
- minimap_line -= get_next_visible_line_index_offset_from(first_visible_line, 0, -num_lines_before).x;
+ int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_vis_line;
+ if (first_vis_line > 0 && minimap_line >= 0) {
+ minimap_line -= get_next_visible_line_index_offset_from(first_vis_line, 0, -num_lines_before).x;
minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
} else {
minimap_line = 0;
@@ -3918,7 +4317,7 @@ int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const {
int row = minimap_line + Math::floor(rows);
if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE || _is_hiding_enabled()) {
- int f_ofs = get_next_visible_line_index_offset_from(minimap_line, caret.wrap_ofs, rows + (1 * SIGN(rows))).x - 1;
+ int f_ofs = get_next_visible_line_index_offset_from(minimap_line, first_visible_line_wrap_ofs, rows + (1 * SIGN(rows))).x - 1;
if (rows < 0) {
row = minimap_line - f_ofs;
} else {
@@ -3941,19 +4340,31 @@ bool TextEdit::is_dragging_cursor() const {
return dragging_selection || dragging_minimap;
}
-bool TextEdit::is_mouse_over_selection(bool p_edges) const {
- if (!has_selection()) {
- return false;
- }
- Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
- int row = pos.y;
- int col = pos.x;
- if (p_edges) {
- if ((row == selection.from_line && col == selection.from_column) || (row == selection.to_line && col == selection.to_column)) {
+bool TextEdit::is_mouse_over_selection(bool p_edges, int p_caret) const {
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
+
+ if (!has_selection(i)) {
+ continue;
+ }
+
+ Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
+ int row = pos.y;
+ int col = pos.x;
+ if (p_edges) {
+ if ((row == get_selection_from_line(i) && col == get_selection_from_column(i)) || (row == get_selection_to_line(i) && col == get_selection_to_column(i))) {
+ return true;
+ }
+ }
+
+ if (row >= get_selection_from_line(i) && row <= get_selection_to_line(i) && (row > get_selection_from_line(i) || col > get_selection_from_column(i)) && (row < get_selection_to_line(i) || col < get_selection_to_column(i))) {
return true;
}
}
- return (row >= selection.from_line && row <= selection.to_line && (row > selection.from_line || col > selection.from_column) && (row < selection.to_line || col < selection.to_column));
+
+ return false;
}
/* Caret */
@@ -4016,15 +4427,295 @@ bool TextEdit::is_caret_mid_grapheme_enabled() const {
return caret_mid_grapheme_enabled;
}
-bool TextEdit::is_caret_visible() const {
- return caret.visible;
+void TextEdit::set_multiple_carets_enabled(bool p_enabled) {
+ multi_carets_enabled = p_enabled;
+ if (!multi_carets_enabled) {
+ remove_secondary_carets();
+ }
+}
+
+bool TextEdit::is_multiple_carets_enabled() const {
+ return multi_carets_enabled;
+}
+
+int TextEdit::add_caret(int p_line, int p_col) {
+ if (!multi_carets_enabled) {
+ return -1;
+ }
+
+ p_line = CLAMP(p_line, 0, text.size() - 1);
+ p_col = CLAMP(p_col, 0, get_line(p_line).length());
+
+ for (int i = 0; i < carets.size(); i++) {
+ if (get_caret_line(i) == p_line && get_caret_column(i) == p_col) {
+ return -1;
+ }
+
+ if (has_selection(i)) {
+ if (p_line >= get_selection_from_line(i) && p_line <= get_selection_to_line(i) && (p_line > get_selection_from_line(i) || p_col >= get_selection_from_column(i)) && (p_line < get_selection_to_line(i) || p_col <= get_selection_to_column(i))) {
+ return -1;
+ }
+ }
+ }
+
+ carets.push_back(Caret());
+ set_caret_line(p_line, false, false, 0, carets.size() - 1);
+ set_caret_column(p_col, false, carets.size() - 1);
+ caret_index_edit_dirty = true;
+ return carets.size() - 1;
+}
+
+void TextEdit::remove_caret(int p_caret) {
+ ERR_FAIL_COND_MSG(carets.size() <= 1, "The main caret should not be removed.");
+ ERR_FAIL_INDEX(p_caret, carets.size());
+ carets.remove_at(p_caret);
+ caret_index_edit_dirty = true;
+}
+
+void TextEdit::remove_secondary_carets() {
+ carets.resize(1);
+ caret_index_edit_dirty = true;
+ queue_redraw();
+}
+
+void TextEdit::merge_overlapping_carets() {
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = 0; i < caret_edit_order.size() - 1; i++) {
+ int first_caret = caret_edit_order[i];
+ int second_caret = caret_edit_order[i + 1];
+
+ // Both have selection.
+ if (has_selection(first_caret) && has_selection(second_caret)) {
+ bool should_merge = false;
+ if (get_selection_from_line(first_caret) >= get_selection_from_line(second_caret) && get_selection_from_line(first_caret) <= get_selection_to_line(second_caret) && (get_selection_from_line(first_caret) > get_selection_from_line(second_caret) || get_selection_from_column(first_caret) >= get_selection_from_column(second_caret)) && (get_selection_from_line(first_caret) < get_selection_to_line(second_caret) || get_selection_from_column(first_caret) <= get_selection_to_column(second_caret))) {
+ should_merge = true;
+ }
+
+ if (get_selection_to_line(first_caret) >= get_selection_from_line(second_caret) && get_selection_to_line(first_caret) <= get_selection_to_line(second_caret) && (get_selection_to_line(first_caret) > get_selection_from_line(second_caret) || get_selection_to_column(first_caret) >= get_selection_from_column(second_caret)) && (get_selection_to_line(first_caret) < get_selection_to_line(second_caret) || get_selection_to_column(first_caret) <= get_selection_to_column(second_caret))) {
+ should_merge = true;
+ }
+
+ if (!should_merge) {
+ continue;
+ }
+
+ // Save the newest one for click+drag.
+ int caret_to_save = first_caret;
+ int caret_to_remove = second_caret;
+ if (first_caret < second_caret) {
+ caret_to_save = second_caret;
+ caret_to_remove = first_caret;
+ }
+
+ int from_line = MIN(get_selection_from_line(caret_to_save), get_selection_from_line(caret_to_remove));
+ int to_line = MAX(get_selection_to_line(caret_to_save), get_selection_to_line(caret_to_remove));
+ int from_col = get_selection_from_column(caret_to_save);
+ int to_col = get_selection_to_column(caret_to_save);
+ int selection_line = get_selection_line(caret_to_save);
+ int selection_col = get_selection_column(caret_to_save);
+
+ bool at_from = (get_caret_line(caret_to_save) == get_selection_from_line(caret_to_save) && get_caret_column(caret_to_save) == get_selection_from_column(caret_to_save));
+
+ if (at_from) {
+ if (get_selection_line(caret_to_remove) > get_selection_line(caret_to_save) || (get_selection_line(caret_to_remove) == get_selection_line(caret_to_save) && get_selection_column(caret_to_remove) >= get_selection_column(caret_to_save))) {
+ selection_line = get_selection_line(caret_to_remove);
+ selection_col = get_selection_column(caret_to_remove);
+ }
+ } else if (get_selection_line(caret_to_remove) < get_selection_line(caret_to_save) || (get_selection_line(caret_to_remove) == get_selection_line(caret_to_save) && get_selection_column(caret_to_remove) <= get_selection_column(caret_to_save))) {
+ selection_line = get_selection_line(caret_to_remove);
+ selection_col = get_selection_column(caret_to_remove);
+ }
+
+ if (get_selection_from_line(caret_to_remove) < get_selection_from_line(caret_to_save) || (get_selection_from_line(caret_to_remove) == get_selection_from_line(caret_to_save) && get_selection_from_column(caret_to_remove) <= get_selection_from_column(caret_to_save))) {
+ from_col = get_selection_from_column(caret_to_remove);
+ } else {
+ to_col = get_selection_to_column(caret_to_remove);
+ }
+
+ select(from_line, from_col, to_line, to_col, caret_to_save);
+ set_selection_mode(selecting_mode, selection_line, selection_col, caret_to_save);
+ set_caret_line((at_from ? from_line : to_line), caret_to_save == 0, true, 0, caret_to_save);
+ set_caret_column((at_from ? from_col : to_col), caret_to_save == 0, caret_to_save);
+ remove_caret(caret_to_remove);
+ i--;
+ caret_edit_order = get_caret_index_edit_order();
+ continue;
+ }
+
+ // Only first has selection.
+ if (has_selection(first_caret)) {
+ if (get_caret_line(second_caret) >= get_selection_from_line(first_caret) && get_caret_line(second_caret) <= get_selection_to_line(first_caret) && (get_caret_line(second_caret) > get_selection_from_line(first_caret) || get_caret_column(second_caret) >= get_selection_from_column(first_caret)) && (get_caret_line(second_caret) < get_selection_to_line(first_caret) || get_caret_column(second_caret) <= get_selection_to_column(first_caret))) {
+ remove_caret(second_caret);
+ caret_edit_order = get_caret_index_edit_order();
+ i--;
+ }
+ continue;
+ }
+
+ // Only second has Selection.
+ if (has_selection(second_caret)) {
+ if (get_caret_line(first_caret) >= get_selection_from_line(second_caret) && get_caret_line(first_caret) <= get_selection_to_line(second_caret) && (get_caret_line(first_caret) > get_selection_from_line(second_caret) || get_caret_column(first_caret) >= get_selection_from_column(second_caret)) && (get_caret_line(first_caret) < get_selection_to_line(second_caret) || get_caret_column(first_caret) <= get_selection_to_column(second_caret))) {
+ remove_caret(first_caret);
+ caret_edit_order = get_caret_index_edit_order();
+ i--;
+ }
+ continue;
+ }
+
+ // Both have no selection.
+ if (get_caret_line(first_caret) == get_caret_line(second_caret) && get_caret_column(first_caret) == get_caret_column(second_caret)) {
+ // Save the newest one for click+drag.
+ if (first_caret < second_caret) {
+ remove_caret(first_caret);
+ } else {
+ remove_caret(second_caret);
+ }
+ i--;
+ caret_edit_order = get_caret_index_edit_order();
+ continue;
+ }
+ }
+}
+
+int TextEdit::get_caret_count() const {
+ return carets.size();
}
-Point2 TextEdit::get_caret_draw_pos() const {
- return caret.draw_pos;
+void TextEdit::add_caret_at_carets(bool p_below) {
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &caret_index : caret_edit_order) {
+ const int caret_line = get_caret_line(caret_index);
+ const int caret_column = get_caret_column(caret_index);
+
+ // The last fit x will be cleared if the caret has a selection,
+ // but if it does not have a selection the last fit x will be
+ // transferred to the new caret
+ int caret_from_column = 0, caret_to_column = 0, caret_last_fit_x = carets[caret_index].last_fit_x;
+ if (has_selection(caret_index)) {
+ // If the selection goes over multiple lines, deselect it.
+ if (get_selection_from_line(caret_index) != get_selection_to_line(caret_index)) {
+ deselect(caret_index);
+ } else {
+ caret_from_column = get_selection_from_column(caret_index);
+ caret_to_column = get_selection_to_column(caret_index);
+ caret_last_fit_x = -1;
+ carets.write[caret_index].last_fit_x = _get_column_x_offset_for_line(caret_column, caret_line, caret_column);
+ }
+ }
+
+ // Get the line and column of the new caret as if you would move the caret by pressing the arrow keys
+ int new_caret_line, new_caret_column, new_caret_from_column = 0, new_caret_to_column = 0;
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_column, p_below, new_caret_line, new_caret_column, caret_last_fit_x);
+
+ // If the caret does have a selection calculate the new from and to columns
+ if (caret_from_column != caret_to_column) {
+ // We only need to calculate the selection columns if the column of the caret changed
+ if (caret_column != new_caret_column) {
+ int _; // unused placeholder for p_new_line
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_from_column, p_below, _, new_caret_from_column);
+ _get_above_below_caret_line_column(caret_line, get_caret_wrap_index(caret_index), caret_to_column, p_below, _, new_caret_to_column);
+ } else {
+ new_caret_from_column = caret_from_column;
+ new_caret_to_column = caret_to_column;
+ }
+ }
+
+ // Add the new caret
+ const int new_caret_index = add_caret(new_caret_line, new_caret_column);
+
+ if (new_caret_index == -1) {
+ continue;
+ }
+ // Also add the selection if there should be one
+ if (new_caret_from_column != new_caret_to_column) {
+ select(new_caret_line, new_caret_from_column, new_caret_line, new_caret_to_column, new_caret_index);
+ // Necessary to properly modify the selection after adding the new caret
+ carets.write[new_caret_index].selection.selecting_line = new_caret_line;
+ carets.write[new_caret_index].selection.selecting_column = new_caret_column == new_caret_from_column ? new_caret_to_column : new_caret_from_column;
+ continue;
+ }
+
+ // Copy the last fit x over
+ carets.write[new_caret_index].last_fit_x = carets[caret_index].last_fit_x;
+ }
+
+ merge_overlapping_carets();
+ queue_redraw();
}
-void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_hidden, int p_wrap_index) {
+Vector<int> TextEdit::get_caret_index_edit_order() {
+ if (!caret_index_edit_dirty) {
+ return caret_index_edit_order;
+ }
+
+ caret_index_edit_order.clear();
+ caret_index_edit_order.push_back(0);
+ for (int i = 1; i < carets.size(); i++) {
+ int j = 0;
+
+ int line = carets[i].selection.active ? carets[i].selection.to_line : carets[i].line;
+ int col = carets[i].selection.active ? carets[i].selection.to_column : carets[i].column;
+
+ for (; j < caret_index_edit_order.size(); j++) {
+ int idx = caret_index_edit_order[j];
+ int other_line = carets[idx].selection.active ? carets[idx].selection.to_line : carets[idx].line;
+ int other_col = carets[idx].selection.active ? carets[idx].selection.to_column : carets[idx].column;
+ if (line > other_line || (line == other_line && col > other_col)) {
+ break;
+ }
+ }
+ caret_index_edit_order.insert(j, i);
+ }
+ caret_index_edit_dirty = false;
+ return caret_index_edit_order;
+}
+
+void TextEdit::adjust_carets_after_edit(int p_caret, int p_from_line, int p_from_col, int p_to_line, int p_to_col) {
+ int edit_height = p_from_line - p_to_line;
+ int edit_size = ((edit_height == 0) ? p_from_col : 0) - p_to_col;
+
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int j = 0; j < caret_edit_order.size(); j++) {
+ if (caret_edit_order[j] == p_caret) {
+ return;
+ }
+
+ // Adjust caret.
+ // set_caret_line could adjust the column, so save here.
+ int cc = get_caret_column(caret_edit_order[j]);
+ if (edit_height != 0) {
+ set_caret_line(get_caret_line(caret_edit_order[j]) + edit_height, false, true, 0, caret_edit_order[j]);
+ }
+ if (get_caret_line(p_caret) == get_caret_line(caret_edit_order[j])) {
+ set_caret_column(cc + edit_size, false, caret_edit_order[j]);
+ }
+
+ // Adjust selection.
+ if (!has_selection(caret_edit_order[j])) {
+ continue;
+ }
+ if (edit_height != 0) {
+ carets.write[caret_edit_order[j]].selection.from_line += edit_height;
+ carets.write[caret_edit_order[j]].selection.to_line += edit_height;
+ }
+ if (get_caret_line(p_caret) == carets[caret_edit_order[j]].selection.from_line) {
+ carets.write[caret_edit_order[j]].selection.from_column += edit_size;
+ }
+ }
+}
+
+bool TextEdit::is_caret_visible(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), 0);
+ return carets[p_caret].visible;
+}
+
+Point2 TextEdit::get_caret_draw_pos(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), Point2(0, 0));
+ return carets[p_caret].draw_pos;
+}
+
+void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_hidden, int p_wrap_index, int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
if (setting_caret_line) {
return;
}
@@ -4053,10 +4744,10 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
}
}
}
- bool caret_moved = caret.line != p_line;
- caret.line = p_line;
+ bool caret_moved = get_caret_line(p_caret) != p_line;
+ carets.write[p_caret].line = p_line;
- int n_col = _get_char_pos_for_line(caret.last_fit_x, p_line, p_wrap_index);
+ int n_col = _get_char_pos_for_line(carets[p_caret].last_fit_x, p_line, p_wrap_index);
if (n_col != 0 && get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE && p_wrap_index < get_line_wrap_count(p_line)) {
Vector<String> rows = get_line_wrapped_text(p_line);
int row_end_col = 0;
@@ -4067,11 +4758,11 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
n_col -= 1;
}
}
- caret_moved = (caret_moved || caret.column != n_col);
- caret.column = n_col;
+ caret_moved = (caret_moved || get_caret_column(p_caret) != n_col);
+ carets.write[p_caret].column = n_col;
if (is_inside_tree() && p_adjust_viewport) {
- adjust_viewport_to_caret();
+ adjust_viewport_to_caret(p_caret);
}
setting_caret_line = false;
@@ -4084,25 +4775,27 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_
}
}
-int TextEdit::get_caret_line() const {
- return caret.line;
+int TextEdit::get_caret_line(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), 0);
+ return carets[p_caret].line;
}
-void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) {
+void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport, int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
if (p_col < 0) {
p_col = 0;
}
- if (p_col > get_line(caret.line).length()) {
- p_col = get_line(caret.line).length();
+ if (p_col > get_line(get_caret_line(p_caret)).length()) {
+ p_col = get_line(get_caret_line(p_caret)).length();
}
- bool caret_moved = caret.column != p_col;
- caret.column = p_col;
+ bool caret_moved = get_caret_column(p_caret) != p_col;
+ carets.write[p_caret].column = p_col;
- caret.last_fit_x = _get_column_x_offset_for_line(caret.column, caret.line);
+ carets.write[p_caret].last_fit_x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
if (is_inside_tree() && p_adjust_viewport) {
- adjust_viewport_to_caret();
+ adjust_viewport_to_caret(p_caret);
}
if (caret_moved && !caret_pos_dirty) {
@@ -4113,24 +4806,36 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) {
}
}
-int TextEdit::get_caret_column() const {
- return caret.column;
+int TextEdit::get_caret_column(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), 0);
+ return carets[p_caret].column;
}
-int TextEdit::get_caret_wrap_index() const {
- return get_line_wrap_index_at_column(caret.line, caret.column);
+int TextEdit::get_caret_wrap_index(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), 0);
+ return get_line_wrap_index_at_column(get_caret_line(p_caret), get_caret_column(p_caret));
}
-String TextEdit::get_word_under_caret() const {
- ERR_FAIL_INDEX_V(caret.line, text.size(), "");
- ERR_FAIL_INDEX_V(caret.column, text[caret.line].length() + 1, "");
- PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- for (int i = 0; i < words.size(); i = i + 2) {
- if (words[i] <= caret.column && words[i + 1] > caret.column) {
- return text[caret.line].substr(words[i], words[i + 1] - words[i]);
+String TextEdit::get_word_under_caret(int p_caret) const {
+ ERR_FAIL_COND_V(p_caret > carets.size(), "");
+
+ StringBuilder selected_text;
+ for (int c = 0; c < carets.size(); c++) {
+ if (p_caret != -1 && p_caret != c) {
+ continue;
+ }
+
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(c))->get_rid());
+ for (int i = 0; i < words.size(); i = i + 2) {
+ if (words[i] <= get_caret_column(c) && words[i + 1] > get_caret_column(c)) {
+ selected_text += text[get_caret_line(c)].substr(words[i], words[i + 1] - words[i]);
+ if (p_caret == -1 && c != carets.size() - 1) {
+ selected_text += "\n";
+ }
+ }
}
}
- return "";
+ return selected_text.as_string();
}
/* Selection. */
@@ -4156,7 +4861,7 @@ void TextEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
}
deselect_on_focus_loss_enabled = p_enabled;
- if (p_enabled && selection.active && !has_focus()) {
+ if (p_enabled && has_selection() && !has_focus()) {
deselect();
}
}
@@ -4173,30 +4878,24 @@ bool TextEdit::is_drag_and_drop_selection_enabled() const {
return drag_and_drop_selection_enabled;
}
-void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
- override_selected_font_color = p_override_selected_font_color;
-}
-
-bool TextEdit::is_overriding_selected_font_color() const {
- return override_selected_font_color;
-}
+void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column, int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
-void TextEdit::set_selection_mode(SelectionMode p_mode, int p_line, int p_column) {
- selection.selecting_mode = p_mode;
+ selecting_mode = p_mode;
if (p_line >= 0) {
ERR_FAIL_INDEX(p_line, text.size());
- selection.selecting_line = p_line;
- selection.selecting_column = CLAMP(selection.selecting_column, 0, text[selection.selecting_line].length());
+ carets.write[p_caret].selection.selecting_line = p_line;
+ carets.write[p_caret].selection.selecting_column = CLAMP(carets[p_caret].selection.selecting_column, 0, text[carets[p_caret].selection.selecting_line].length());
}
if (p_column >= 0) {
- ERR_FAIL_INDEX(selection.selecting_line, text.size());
- ERR_FAIL_INDEX(p_column, text[selection.selecting_line].length());
- selection.selecting_column = p_column;
+ ERR_FAIL_INDEX(carets[p_caret].selection.selecting_line, text.size());
+ ERR_FAIL_INDEX(p_column, text[carets[p_caret].selection.selecting_line].length() + 1);
+ carets.write[p_caret].selection.selecting_column = p_column;
}
}
TextEdit::SelectionMode TextEdit::get_selection_mode() const {
- return selection.selecting_mode;
+ return selecting_mode;
}
void TextEdit::select_all() {
@@ -4207,21 +4906,19 @@ void TextEdit::select_all() {
if (text.size() == 1 && text[0].length() == 0) {
return;
}
- selection.active = true;
- selection.from_line = 0;
- selection.from_column = 0;
- selection.selecting_line = 0;
- selection.selecting_column = 0;
- selection.to_line = text.size() - 1;
- selection.to_column = text[selection.to_line].length();
- selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
- selection.shiftclick_left = true;
- set_caret_line(selection.to_line, false);
- set_caret_column(selection.to_column, false);
+
+ remove_secondary_carets();
+ select(0, 0, text.size() - 1, text[text.size() - 1].length());
+ set_selection_mode(SelectionMode::SELECTION_MODE_SHIFT, 0, 0);
+ carets.write[0].selection.shiftclick_left = true;
+ set_caret_line(get_selection_to_line(), false);
+ set_caret_column(get_selection_to_column(), false);
queue_redraw();
}
-void TextEdit::select_word_under_caret() {
+void TextEdit::select_word_under_caret(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
+
if (!selecting_enabled) {
return;
}
@@ -4230,36 +4927,83 @@ void TextEdit::select_word_under_caret() {
return;
}
- if (selection.active) {
- /* Allow toggling selection by pressing the shortcut a second time. */
- /* This is also usable as a general-purpose "deselect" shortcut after */
- /* selecting anything. */
- deselect();
+ for (int c = 0; c < carets.size(); c++) {
+ if (p_caret != -1 && p_caret != c) {
+ continue;
+ }
+
+ if (has_selection(c)) {
+ // Allow toggling selection by pressing the shortcut a second time.
+ // This is also usable as a general-purpose "deselect" shortcut after
+ // selecting anything.
+ deselect(c);
+ continue;
+ }
+
+ int begin = 0;
+ int end = 0;
+ const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(get_caret_line(c))->get_rid());
+ for (int i = 0; i < words.size(); i = i + 2) {
+ if ((words[i] <= get_caret_column(c) && words[i + 1] >= get_caret_column(c)) || (i == words.size() - 2 && get_caret_column(c) == words[i + 1])) {
+ begin = words[i];
+ end = words[i + 1];
+ break;
+ }
+ }
+
+ // No word found.
+ if (begin == 0 && end == 0) {
+ continue;
+ }
+
+ select(get_caret_line(c), begin, get_caret_line(c), end, c);
+ // Move the caret to the end of the word for easier editing.
+ set_caret_column(end, false, c);
+ }
+ merge_overlapping_carets();
+}
+
+void TextEdit::add_selection_for_next_occurrence() {
+ if (!selecting_enabled || !is_multiple_carets_enabled()) {
return;
}
- int begin = 0;
- int end = 0;
- const PackedInt32Array words = TS->shaped_text_get_word_breaks(text.get_line_data(caret.line)->get_rid());
- for (int i = 0; i < words.size(); i = i + 2) {
- if ((words[i] <= caret.column && words[i + 1] >= caret.column) || (i == words.size() - 2 && caret.column == words[i + 1])) {
- begin = words[i];
- end = words[i + 1];
- break;
- }
+ if (text.size() == 1 && text[0].length() == 0) {
+ return;
}
- // No word found.
- if (begin == 0 && end == 0) {
+ // Always use the last caret, to correctly search for
+ // the next occurrence that comes after this caret.
+ int caret = get_caret_count() - 1;
+
+ if (!has_selection(caret)) {
+ select_word_under_caret(caret);
return;
}
- select(caret.line, begin, caret.line, end);
- /* Move the caret to the end of the word for easier editing. */
- set_caret_column(end, false);
+ const String &highlighted_text = get_selected_text(caret);
+ int column = get_selection_from_column(caret) + 1;
+ int line = get_caret_line(caret);
+
+ const Point2i next_occurrence = search(highlighted_text, SEARCH_MATCH_CASE, line, column);
+
+ if (next_occurrence.x == -1 || next_occurrence.y == -1) {
+ return;
+ }
+
+ int to_column = get_selection_to_column(caret) + 1;
+ int end = next_occurrence.x + (to_column - column);
+ int new_caret = add_caret(next_occurrence.y, end);
+
+ if (new_caret != -1) {
+ select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret);
+ adjust_viewport_to_caret(new_caret);
+ merge_overlapping_carets();
+ }
}
-void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
+void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
if (!selecting_enabled) {
return;
}
@@ -4288,91 +5032,143 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t
p_to_column = 0;
}
- selection.from_line = p_from_line;
- selection.from_column = p_from_column;
- selection.to_line = p_to_line;
- selection.to_column = p_to_column;
+ carets.write[p_caret].selection.from_line = p_from_line;
+ carets.write[p_caret].selection.from_column = p_from_column;
+ carets.write[p_caret].selection.to_line = p_to_line;
+ carets.write[p_caret].selection.to_column = p_to_column;
- selection.active = true;
+ carets.write[p_caret].selection.active = true;
- if (selection.from_line == selection.to_line) {
- if (selection.from_column == selection.to_column) {
- selection.active = false;
+ if (carets[p_caret].selection.from_line == carets[p_caret].selection.to_line) {
+ if (carets[p_caret].selection.from_column == carets[p_caret].selection.to_column) {
+ carets.write[p_caret].selection.active = false;
- } else if (selection.from_column > selection.to_column) {
- selection.shiftclick_left = false;
- SWAP(selection.from_column, selection.to_column);
+ } else if (carets[p_caret].selection.from_column > carets[p_caret].selection.to_column) {
+ carets.write[p_caret].selection.shiftclick_left = false;
+ SWAP(carets.write[p_caret].selection.from_column, carets.write[p_caret].selection.to_column);
} else {
- selection.shiftclick_left = true;
+ carets.write[p_caret].selection.shiftclick_left = true;
}
- } else if (selection.from_line > selection.to_line) {
- selection.shiftclick_left = false;
- SWAP(selection.from_line, selection.to_line);
- SWAP(selection.from_column, selection.to_column);
+ } else if (carets[p_caret].selection.from_line > carets[p_caret].selection.to_line) {
+ carets.write[p_caret].selection.shiftclick_left = false;
+ SWAP(carets.write[p_caret].selection.from_line, carets.write[p_caret].selection.to_line);
+ SWAP(carets.write[p_caret].selection.from_column, carets.write[p_caret].selection.to_column);
} else {
- selection.shiftclick_left = true;
+ carets.write[p_caret].selection.shiftclick_left = true;
}
+ caret_index_edit_dirty = true;
queue_redraw();
}
-bool TextEdit::has_selection() const {
- return selection.active;
+bool TextEdit::has_selection(int p_caret) const {
+ ERR_FAIL_COND_V(p_caret > carets.size(), false);
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
+
+ if (carets[i].selection.active) {
+ return true;
+ }
+ }
+ return false;
}
-String TextEdit::get_selected_text() const {
- if (!selection.active) {
- return "";
+String TextEdit::get_selected_text(int p_caret) {
+ ERR_FAIL_COND_V(p_caret > carets.size(), "");
+
+ StringBuilder selected_text;
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = caret_edit_order.size() - 1; i >= 0; i--) {
+ int caret_idx = caret_edit_order[i];
+ if (p_caret != -1 && p_caret != caret_idx) {
+ continue;
+ }
+
+ if (!has_selection(caret_idx)) {
+ continue;
+ }
+ selected_text += _base_get_text(get_selection_from_line(caret_idx), get_selection_from_column(caret_idx), get_selection_to_line(caret_idx), get_selection_to_column(caret_idx));
+ if (p_caret == -1 && i != 0) {
+ selected_text += "\n";
+ }
}
- return _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
+ return selected_text.as_string();
}
-int TextEdit::get_selection_line() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.selecting_line;
+int TextEdit::get_selection_line(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.selecting_line;
}
-int TextEdit::get_selection_column() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.selecting_column;
+int TextEdit::get_selection_column(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.selecting_column;
}
-int TextEdit::get_selection_from_line() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.from_line;
+int TextEdit::get_selection_from_line(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.from_line;
}
-int TextEdit::get_selection_from_column() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.from_column;
+int TextEdit::get_selection_from_column(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.from_column;
}
-int TextEdit::get_selection_to_line() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.to_line;
+int TextEdit::get_selection_to_line(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.to_line;
}
-int TextEdit::get_selection_to_column() const {
- ERR_FAIL_COND_V(!selection.active, -1);
- return selection.to_column;
+int TextEdit::get_selection_to_column(int p_caret) const {
+ ERR_FAIL_INDEX_V(p_caret, carets.size(), -1);
+ ERR_FAIL_COND_V(!has_selection(p_caret), -1);
+ return carets[p_caret].selection.to_column;
}
-void TextEdit::deselect() {
- selection.active = false;
+void TextEdit::deselect(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
+ for (int i = 0; i < carets.size(); i++) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
+ carets.write[i].selection.active = false;
+ }
+ caret_index_edit_dirty = true;
queue_redraw();
}
-void TextEdit::delete_selection() {
- if (!has_selection()) {
- return;
- }
+void TextEdit::delete_selection(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
+
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
+
+ if (!has_selection(i)) {
+ continue;
+ }
- selection.active = false;
- selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
- set_caret_line(selection.from_line, false, false);
- set_caret_column(selection.from_column);
+ selecting_mode = SelectionMode::SELECTION_MODE_NONE;
+ _remove_text(carets[i].selection.from_line, carets[i].selection.from_column, carets[i].selection.to_line, carets[i].selection.to_column);
+ set_caret_line(carets[i].selection.from_line, false, false, 0, i);
+ set_caret_column(carets[i].selection.from_column, i == 0, i);
+ carets.write[i].selection.active = false;
+
+ adjust_carets_after_edit(i, carets[i].selection.from_line, carets[i].selection.from_column, carets[i].selection.to_line, carets[i].selection.to_column);
+ }
+ end_complex_operation();
queue_redraw();
}
@@ -4472,6 +5268,14 @@ bool TextEdit::is_scroll_past_end_of_file_enabled() const {
return scroll_past_end_of_file_enabled;
}
+VScrollBar *TextEdit::get_v_scroll_bar() const {
+ return v_scroll;
+}
+
+HScrollBar *TextEdit::get_h_scroll_bar() const {
+ return h_scroll;
+}
+
void TextEdit::set_v_scroll(double p_scroll) {
v_scroll->set_value(p_scroll);
int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
@@ -4543,7 +5347,7 @@ void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) {
}
int TextEdit::get_first_visible_line() const {
- return CLAMP(caret.line_ofs, 0, text.size() - 1);
+ return CLAMP(first_visible_line, 0, text.size() - 1);
}
void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
@@ -4582,14 +5386,14 @@ void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
int TextEdit::get_last_full_visible_line() const {
int first_vis_line = get_first_visible_line();
int last_vis_line = 0;
- last_vis_line = first_vis_line + get_next_visible_line_index_offset_from(first_vis_line, caret.wrap_ofs, get_visible_line_count()).x - 1;
+ last_vis_line = first_vis_line + get_next_visible_line_index_offset_from(first_vis_line, first_visible_line_wrap_ofs, get_visible_line_count()).x - 1;
last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
return last_vis_line;
}
int TextEdit::get_last_full_visible_line_wrap_index() const {
int first_vis_line = get_first_visible_line();
- return get_next_visible_line_index_offset_from(first_vis_line, caret.wrap_ofs, get_visible_line_count()).y;
+ return get_next_visible_line_index_offset_from(first_vis_line, first_visible_line_wrap_ofs, get_visible_line_count()).y;
}
int TextEdit::get_visible_line_count() const {
@@ -4625,16 +5429,18 @@ int TextEdit::get_total_visible_line_count() const {
}
// Auto adjust
-void TextEdit::adjust_viewport_to_caret() {
+void TextEdit::adjust_viewport_to_caret(int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
+
// Make sure Caret is visible on the screen.
scrolling = false;
minimap_clicked = false;
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
+ int cur_line = get_caret_line(p_caret);
+ int cur_wrap = get_caret_wrap_index(p_caret);
int first_vis_line = get_first_visible_line();
- int first_vis_wrap = caret.wrap_ofs;
+ int first_vis_wrap = first_visible_line_wrap_ofs;
int last_vis_line = get_last_full_visible_line();
int last_vis_wrap = get_last_full_visible_line_wrap_index();
@@ -4661,43 +5467,45 @@ void TextEdit::adjust_viewport_to_caret() {
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- caret_pos.x = _get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
- caret_pos.x = _get_column_x_offset_for_line(caret.column, caret.line);
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
}
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- caret_pos.y = _get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
- caret_pos.y = _get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
}
} else {
caret_pos.y = caret_pos.x;
}
- if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
- caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
+ if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) {
+ first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
}
- if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
- caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
+ if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) {
+ first_visible_col = MIN(caret_pos.x, caret_pos.y);
}
} else {
- caret.x_ofs = 0;
+ first_visible_col = 0;
}
- h_scroll->set_value(caret.x_ofs);
+ h_scroll->set_value(first_visible_col);
queue_redraw();
}
-void TextEdit::center_viewport_to_caret() {
+void TextEdit::center_viewport_to_caret(int p_caret) {
+ ERR_FAIL_INDEX(p_caret, carets.size());
+
// Move viewport so the caret is in the center of the screen.
scrolling = false;
minimap_clicked = false;
- set_line_as_center_visible(caret.line, get_caret_wrap_index());
+ set_line_as_center_visible(get_caret_line(p_caret), get_caret_wrap_index(p_caret));
int visible_width = get_size().width - style_normal->get_minimum_size().width - gutters_width - gutter_padding;
if (draw_minimap) {
visible_width -= minimap_width;
@@ -4714,33 +5522,33 @@ void TextEdit::center_viewport_to_caret() {
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- caret_pos.x = _get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
- caret_pos.x = _get_column_x_offset_for_line(caret.column, caret.line);
+ caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret));
}
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- caret_pos.y = _get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret));
} else {
- caret_pos.y = _get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
+ caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.size(), get_caret_line(p_caret), get_caret_column(p_caret));
}
} else {
caret_pos.y = caret_pos.x;
}
- if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
- caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
+ if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) {
+ first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
}
- if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
- caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
+ if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) {
+ first_visible_col = MIN(caret_pos.x, caret_pos.y);
}
} else {
- caret.x_ofs = 0;
+ first_visible_col = 0;
}
- h_scroll->set_value(caret.x_ofs);
+ h_scroll->set_value(first_visible_col);
queue_redraw();
}
@@ -5187,7 +5995,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("swap_lines", "from_line", "to_line"), &TextEdit::swap_lines);
ClassDB::bind_method(D_METHOD("insert_line_at", "line", "text"), &TextEdit::insert_line_at);
- ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &TextEdit::insert_text_at_caret);
+ ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text", "caret_index"), &TextEdit::insert_text_at_caret, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("remove_text", "from_line", "from_column", "to_line", "to_column"), &TextEdit::remove_text);
@@ -5196,18 +6004,19 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_visible_line_index_offset_from", "line", "wrap_index", "visible_amount"), &TextEdit::get_next_visible_line_index_offset_from);
// Overridable actions
- ClassDB::bind_method(D_METHOD("backspace"), &TextEdit::backspace);
+ ClassDB::bind_method(D_METHOD("backspace", "caret_index"), &TextEdit::backspace, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut);
- ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
- ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste);
+ ClassDB::bind_method(D_METHOD("cut", "caret_index"), &TextEdit::cut, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("copy", "caret_index"), &TextEdit::copy, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("paste", "caret_index"), &TextEdit::paste, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("paste_primary_clipboard", "caret_index"), &TextEdit::paste_primary_clipboard, DEFVAL(-1));
- GDVIRTUAL_BIND(_handle_unicode_input, "unicode_char")
- GDVIRTUAL_BIND(_backspace)
- GDVIRTUAL_BIND(_cut)
- GDVIRTUAL_BIND(_copy)
- GDVIRTUAL_BIND(_paste)
- GDVIRTUAL_BIND(_paste_primary_clipboard)
+ GDVIRTUAL_BIND(_handle_unicode_input, "unicode_char", "caret_index")
+ GDVIRTUAL_BIND(_backspace, "caret_index")
+ GDVIRTUAL_BIND(_cut, "caret_index")
+ GDVIRTUAL_BIND(_copy, "caret_index")
+ GDVIRTUAL_BIND(_paste, "caret_index")
+ GDVIRTUAL_BIND(_paste_primary_clipboard, "caret_index")
// Context Menu
BIND_ENUM_CONSTANT(MENU_CUT);
@@ -5241,6 +6050,14 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_MAX);
/* Versioning */
+ BIND_ENUM_CONSTANT(ACTION_NONE);
+ BIND_ENUM_CONSTANT(ACTION_TYPING);
+ BIND_ENUM_CONSTANT(ACTION_BACKSPACE);
+ BIND_ENUM_CONSTANT(ACTION_DELETE);
+
+ ClassDB::bind_method(D_METHOD("start_action", "action"), &TextEdit::start_action);
+ ClassDB::bind_method(D_METHOD("end_action"), &TextEdit::end_complex_operation);
+
ClassDB::bind_method(D_METHOD("begin_complex_operation"), &TextEdit::begin_complex_operation);
ClassDB::bind_method(D_METHOD("end_complex_operation"), &TextEdit::end_complex_operation);
@@ -5280,7 +6097,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_minimap_line_at_pos", "position"), &TextEdit::get_minimap_line_at_pos);
ClassDB::bind_method(D_METHOD("is_dragging_cursor"), &TextEdit::is_dragging_cursor);
- ClassDB::bind_method(D_METHOD("is_mouse_over_selection", "edges"), &TextEdit::is_mouse_over_selection);
+ ClassDB::bind_method(D_METHOD("is_mouse_over_selection", "edges", "caret_index"), &TextEdit::is_mouse_over_selection, DEFVAL(-1));
/* Caret. */
BIND_ENUM_CONSTANT(CARET_TYPE_LINE);
@@ -5304,18 +6121,31 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_caret_mid_grapheme_enabled", "enabled"), &TextEdit::set_caret_mid_grapheme_enabled);
ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &TextEdit::is_caret_mid_grapheme_enabled);
- ClassDB::bind_method(D_METHOD("is_caret_visible"), &TextEdit::is_caret_visible);
- ClassDB::bind_method(D_METHOD("get_caret_draw_pos"), &TextEdit::get_caret_draw_pos);
+ ClassDB::bind_method(D_METHOD("set_multiple_carets_enabled", "enabled"), &TextEdit::set_multiple_carets_enabled);
+ ClassDB::bind_method(D_METHOD("is_multiple_carets_enabled"), &TextEdit::is_multiple_carets_enabled);
+
+ ClassDB::bind_method(D_METHOD("add_caret", "line", "col"), &TextEdit::add_caret);
+ ClassDB::bind_method(D_METHOD("remove_caret", "caret"), &TextEdit::remove_caret);
+ ClassDB::bind_method(D_METHOD("remove_secondary_carets"), &TextEdit::remove_secondary_carets);
+ ClassDB::bind_method(D_METHOD("merge_overlapping_carets"), &TextEdit::merge_overlapping_carets);
+ ClassDB::bind_method(D_METHOD("get_caret_count"), &TextEdit::get_caret_count);
+ ClassDB::bind_method(D_METHOD("add_caret_at_carets", "below"), &TextEdit::add_caret_at_carets);
- ClassDB::bind_method(D_METHOD("set_caret_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::set_caret_line, DEFVAL(true), DEFVAL(true), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_caret_line"), &TextEdit::get_caret_line);
+ ClassDB::bind_method(D_METHOD("get_caret_index_edit_order"), &TextEdit::get_caret_index_edit_order);
+ ClassDB::bind_method(D_METHOD("adjust_carets_after_edit", "caret", "from_line", "from_col", "to_line", "to_col"), &TextEdit::adjust_carets_after_edit);
- ClassDB::bind_method(D_METHOD("set_caret_column", "column", "adjust_viewport"), &TextEdit::set_caret_column, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("get_caret_column"), &TextEdit::get_caret_column);
+ ClassDB::bind_method(D_METHOD("is_caret_visible", "caret_index"), &TextEdit::is_caret_visible, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_caret_draw_pos", "caret_index"), &TextEdit::get_caret_draw_pos, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_caret_wrap_index"), &TextEdit::get_caret_wrap_index);
+ ClassDB::bind_method(D_METHOD("set_caret_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index", "caret_index"), &TextEdit::set_caret_line, DEFVAL(true), DEFVAL(true), DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_caret_line", "caret_index"), &TextEdit::get_caret_line, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_word_under_caret"), &TextEdit::get_word_under_caret);
+ ClassDB::bind_method(D_METHOD("set_caret_column", "column", "adjust_viewport", "caret_index"), &TextEdit::set_caret_column, DEFVAL(true), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_caret_column", "caret_index"), &TextEdit::get_caret_column, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("get_caret_wrap_index", "caret_index"), &TextEdit::get_caret_wrap_index, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("get_word_under_caret", "caret_index"), &TextEdit::get_word_under_caret, DEFVAL(-1));
/* Selection. */
BIND_ENUM_CONSTANT(SELECTION_MODE_NONE);
@@ -5333,30 +6163,28 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_drag_and_drop_selection_enabled", "enable"), &TextEdit::set_drag_and_drop_selection_enabled);
ClassDB::bind_method(D_METHOD("is_drag_and_drop_selection_enabled"), &TextEdit::is_drag_and_drop_selection_enabled);
- ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &TextEdit::set_override_selected_font_color);
- ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &TextEdit::is_overriding_selected_font_color);
-
- ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_selection_mode", "mode", "line", "column", "caret_index"), &TextEdit::set_selection_mode, DEFVAL(-1), DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_selection_mode"), &TextEdit::get_selection_mode);
ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
- ClassDB::bind_method(D_METHOD("select_word_under_caret"), &TextEdit::select_word_under_caret);
- ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select);
+ ClassDB::bind_method(D_METHOD("select_word_under_caret", "caret_index"), &TextEdit::select_word_under_caret, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_selection_for_next_occurrence"), &TextEdit::add_selection_for_next_occurrence);
+ ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column", "caret_index"), &TextEdit::select, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("has_selection"), &TextEdit::has_selection);
+ ClassDB::bind_method(D_METHOD("has_selection", "caret_index"), &TextEdit::has_selection, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_selected_text"), &TextEdit::get_selected_text);
+ ClassDB::bind_method(D_METHOD("get_selected_text", "caret_index"), &TextEdit::get_selected_text, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_selection_line"), &TextEdit::get_selection_line);
- ClassDB::bind_method(D_METHOD("get_selection_column"), &TextEdit::get_selection_column);
+ ClassDB::bind_method(D_METHOD("get_selection_line", "caret_index"), &TextEdit::get_selection_line, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_selection_column", "caret_index"), &TextEdit::get_selection_column, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line);
- ClassDB::bind_method(D_METHOD("get_selection_from_column"), &TextEdit::get_selection_from_column);
- ClassDB::bind_method(D_METHOD("get_selection_to_line"), &TextEdit::get_selection_to_line);
- ClassDB::bind_method(D_METHOD("get_selection_to_column"), &TextEdit::get_selection_to_column);
+ ClassDB::bind_method(D_METHOD("get_selection_from_line", "caret_index"), &TextEdit::get_selection_from_line, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_selection_from_column", "caret_index"), &TextEdit::get_selection_from_column, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_selection_to_line", "caret_index"), &TextEdit::get_selection_to_line, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_selection_to_column", "caret_index"), &TextEdit::get_selection_to_column, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
- ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection);
+ ClassDB::bind_method(D_METHOD("deselect", "caret_index"), &TextEdit::deselect, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("delete_selection", "caret_index"), &TextEdit::delete_selection, DEFVAL(-1));
/* Line wrapping. */
BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE);
@@ -5379,6 +6207,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_smooth_scroll_enabled", "enable"), &TextEdit::set_smooth_scroll_enabled);
ClassDB::bind_method(D_METHOD("is_smooth_scroll_enabled"), &TextEdit::is_smooth_scroll_enabled);
+ ClassDB::bind_method(D_METHOD("get_v_scroll_bar"), &TextEdit::get_v_scroll_bar);
+ ClassDB::bind_method(D_METHOD("get_h_scroll_bar"), &TextEdit::get_h_scroll_bar);
+
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &TextEdit::set_v_scroll);
ClassDB::bind_method(D_METHOD("get_v_scroll"), &TextEdit::get_v_scroll);
@@ -5411,8 +6242,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_total_visible_line_count"), &TextEdit::get_total_visible_line_count);
// Auto adjust
- ClassDB::bind_method(D_METHOD("adjust_viewport_to_caret"), &TextEdit::adjust_viewport_to_caret);
- ClassDB::bind_method(D_METHOD("center_viewport_to_caret"), &TextEdit::center_viewport_to_caret);
+ ClassDB::bind_method(D_METHOD("adjust_viewport_to_caret", "caret_index"), &TextEdit::adjust_viewport_to_caret, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("center_viewport_to_caret", "caret_index"), &TextEdit::center_viewport_to_caret, DEFVAL(0));
// Minimap
ClassDB::bind_method(D_METHOD("set_draw_minimap", "enabled"), &TextEdit::set_draw_minimap);
@@ -5501,7 +6332,6 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
@@ -5528,6 +6358,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_interval", "get_caret_blink_interval");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_move_on_right_click"), "set_move_caret_on_right_click_enabled", "is_move_caret_on_right_click_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_multiple"), "set_multiple_carets_enabled", "is_multiple_carets_enabled");
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");
@@ -5613,157 +6444,238 @@ void TextEdit::_set_symbol_lookup_word(const String &p_symbol) {
/* Text manipulation */
// Overridable actions
-void TextEdit::_handle_unicode_input_internal(const uint32_t p_unicode) {
+void TextEdit::_handle_unicode_input_internal(const uint32_t p_unicode, int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
if (!editable) {
return;
}
- bool had_selection = has_selection();
- if (had_selection) {
- begin_complex_operation();
- delete_selection();
- }
-
- /* Remove the old character if in insert mode and no selection. */
- if (overtype_mode && !had_selection) {
- begin_complex_operation();
-
- /* Make sure we don't try and remove empty space. */
- int cl = get_caret_line();
- int cc = get_caret_column();
- if (cc < get_line(cl).length()) {
- _remove_text(cl, cc, cl, cc + 1);
+ start_action(EditAction::ACTION_TYPING);
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
}
- }
- const char32_t chr[2] = { (char32_t)p_unicode, 0 };
- insert_text_at_caret(chr);
+ /* Remove the old character if in insert mode and no selection. */
+ if (overtype_mode && !has_selection(i)) {
+ /* Make sure we don't try and remove empty space. */
+ int cl = get_caret_line(i);
+ int cc = get_caret_column(i);
+ if (cc < get_line(cl).length()) {
+ _remove_text(cl, cc, cl, cc + 1);
+ }
+ }
- if ((overtype_mode && !had_selection) || (had_selection)) {
- end_complex_operation();
+ const char32_t chr[2] = { (char32_t)p_unicode, 0 };
+ insert_text_at_caret(chr, i);
}
+ end_action();
}
-void TextEdit::_backspace_internal() {
+void TextEdit::_backspace_internal(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
if (!editable) {
return;
}
- if (has_selection()) {
- delete_selection();
+ if (has_selection(p_caret)) {
+ delete_selection(p_caret);
return;
}
- int cc = get_caret_column();
- int cl = get_caret_line();
+ begin_complex_operation();
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
- if (cc == 0 && cl == 0) {
- return;
- }
+ int cc = get_caret_column(i);
+ int cl = get_caret_line(i);
- int prev_line = cc ? cl : cl - 1;
- int prev_column = cc ? (cc - 1) : (text[cl - 1].length());
+ if (cc == 0 && cl == 0) {
+ continue;
+ }
- merge_gutters(prev_line, cl);
+ int prev_line = cc ? cl : cl - 1;
+ int prev_column = cc ? (cc - 1) : (text[cl - 1].length());
- if (_is_line_hidden(cl)) {
- _set_line_as_hidden(prev_line, true);
- }
- _remove_text(prev_line, prev_column, cl, cc);
+ merge_gutters(prev_line, cl);
- set_caret_line(prev_line, false, true);
- set_caret_column(prev_column);
+ if (_is_line_hidden(cl)) {
+ _set_line_as_hidden(prev_line, true);
+ }
+ _remove_text(prev_line, prev_column, cl, cc);
+
+ set_caret_line(prev_line, false, true, 0, i);
+ set_caret_column(prev_column, i == 0, i);
+
+ adjust_carets_after_edit(i, prev_line, prev_column, cl, cc);
+ }
+ merge_overlapping_carets();
+ end_complex_operation();
}
-void TextEdit::_cut_internal() {
+void TextEdit::_cut_internal(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
if (!editable) {
return;
}
- if (has_selection()) {
- DisplayServer::get_singleton()->clipboard_set(get_selected_text());
- delete_selection();
+ if (has_selection(p_caret)) {
+ DisplayServer::get_singleton()->clipboard_set(get_selected_text(p_caret));
+ delete_selection(p_caret);
cut_copy_line = "";
return;
}
- int cl = get_caret_line();
- int cc = get_caret_column();
- int indent_level = get_indent_level(cl);
- double hscroll = get_h_scroll();
+ begin_complex_operation();
+ Vector<int> carets_to_remove;
+
+ StringBuilder clipboard;
+ // This is the exception and has to edit in reverse order else the string copied to the clipboard will be backwards.
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = caret_edit_order.size() - 1; i >= 0; i--) {
+ int caret_idx = caret_edit_order[i];
+ if (p_caret != -1 && p_caret != caret_idx) {
+ continue;
+ }
- String clipboard = text[cl];
- DisplayServer::get_singleton()->clipboard_set(clipboard);
- set_caret_column(0);
+ int cl = get_caret_line(caret_idx);
+ int cc = get_caret_column(caret_idx);
+ int indent_level = get_indent_level(cl);
+ double hscroll = get_h_scroll();
- if (cl == 0 && get_line_count() > 1) {
- _remove_text(cl, 0, cl + 1, 0);
- } else {
- _remove_text(cl, 0, cl, text[cl].length());
- backspace();
- set_caret_line(get_caret_line() + 1);
- }
+ // Check for overlaping carets.
+ // We don't need to worry about selections as that is caught before this entire section.
+ for (int j = i - 1; j >= 0; j--) {
+ if (get_caret_line(caret_edit_order[j]) == cl) {
+ carets_to_remove.push_back(caret_edit_order[j]);
+ i = j;
+ }
+ }
+
+ clipboard += text[cl];
+ if (p_caret == -1 && caret_idx != 0) {
+ clipboard += "\n";
+ }
+
+ if (cl == 0 && get_line_count() > 1) {
+ _remove_text(cl, 0, cl + 1, 0);
+ adjust_carets_after_edit(caret_idx, cl, 0, cl + 1, text[cl].length());
+ } else {
+ _remove_text(cl, 0, cl, text[cl].length());
+ set_caret_column(0, false, caret_idx);
+ backspace(caret_idx);
+ set_caret_line(get_caret_line(caret_idx) + 1, caret_idx == 0, 0, 0, caret_idx);
+ }
- // Correct the visually perceived caret column taking care of indentation level of the lines.
- int diff_indent = indent_level - get_indent_level(get_caret_line());
- cc += diff_indent;
- if (diff_indent != 0) {
- cc += diff_indent > 0 ? -1 : 1;
+ // Correct the visually perceived caret column taking care of indentation level of the lines.
+ int diff_indent = indent_level - get_indent_level(get_caret_line(caret_idx));
+ cc += diff_indent;
+ if (diff_indent != 0) {
+ cc += diff_indent > 0 ? -1 : 1;
+ }
+
+ // Restore horizontal scroll and caret column modified by the backspace() call.
+ set_h_scroll(hscroll);
+ set_caret_column(cc, caret_idx == 0, caret_idx);
}
- // Restore horizontal scroll and caret column modified by the backspace() call.
- set_h_scroll(hscroll);
- set_caret_column(cc);
+ // Sort and remove backwards to preserve indexes.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ remove_caret(carets_to_remove[i]);
+ }
+ end_complex_operation();
- cut_copy_line = clipboard;
+ String clipboard_string = clipboard.as_string();
+ DisplayServer::get_singleton()->clipboard_set(clipboard_string);
+ cut_copy_line = clipboard_string;
}
-void TextEdit::_copy_internal() {
- if (has_selection()) {
- DisplayServer::get_singleton()->clipboard_set(get_selected_text());
+void TextEdit::_copy_internal(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
+ if (has_selection(p_caret)) {
+ DisplayServer::get_singleton()->clipboard_set(get_selected_text(p_caret));
cut_copy_line = "";
return;
}
- int cl = get_caret_line();
- if (text[cl].length() != 0) {
- String clipboard = _base_get_text(cl, 0, cl, text[cl].length());
- DisplayServer::get_singleton()->clipboard_set(clipboard);
- cut_copy_line = clipboard;
+ StringBuilder clipboard;
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ for (int i = caret_edit_order.size() - 1; i >= 0; i--) {
+ int caret_idx = caret_edit_order[i];
+ if (p_caret != -1 && p_caret != caret_idx) {
+ continue;
+ }
+
+ int cl = get_caret_line(caret_idx);
+ if (text[cl].length() != 0) {
+ clipboard += _base_get_text(cl, 0, cl, text[cl].length());
+ if (p_caret == -1 && i != 0) {
+ clipboard += "\n";
+ }
+ }
}
+
+ String clipboard_string = clipboard.as_string();
+ DisplayServer::get_singleton()->clipboard_set(clipboard_string);
+ cut_copy_line = clipboard_string;
}
-void TextEdit::_paste_internal() {
+void TextEdit::_paste_internal(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
if (!editable) {
return;
}
String clipboard = DisplayServer::get_singleton()->clipboard_get();
+ Vector<String> clipboad_lines = clipboard.split("\n");
+ bool insert_line_per_caret = p_caret == -1 && carets.size() > 1 && clipboad_lines.size() == carets.size();
begin_complex_operation();
- if (has_selection()) {
- delete_selection();
- } else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) {
- set_caret_column(0);
- String ins = "\n";
- clipboard += ins;
- }
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ int clipboad_line = clipboad_lines.size() - 1;
+ for (const int &i : caret_edit_order) {
+ if (p_caret != -1 && p_caret != i) {
+ continue;
+ }
+
+ if (has_selection(i)) {
+ delete_selection(i);
+ } else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) {
+ set_caret_column(0, i == 0, i);
+ String ins = "\n";
+ clipboard += ins;
+ }
+
+ if (insert_line_per_caret) {
+ clipboard = clipboad_lines[clipboad_line];
+ }
- insert_text_at_caret(clipboard);
+ insert_text_at_caret(clipboard, i);
+ clipboad_line--;
+ }
end_complex_operation();
}
-void TextEdit::_paste_primary_clipboard_internal() {
+void TextEdit::_paste_primary_clipboard_internal(int p_caret) {
+ ERR_FAIL_COND(p_caret > carets.size());
if (!is_editable() || !DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
return;
}
String paste_buffer = DisplayServer::get_singleton()->clipboard_get_primary();
- Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
- deselect();
- set_caret_line(pos.y, true, false);
- set_caret_column(pos.x);
+ if (carets.size() == 1) {
+ Point2i pos = get_line_column_at_pos(get_local_mouse_pos());
+ deselect();
+ set_caret_line(pos.y, true, false);
+ set_caret_column(pos.x);
+ }
+
if (!paste_buffer.is_empty()) {
insert_text_at_caret(paste_buffer);
}
@@ -5880,6 +6792,10 @@ Key TextEdit::_get_menu_action_accelerator(const String &p_action) {
/* Versioning */
void TextEdit::_push_current_op() {
+ if (pending_action_end) {
+ start_action(EditAction::ACTION_NONE);
+ return;
+ }
if (current_op.type == TextOperation::TYPE_NONE) {
return; // Nothing to do.
}
@@ -5981,6 +6897,7 @@ int TextEdit::_get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) con
void TextEdit::_emit_caret_changed() {
emit_signal(SNAME("caret_changed"));
caret_pos_dirty = false;
+ caret_index_edit_dirty = true;
}
void TextEdit::_reset_caret_blink_timer() {
@@ -6003,7 +6920,7 @@ void TextEdit::_toggle_draw_caret() {
}
}
-int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line) const {
+int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line, int p_column) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
int row = 0;
@@ -6016,7 +6933,7 @@ int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line) const {
}
RID text_rid = text.get_line_data(p_line)->get_line_rid(row);
- CaretInfo ts_caret = TS->shaped_text_get_carets(text_rid, caret.column);
+ CaretInfo ts_caret = TS->shaped_text_get_carets(text_rid, p_column);
if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) {
return ts_caret.l_caret.position.x;
} else {
@@ -6029,8 +6946,8 @@ void TextEdit::_click_selection_held() {
// Warning: is_mouse_button_pressed(MouseButton::LEFT) returns false for double+ clicks, so this doesn't work for MODE_WORD
// and MODE_LINE. However, moving the mouse triggers _gui_input, which calls these functions too, so that's not a huge problem.
// I'm unsure if there's an actual fix that doesn't have a ton of side effects.
- if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) {
- switch (selection.selecting_mode) {
+ if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT) && get_selection_mode() != SelectionMode::SELECTION_MODE_NONE) {
+ switch (get_selection_mode()) {
case SelectionMode::SELECTION_MODE_POINTER: {
_update_selection_mode_pointer();
} break;
@@ -6056,14 +6973,16 @@ void TextEdit::_update_selection_mode_pointer() {
Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
+ int caret_idx = carets.size() - 1;
- select(selection.selecting_line, selection.selecting_column, line, col);
+ select(carets[caret_idx].selection.selecting_line, carets[caret_idx].selection.selecting_column, line, col, caret_idx);
- set_caret_line(line, false);
- set_caret_column(col);
+ set_caret_line(line, false, true, 0, caret_idx);
+ set_caret_column(col, true, caret_idx);
queue_redraw();
click_select_held->start();
+ merge_overlapping_carets();
}
void TextEdit::_update_selection_mode_word() {
@@ -6073,6 +6992,7 @@ void TextEdit::_update_selection_mode_word() {
Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
+ int caret_idx = carets.size() - 1;
int caret_pos = CLAMP(col, 0, text[line].length());
int beg = caret_pos;
@@ -6087,25 +7007,25 @@ void TextEdit::_update_selection_mode_word() {
}
/* Initial selection. */
- if (!selection.active) {
- select(line, beg, line, end);
- selection.selecting_column = beg;
- selection.selected_word_beg = beg;
- selection.selected_word_end = end;
- selection.selected_word_origin = beg;
- set_caret_line(line, false);
- set_caret_column(end);
+ if (!has_selection(caret_idx)) {
+ select(line, beg, line, end, caret_idx);
+ carets.write[caret_idx].selection.selecting_column = beg;
+ carets.write[caret_idx].selection.selected_word_beg = beg;
+ carets.write[caret_idx].selection.selected_word_end = end;
+ carets.write[caret_idx].selection.selected_word_origin = beg;
+ set_caret_line(line, false, true, 0, caret_idx);
+ set_caret_column(end, true, caret_idx);
} else {
- if ((col <= selection.selected_word_origin && line == selection.selecting_line) || line < selection.selecting_line) {
- selection.selecting_column = selection.selected_word_end;
- select(line, beg, selection.selecting_line, selection.selected_word_end);
- set_caret_line(selection.from_line, false);
- set_caret_column(selection.from_column);
+ if ((col <= carets[caret_idx].selection.selected_word_origin && line == get_selection_line(caret_idx)) || line < get_selection_line(caret_idx)) {
+ carets.write[caret_idx].selection.selecting_column = carets[caret_idx].selection.selected_word_end;
+ select(line, beg, get_selection_line(caret_idx), carets[caret_idx].selection.selected_word_end, caret_idx);
+ set_caret_line(get_selection_from_line(caret_idx), false, true, 0, caret_idx);
+ set_caret_column(get_selection_from_column(caret_idx), true, caret_idx);
} else {
- selection.selecting_column = selection.selected_word_beg;
- select(selection.selecting_line, selection.selected_word_beg, line, end);
- set_caret_line(selection.to_line, false);
- set_caret_column(selection.to_column);
+ carets.write[caret_idx].selection.selecting_column = carets[caret_idx].selection.selected_word_beg;
+ select(get_selection_line(caret_idx), carets[caret_idx].selection.selected_word_beg, line, end, caret_idx);
+ set_caret_line(get_selection_to_line(caret_idx), false, true, 0, caret_idx);
+ set_caret_column(get_selection_to_column(caret_idx), true, caret_idx);
}
}
@@ -6116,6 +7036,7 @@ void TextEdit::_update_selection_mode_word() {
queue_redraw();
click_select_held->start();
+ merge_overlapping_carets();
}
void TextEdit::_update_selection_mode_line() {
@@ -6125,21 +7046,22 @@ void TextEdit::_update_selection_mode_line() {
Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
+ int caret_idx = carets.size() - 1;
col = 0;
- if (line < selection.selecting_line) {
+ if (line < carets[caret_idx].selection.selecting_line) {
/* Caret is above us. */
- set_caret_line(line - 1, false);
- selection.selecting_column = text[selection.selecting_line].length();
+ set_caret_line(line - 1, false, true, 0, caret_idx);
+ carets.write[caret_idx].selection.selecting_column = text[get_selection_line(caret_idx)].length();
} else {
/* Caret is below us. */
- set_caret_line(line + 1, false);
- selection.selecting_column = 0;
+ set_caret_line(line + 1, false, true, 0, caret_idx);
+ carets.write[caret_idx].selection.selecting_column = 0;
col = text[line].length();
}
- set_caret_column(0);
+ set_caret_column(0, false, caret_idx);
- select(selection.selecting_line, selection.selecting_column, line, col);
+ select(carets[caret_idx].selection.selecting_line, carets[caret_idx].selection.selecting_column, line, col, caret_idx);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) {
DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text());
}
@@ -6147,33 +7069,31 @@ void TextEdit::_update_selection_mode_line() {
queue_redraw();
click_select_held->start();
+ merge_overlapping_carets();
}
-void TextEdit::_pre_shift_selection() {
+void TextEdit::_pre_shift_selection(int p_caret) {
if (!selecting_enabled) {
return;
}
- if (!selection.active || selection.selecting_mode == SelectionMode::SELECTION_MODE_NONE) {
- selection.selecting_line = caret.line;
- selection.selecting_column = caret.column;
- selection.active = true;
+ if (!has_selection(p_caret) || get_selection_mode() == SelectionMode::SELECTION_MODE_NONE) {
+ carets.write[p_caret].selection.active = true;
+ set_selection_mode(SelectionMode::SELECTION_MODE_SHIFT, get_caret_line(p_caret), get_caret_column(p_caret), p_caret);
+ return;
}
- selection.selecting_mode = SelectionMode::SELECTION_MODE_SHIFT;
+ set_selection_mode(SelectionMode::SELECTION_MODE_SHIFT, get_selection_line(p_caret), get_selection_column(p_caret), p_caret);
}
-void TextEdit::_post_shift_selection() {
+void TextEdit::_post_shift_selection(int p_caret) {
if (!selecting_enabled) {
return;
}
- if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) {
- select(selection.selecting_line, selection.selecting_column, caret.line, caret.column);
- queue_redraw();
+ if (has_selection(p_caret) && get_selection_mode() == SelectionMode::SELECTION_MODE_SHIFT) {
+ select(get_selection_line(p_caret), get_selection_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret), p_caret);
}
-
- selection.selecting_text = true;
}
/* Line Wrapping */
@@ -6199,17 +7119,14 @@ void TextEdit::_update_wrap_at_column(bool p_force) {
_update_placeholder();
}
- _update_caret_wrap_offset();
-}
-
-void TextEdit::_update_caret_wrap_offset() {
+ // Update viewport.
int first_vis_line = get_first_visible_line();
if (is_line_wrapped(first_vis_line)) {
- caret.wrap_ofs = MIN(caret.wrap_ofs, get_line_wrap_count(first_vis_line));
+ first_visible_line_wrap_ofs = MIN(first_visible_line_wrap_ofs, get_line_wrap_count(first_vis_line));
} else {
- caret.wrap_ofs = 0;
+ first_visible_line_wrap_ofs = 0;
}
- set_line_as_first_visible(caret.line_ofs, caret.wrap_ofs);
+ set_line_as_first_visible(first_visible_line, first_visible_line_wrap_ofs);
}
/* Viewport. */
@@ -6258,8 +7175,8 @@ void TextEdit::_update_scrollbars() {
set_v_scroll(get_v_scroll());
} else {
- caret.line_ofs = 0;
- caret.wrap_ofs = 0;
+ first_visible_line = 0;
+ first_visible_line_wrap_ofs = 0;
v_scroll->set_value(0);
v_scroll->set_max(0);
v_scroll->hide();
@@ -6269,15 +7186,15 @@ void TextEdit::_update_scrollbars() {
h_scroll->show();
h_scroll->set_max(total_width);
h_scroll->set_page(visible_width);
- if (caret.x_ofs > (total_width - visible_width)) {
- caret.x_ofs = (total_width - visible_width);
+ if (first_visible_col > (total_width - visible_width)) {
+ first_visible_col = (total_width - visible_width);
}
- if (fabs(h_scroll->get_value() - (double)caret.x_ofs) >= 1) {
- h_scroll->set_value(caret.x_ofs);
+ if (fabs(h_scroll->get_value() - (double)first_visible_col) >= 1) {
+ h_scroll->set_value(first_visible_col);
}
} else {
- caret.x_ofs = 0;
+ first_visible_col = 0;
h_scroll->set_value(0);
h_scroll->set_max(0);
h_scroll->hide();
@@ -6306,7 +7223,7 @@ void TextEdit::_scroll_moved(double p_to_val) {
}
if (h_scroll->is_visible_in_tree()) {
- caret.x_ofs = h_scroll->get_value();
+ first_visible_col = h_scroll->get_value();
}
if (v_scroll->is_visible_in_tree()) {
// Set line ofs and wrap ofs.
@@ -6329,8 +7246,8 @@ void TextEdit::_scroll_moved(double p_to_val) {
int wi = line_wrap_amount - (sc - v_scroll_i - 1);
wi = CLAMP(wi, 0, line_wrap_amount);
- caret.line_ofs = n_line;
- caret.wrap_ofs = wi;
+ first_visible_line = n_line;
+ first_visible_line_wrap_ofs = wi;
}
queue_redraw();
}
@@ -6411,16 +7328,18 @@ void TextEdit::_scroll_lines_up() {
set_v_scroll(get_v_scroll() - 1);
// Adjust the caret to viewport.
- if (!selection.active) {
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
+ for (int i = 0; i < carets.size(); i++) {
+ if (has_selection(i)) {
+ continue;
+ }
+
int last_vis_line = get_last_full_visible_line();
int last_vis_wrap = get_last_full_visible_line_wrap_index();
-
- if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
- set_caret_line(last_vis_line, false, false, last_vis_wrap);
+ if (get_caret_line(i) > last_vis_line || (get_caret_line(i) == last_vis_line && get_caret_wrap_index(i) > last_vis_wrap)) {
+ set_caret_line(last_vis_line, false, false, last_vis_wrap, i);
}
}
+ merge_overlapping_carets();
}
void TextEdit::_scroll_lines_down() {
@@ -6431,16 +7350,17 @@ void TextEdit::_scroll_lines_down() {
set_v_scroll(get_v_scroll() + 1);
// Adjust the caret to viewport.
- if (!selection.active) {
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
- int first_vis_line = get_first_visible_line();
- int first_vis_wrap = caret.wrap_ofs;
+ for (int i = 0; i < carets.size(); i++) {
+ if (has_selection(i)) {
+ continue;
+ }
- if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
- set_caret_line(first_vis_line, false, false, first_vis_wrap);
+ int first_vis_line = get_first_visible_line();
+ if (get_caret_line(i) < first_vis_line || (get_caret_line(i) == first_vis_line && get_caret_wrap_index(i) < first_visible_line_wrap_ofs)) {
+ set_caret_line(first_vis_line, false, false, first_visible_line_wrap_ofs, i);
}
}
+ merge_overlapping_carets();
}
// Minimap
@@ -6577,6 +7497,8 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r
op.version = ++version;
op.chain_forward = false;
op.chain_backward = false;
+ op.start_carets = carets;
+ op.end_carets = carets;
// See if it should just be set as current op.
if (current_op.type != op.type) {
@@ -6599,6 +7521,7 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r
current_op.to_column = retchar;
current_op.to_line = retline;
current_op.version = op.version;
+ current_op.end_carets = carets;
}
void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) {
@@ -6606,10 +7529,10 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i
idle_detect->start();
}
- String text;
+ String txt;
if (undo_enabled) {
_clear_redo();
- text = _base_get_text(p_from_line, p_from_column, p_to_line, p_to_column);
+ txt = _base_get_text(p_from_line, p_from_column, p_to_line, p_to_column);
}
_base_remove_text(p_from_line, p_from_column, p_to_line, p_to_column);
@@ -6625,10 +7548,12 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i
op.from_column = p_from_column;
op.to_line = p_to_line;
op.to_column = p_to_column;
- op.text = text;
+ op.text = txt;
op.version = ++version;
op.chain_forward = false;
op.chain_backward = false;
+ op.start_carets = carets;
+ op.end_carets = carets;
// See if it should just be set as current op.
if (current_op.type != op.type) {
@@ -6640,9 +7565,10 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i
// See if it can be merged.
if (current_op.from_line == p_to_line && current_op.from_column == p_to_column) {
// Backspace or similar.
- current_op.text = text + current_op.text;
+ current_op.text = txt + current_op.text;
current_op.from_line = p_from_line;
current_op.from_column = p_from_column;
+ current_op.end_carets = carets;
return; // Update current op.
}
@@ -6692,7 +7618,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
r_end_line = p_line + substrings.size() - 1;
r_end_column = text[r_end_line].length() - postinsert_text.length();
- TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text.get_line_data(r_end_line)->get_rid(), (r_end_line == p_line) ? caret.column : 0, r_end_column);
+ TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text.get_line_data(r_end_line)->get_rid(), (r_end_line == p_line) ? carets[0].column : 0, r_end_column);
if (dir != TextServer::DIRECTION_AUTO) {
input_direction = (TextDirection)dir;
}
@@ -6754,6 +7680,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
TextEdit::TextEdit(const String &p_placeholder) {
placeholder_data_buf.instantiate();
+ carets.push_back(Caret());
clear();
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a8da878ede..263a36aba8 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -42,6 +42,14 @@ class TextEdit : public Control {
GDCLASS(TextEdit, Control);
public:
+ /* Edit Actions. */
+ enum EditAction {
+ ACTION_NONE,
+ ACTION_TYPING,
+ ACTION_BACKSPACE,
+ ACTION_DELETE,
+ };
+
/* Caret. */
enum CaretType {
CARET_TYPE_LINE,
@@ -299,12 +307,15 @@ private:
Key _get_menu_action_accelerator(const String &p_action);
/* Versioning */
+ struct Caret;
struct TextOperation {
enum Type {
TYPE_NONE,
TYPE_INSERT,
TYPE_REMOVE
};
+ Vector<Caret> start_carets;
+ Vector<Caret> end_carets;
Type type = TYPE_NONE;
int from_line = 0;
@@ -321,6 +332,10 @@ private:
bool undo_enabled = true;
int undo_stack_max_size = 50;
+ EditAction current_action = EditAction::ACTION_NONE;
+ bool pending_action_end = false;
+ bool in_action = false;
+
int complex_operation_count = 0;
bool next_operation_is_complex = false;
@@ -361,19 +376,39 @@ private:
int _get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
/* Caret. */
+ struct Selection {
+ bool active = false;
+ bool shiftclick_left = false;
+
+ int selecting_line = 0;
+ int selecting_column = 0;
+ int selected_word_beg = 0;
+ int selected_word_end = 0;
+ int selected_word_origin = 0;
+
+ int from_line = 0;
+ int from_column = 0;
+ int to_line = 0;
+ int to_column = 0;
+ };
+
struct Caret {
+ Selection selection;
+
Point2 draw_pos;
bool visible = false;
int last_fit_x = 0;
int line = 0;
int column = 0;
- int x_ofs = 0;
- int line_ofs = 0;
- int wrap_ofs = 0;
- } caret;
+ };
+
+ // Vector containing all the carets, index '0' is the "main caret" and should never be removed.
+ Vector<Caret> carets;
+ Vector<int> caret_index_edit_order;
bool setting_caret_line = false;
bool caret_pos_dirty = false;
+ bool caret_index_edit_dirty = true;
Color caret_color = Color(1, 1, 1);
Color caret_background_color = Color(0, 0, 0);
@@ -389,6 +424,8 @@ private:
bool caret_mid_grapheme_enabled = true;
+ bool multi_carets_enabled = true;
+
bool drag_action = false;
bool drag_caret_force_displayed = false;
@@ -397,37 +434,20 @@ private:
void _reset_caret_blink_timer();
void _toggle_draw_caret();
- int _get_column_x_offset_for_line(int p_char, int p_line) const;
+ int _get_column_x_offset_for_line(int p_char, int p_line, int p_column) const;
/* Selection. */
- struct Selection {
- SelectionMode selecting_mode = SelectionMode::SELECTION_MODE_NONE;
- int selecting_line = 0;
- int selecting_column = 0;
- int selected_word_beg = 0;
- int selected_word_end = 0;
- int selected_word_origin = 0;
- bool selecting_text = false;
-
- bool active = false;
-
- int from_line = 0;
- int from_column = 0;
- int to_line = 0;
- int to_column = 0;
-
- bool shiftclick_left = false;
- bool drag_attempt = false;
- } selection;
+ SelectionMode selecting_mode = SelectionMode::SELECTION_MODE_NONE;
bool selecting_enabled = true;
bool deselect_on_focus_loss_enabled = true;
bool drag_and_drop_selection_enabled = true;
- Color font_selected_color = Color(1, 1, 1);
+ Color font_selected_color = Color(0, 0, 0, 0);
Color selection_color = Color(1, 1, 1);
- bool override_selected_font_color = false;
+ bool use_selected_font_color = false;
+ bool selection_drag_attempt = false;
bool dragging_selection = false;
Timer *click_select_held = nullptr;
@@ -439,8 +459,8 @@ private:
void _update_selection_mode_word();
void _update_selection_mode_line();
- void _pre_shift_selection();
- void _post_shift_selection();
+ void _pre_shift_selection(int p_caret);
+ void _post_shift_selection(int p_caret);
/* Line wrapping. */
LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE;
@@ -450,8 +470,6 @@ private:
void _update_wrap_at_column(bool p_force = false);
- void _update_caret_wrap_offset();
-
/* Viewport. */
HScrollBar *h_scroll = nullptr;
VScrollBar *v_scroll = nullptr;
@@ -466,6 +484,10 @@ private:
float v_scroll_speed = 80.0;
// Scrolling.
+ int first_visible_line = 0;
+ int first_visible_line_wrap_ofs = 0;
+ int first_visible_col = 0;
+
bool scrolling = false;
bool updating_scrolls = false;
@@ -575,6 +597,10 @@ private:
void _delete(bool p_word = false, bool p_all_to_right = false);
void _move_caret_document_start(bool p_select);
void _move_caret_document_end(bool p_select);
+ bool _should_remove_secondary_carets();
+
+ // Used in add_caret_at_carets
+ void _get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x = -1) const;
protected:
void _notification(int p_what);
@@ -583,6 +609,17 @@ protected:
/* Internal API for CodeEdit, pending public API. */
// brace matching
+ struct BraceMatchingData {
+ int open_match_line = -1;
+ int open_match_column = -1;
+ bool open_matching = false;
+ bool open_mismatch = false;
+ int close_match_line = -1;
+ int close_match_column = -1;
+ bool close_matching = false;
+ bool close_mismatch = false;
+ };
+
bool highlight_matching_braces_enabled = false;
Color brace_mismatch_color;
@@ -607,20 +644,20 @@ protected:
/* Text manipulation */
// Overridable actions
- virtual void _handle_unicode_input_internal(const uint32_t p_unicode);
- virtual void _backspace_internal();
+ virtual void _handle_unicode_input_internal(const uint32_t p_unicode, int p_caret);
+ virtual void _backspace_internal(int p_caret);
- virtual void _cut_internal();
- virtual void _copy_internal();
- virtual void _paste_internal();
- virtual void _paste_primary_clipboard_internal();
+ virtual void _cut_internal(int p_caret);
+ virtual void _copy_internal(int p_caret);
+ virtual void _paste_internal(int p_caret);
+ virtual void _paste_primary_clipboard_internal(int p_caret);
- GDVIRTUAL1(_handle_unicode_input, int)
- GDVIRTUAL0(_backspace)
- GDVIRTUAL0(_cut)
- GDVIRTUAL0(_copy)
- GDVIRTUAL0(_paste)
- GDVIRTUAL0(_paste_primary_clipboard)
+ GDVIRTUAL2(_handle_unicode_input, int, int)
+ GDVIRTUAL1(_backspace, int)
+ GDVIRTUAL1(_cut, int)
+ GDVIRTUAL1(_copy, int)
+ GDVIRTUAL1(_paste, int)
+ GDVIRTUAL1(_paste_primary_clipboard, int)
public:
/* General overrides. */
@@ -696,7 +733,7 @@ public:
void swap_lines(int p_from_line, int p_to_line);
void insert_line_at(int p_at, const String &p_text);
- void insert_text_at_caret(const String &p_text);
+ void insert_text_at_caret(const String &p_text, int p_caret = -1);
void remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
@@ -705,13 +742,13 @@ public:
Point2i get_next_visible_line_index_offset_from(int p_line_from, int p_wrap_index_from, int p_visible_amount) const;
// Overridable actions
- void handle_unicode_input(const uint32_t p_unicode);
- void backspace();
+ void handle_unicode_input(const uint32_t p_unicode, int p_caret = -1);
+ void backspace(int p_caret = -1);
- void cut();
- void copy();
- void paste();
- void paste_primary_clipboard();
+ void cut(int p_caret = -1);
+ void copy(int p_caret = -1);
+ void paste(int p_caret = -1);
+ void paste_primary_clipboard(int p_caret = -1);
// Context menu.
PopupMenu *get_menu() const;
@@ -719,6 +756,10 @@ public:
void menu_option(int p_option);
/* Versioning */
+ void start_action(EditAction p_action);
+ void end_action();
+ EditAction get_current_action() const;
+
void begin_complex_operation();
void end_complex_operation();
@@ -753,7 +794,7 @@ public:
int get_minimap_line_at_pos(const Point2i &p_pos) const;
bool is_dragging_cursor() const;
- bool is_mouse_over_selection(bool p_edges = true) const;
+ bool is_mouse_over_selection(bool p_edges = true, int p_caret = -1) const;
/* Caret */
void set_caret_type(CaretType p_type);
@@ -771,18 +812,31 @@ public:
void set_caret_mid_grapheme_enabled(const bool p_enabled);
bool is_caret_mid_grapheme_enabled() const;
- bool is_caret_visible() const;
- Point2 get_caret_draw_pos() const;
+ void set_multiple_carets_enabled(bool p_enabled);
+ bool is_multiple_carets_enabled() const;
+
+ int add_caret(int p_line, int p_col);
+ void remove_caret(int p_caret);
+ void remove_secondary_carets();
+ void merge_overlapping_carets();
+ int get_caret_count() const;
+ void add_caret_at_carets(bool p_below);
- void set_caret_line(int p_line, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
- int get_caret_line() const;
+ Vector<int> get_caret_index_edit_order();
+ void adjust_carets_after_edit(int p_caret, int p_from_line, int p_from_col, int p_to_line, int p_to_col);
- void set_caret_column(int p_col, bool p_adjust_viewport = true);
- int get_caret_column() const;
+ bool is_caret_visible(int p_caret = 0) const;
+ Point2 get_caret_draw_pos(int p_caret = 0) const;
- int get_caret_wrap_index() const;
+ void set_caret_line(int p_line, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0, int p_caret = 0);
+ int get_caret_line(int p_caret = 0) const;
- String get_word_under_caret() const;
+ void set_caret_column(int p_col, bool p_adjust_viewport = true, int p_caret = 0);
+ int get_caret_column(int p_caret = 0) const;
+
+ int get_caret_wrap_index(int p_caret = 0) const;
+
+ String get_word_under_caret(int p_caret = -1) const;
/* Selection. */
void set_selecting_enabled(const bool p_enabled);
@@ -797,27 +851,28 @@ public:
void set_override_selected_font_color(bool p_override_selected_font_color);
bool is_overriding_selected_font_color() const;
- void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1);
+ void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1, int p_caret = 0);
SelectionMode get_selection_mode() const;
void select_all();
- void select_word_under_caret();
- void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column);
+ void select_word_under_caret(int p_caret = -1);
+ void add_selection_for_next_occurrence();
+ void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0);
- bool has_selection() const;
+ bool has_selection(int p_caret = -1) const;
- String get_selected_text() const;
+ String get_selected_text(int p_caret = -1);
- int get_selection_line() const;
- int get_selection_column() const;
+ int get_selection_line(int p_caret = 0) const;
+ int get_selection_column(int p_caret = 0) const;
- int get_selection_from_line() const;
- int get_selection_from_column() const;
- int get_selection_to_line() const;
- int get_selection_to_column() const;
+ int get_selection_from_line(int p_caret = 0) const;
+ int get_selection_from_column(int p_caret = 0) const;
+ int get_selection_to_line(int p_caret = 0) const;
+ int get_selection_to_column(int p_caret = 0) const;
- void deselect();
- void delete_selection();
+ void deselect(int p_caret = -1);
+ void delete_selection(int p_caret = -1);
/* Line wrapping. */
void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode);
@@ -837,6 +892,9 @@ public:
void set_scroll_past_end_of_file_enabled(const bool p_enabled);
bool is_scroll_past_end_of_file_enabled() const;
+ VScrollBar *get_v_scroll_bar() const;
+ HScrollBar *get_h_scroll_bar() const;
+
void set_v_scroll(double p_scroll);
double get_v_scroll() const;
@@ -866,8 +924,8 @@ public:
int get_total_visible_line_count() const;
// Auto Adjust
- void adjust_viewport_to_caret();
- void center_viewport_to_caret();
+ void adjust_viewport_to_caret(int p_caret = 0);
+ void center_viewport_to_caret(int p_caret = 0);
// Minimap
void set_draw_minimap(bool p_enabled);
@@ -949,6 +1007,7 @@ public:
TextEdit(const String &p_placeholder = String());
};
+VARIANT_ENUM_CAST(TextEdit::EditAction);
VARIANT_ENUM_CAST(TextEdit::CaretType);
VARIANT_ENUM_CAST(TextEdit::LineWrappingMode);
VARIANT_ENUM_CAST(TextEdit::SelectionMode);
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index a9982b3ece..48c6dc5cfc 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -510,18 +510,38 @@ void TextureProgressBar::_notification(int p_what) {
}
pts.append(to);
+ Ref<AtlasTexture> atlas_progress = progress;
+ bool valid_atlas_progress = atlas_progress.is_valid() && atlas_progress->get_atlas().is_valid();
+ Rect2 region_rect;
+ Size2 atlas_size;
+ if (valid_atlas_progress) {
+ region_rect = atlas_progress->get_region();
+ atlas_size = atlas_progress->get_atlas()->get_size();
+ }
+
Vector<Point2> uvs;
Vector<Point2> points;
- uvs.push_back(get_relative_center());
- points.push_back(progress_offset + s * get_relative_center());
for (int i = 0; i < pts.size(); i++) {
Point2 uv = unit_val_to_uv(pts[i]);
if (uvs.find(uv) >= 0) {
continue;
}
- uvs.push_back(uv);
points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y));
+ if (valid_atlas_progress) {
+ uv.x = Math::remap(uv.x, 0, 1, region_rect.position.x / atlas_size.x, (region_rect.position.x + region_rect.size.x) / atlas_size.x);
+ uv.y = Math::remap(uv.y, 0, 1, region_rect.position.y / atlas_size.y, (region_rect.position.y + region_rect.size.y) / atlas_size.y);
+ }
+ uvs.push_back(uv);
+ }
+
+ Point2 center_point = get_relative_center();
+ points.push_back(progress_offset + s * center_point);
+ if (valid_atlas_progress) {
+ center_point.x = Math::remap(center_point.x, 0, 1, region_rect.position.x / atlas_size.x, (region_rect.position.x + region_rect.size.x) / atlas_size.x);
+ center_point.y = Math::remap(center_point.y, 0, 1, region_rect.position.y / atlas_size.y, (region_rect.position.y + region_rect.size.y) / atlas_size.y);
}
+ uvs.push_back(center_point);
+
Vector<Color> colors;
colors.push_back(tint_progress);
draw_polygon(points, colors, uvs, progress);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index f82a853e56..6f9a9a5141 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -738,9 +738,9 @@ TreeItem *TreeItem::get_first_child() const {
TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
TreeItem *current = this;
- TreeItem *prev = current->get_prev();
+ TreeItem *prev_item = current->get_prev();
- if (!prev) {
+ if (!prev_item) {
current = current->parent;
if (current == tree->root && tree->hide_root) {
return nullptr;
@@ -757,7 +757,7 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
}
}
} else {
- current = prev;
+ current = prev_item;
while (!current->collapsed && current->first_child) {
//go to the very end
@@ -773,16 +773,16 @@ TreeItem *TreeItem::_get_prev_visible(bool p_wrap) {
TreeItem *TreeItem::get_prev_visible(bool p_wrap) {
TreeItem *loop = this;
- TreeItem *prev = this->_get_prev_visible(p_wrap);
- while (prev && !prev->is_visible()) {
- prev = prev->_get_prev_visible(p_wrap);
- if (prev == loop) {
+ TreeItem *prev_item = this->_get_prev_visible(p_wrap);
+ while (prev_item && !prev_item->is_visible()) {
+ prev_item = prev_item->_get_prev_visible(p_wrap);
+ if (prev_item == loop) {
// Check that we haven't looped all the way around to the start.
- prev = nullptr;
+ prev_item = nullptr;
break;
}
}
- return prev;
+ return prev_item;
}
TreeItem *TreeItem::_get_next_visible(bool p_wrap) {
@@ -814,16 +814,16 @@ TreeItem *TreeItem::_get_next_visible(bool p_wrap) {
TreeItem *TreeItem::get_next_visible(bool p_wrap) {
TreeItem *loop = this;
- TreeItem *next = this->_get_next_visible(p_wrap);
- while (next && !next->is_visible()) {
- next = next->_get_next_visible(p_wrap);
- if (next == loop) {
+ TreeItem *next_item = this->_get_next_visible(p_wrap);
+ while (next_item && !next_item->is_visible()) {
+ next_item = next_item->_get_next_visible(p_wrap);
+ if (next_item == loop) {
// Check that we haven't looped all the way around to the start.
- next = nullptr;
+ next_item = nullptr;
break;
}
}
- return next;
+ return next_item;
}
TreeItem *TreeItem::get_child(int p_idx) {
@@ -1163,7 +1163,7 @@ bool TreeItem::is_editable(int p_column) {
void TreeItem::set_custom_color(int p_column, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
- if (cells[p_column].custom_color == true) {
+ if (cells[p_column].custom_color && cells[p_column].color == p_color) {
return;
}
@@ -1317,8 +1317,8 @@ bool TreeItem::is_folding_disabled() const {
Size2 TreeItem::get_minimum_size(int p_column) {
ERR_FAIL_INDEX_V(p_column, cells.size(), Size2());
- Tree *tree = get_tree();
- ERR_FAIL_COND_V(!tree, Size2());
+ Tree *parent_tree = get_tree();
+ ERR_FAIL_COND_V(!parent_tree, Size2());
const TreeItem::Cell &cell = cells[p_column];
@@ -1328,7 +1328,7 @@ Size2 TreeItem::get_minimum_size(int p_column) {
// Text.
if (!cell.text.is_empty()) {
if (cell.dirty) {
- tree->update_item_cell(this, p_column);
+ parent_tree->update_item_cell(this, p_column);
}
Size2 text_size = cell.text_buf->get_size();
size.width += text_size.width;
@@ -1337,14 +1337,14 @@ Size2 TreeItem::get_minimum_size(int p_column) {
// Icon.
if (cell.mode == CELL_MODE_CHECK) {
- size.width += tree->theme_cache.checked->get_width() + tree->theme_cache.hseparation;
+ size.width += parent_tree->theme_cache.checked->get_width() + parent_tree->theme_cache.hseparation;
}
if (cell.icon.is_valid()) {
Size2i icon_size = cell.get_icon_size();
if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) {
icon_size.width = cell.icon_max_w;
}
- size.width += icon_size.width + tree->theme_cache.hseparation;
+ size.width += icon_size.width + parent_tree->theme_cache.hseparation;
size.height = MAX(size.height, icon_size.height);
}
@@ -1352,13 +1352,13 @@ Size2 TreeItem::get_minimum_size(int p_column) {
for (int i = 0; i < cell.buttons.size(); i++) {
Ref<Texture2D> texture = cell.buttons[i].texture;
if (texture.is_valid()) {
- Size2 button_size = texture->get_size() + tree->theme_cache.button_pressed->get_minimum_size();
+ Size2 button_size = texture->get_size() + parent_tree->theme_cache.button_pressed->get_minimum_size();
size.width += button_size.width;
size.height = MAX(size.height, button_size.height);
}
}
if (cell.buttons.size() >= 2) {
- size.width += (cell.buttons.size() - 1) * tree->theme_cache.button_margin;
+ size.width += (cell.buttons.size() - 1) * parent_tree->theme_cache.button_margin;
}
cells.write[p_column].cached_minimum_size = size;
@@ -1504,6 +1504,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button);
ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button);
ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
+ ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_idx", "color"), &TreeItem::set_button_color);
ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text);
@@ -3190,7 +3191,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
bool is_command = k.is_valid() && k->is_command_or_control_pressed();
- if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_right", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3208,7 +3209,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
} else {
_go_right();
}
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3228,21 +3229,21 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
_go_left();
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed() && !is_command) {
+ } else if (p_event->is_action("ui_up", true) && p_event->is_pressed() && !is_command) {
if (!cursor_can_exit_tree) {
accept_event();
}
_go_up();
- } else if (p_event->is_action("ui_down") && p_event->is_pressed() && !is_command) {
+ } else if (p_event->is_action("ui_down", true) && p_event->is_pressed() && !is_command) {
if (!cursor_can_exit_tree) {
accept_event();
}
_go_down();
- } else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_page_down", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3280,7 +3281,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
ensure_cursor_is_visible();
- } else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_page_up", true) && p_event->is_pressed()) {
if (!cursor_can_exit_tree) {
accept_event();
}
@@ -3317,7 +3318,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
prev->select(selected_col);
}
ensure_cursor_is_visible();
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) {
if (selected_item) {
//bring up editor if possible
if (!edit_selected()) {
@@ -3326,7 +3327,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
}
accept_event();
- } else if (p_event->is_action("ui_select") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_select", true) && p_event->is_pressed()) {
if (select_mode == SELECT_MULTI) {
if (!selected_item) {
return;
diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp
index 3b7f499a07..e8e3e3e556 100644
--- a/scene/gui/view_panner.cpp
+++ b/scene/gui/view_panner.cpp
@@ -38,7 +38,9 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect)
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
Vector2 scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP));
- if (scroll_vec != Vector2()) {
+ // Moving the scroll wheel sends two events: one with pressed as true,
+ // and one with pressed as false. Make sure we only process one of them.
+ if (scroll_vec != Vector2() && mb->is_pressed()) {
if (control_scheme == SCROLL_PANS) {
if (mb->is_ctrl_pressed()) {
scroll_vec.y *= mb->get_factor();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 05d86f77f2..3bf4e95e68 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -168,9 +168,6 @@ Transform2D CanvasItem::get_screen_transform() const {
}
Transform2D CanvasItem::get_global_transform() const {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
-#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
if (pi) {
@@ -222,6 +219,7 @@ void CanvasItem::_enter_canvas() {
}
RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, canvas);
+ RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, visibility_layer);
canvas_group = "root_canvas" + itos(canvas.get_id());
@@ -239,6 +237,7 @@ void CanvasItem::_enter_canvas() {
canvas_layer = parent->canvas_layer;
RenderingServer::get_singleton()->canvas_item_set_parent(canvas_item, parent->get_canvas_item());
RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index());
+ RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, visibility_layer);
}
pending_update = false;
@@ -980,14 +979,19 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_canvas_position_local", "screen_point"), &CanvasItem::make_canvas_position_local);
ClassDB::bind_method(D_METHOD("make_input_local", "event"), &CanvasItem::make_input_local);
+ ClassDB::bind_method(D_METHOD("set_visibility_layer", "layer"), &CanvasItem::set_visibility_layer);
+ ClassDB::bind_method(D_METHOD("get_visibility_layer"), &CanvasItem::get_visibility_layer);
+ ClassDB::bind_method(D_METHOD("set_visibility_layer_bit", "layer", "enabled"), &CanvasItem::set_visibility_layer_bit);
+ ClassDB::bind_method(D_METHOD("get_visibility_layer_bit", "layer"), &CanvasItem::get_visibility_layer_bit);
+
ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &CanvasItem::set_texture_filter);
ClassDB::bind_method(D_METHOD("get_texture_filter"), &CanvasItem::get_texture_filter);
ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat);
- ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
- ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
+ ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode);
+ ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode);
GDVIRTUAL_BIND(_draw);
@@ -997,8 +1001,9 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only,Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "visibility_layer", PROPERTY_HINT_LAYERS_2D_RENDER), "set_visibility_layer", "get_visibility_layer");
ADD_GROUP("Texture", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
@@ -1035,6 +1040,11 @@ void CanvasItem::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR);
BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW);
+ BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX);
}
Transform2D CanvasItem::get_canvas_transform() const {
@@ -1092,7 +1102,30 @@ int CanvasItem::get_canvas_layer() const {
}
}
-void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+void CanvasItem::set_visibility_layer(uint32_t p_visibility_layer) {
+ visibility_layer = p_visibility_layer;
+ RenderingServer::get_singleton()->canvas_item_set_visibility_layer(canvas_item, p_visibility_layer);
+}
+
+uint32_t CanvasItem::get_visibility_layer() const {
+ return visibility_layer;
+}
+
+void CanvasItem::set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_visibility_layer, 32);
+ if (p_enable) {
+ set_visibility_layer(visibility_layer | (1 << p_visibility_layer));
+ } else {
+ set_visibility_layer(visibility_layer & (~(1 << p_visibility_layer)));
+ }
+}
+
+bool CanvasItem::get_visibility_layer_bit(uint32_t p_visibility_layer) const {
+ ERR_FAIL_INDEX_V(p_visibility_layer, 32, false);
+ return (visibility_layer & (1 << p_visibility_layer));
+}
+
+void CanvasItem::_refresh_texture_filter_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1107,6 +1140,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
} else {
texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter);
}
+}
+
+void CanvasItem::_update_texture_filter_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_filter_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache);
queue_redraw();
@@ -1133,7 +1174,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const {
return texture_filter;
}
-void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+void CanvasItem::_refresh_texture_repeat_cache() {
if (!is_inside_tree()) {
return;
}
@@ -1148,6 +1189,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
} else {
texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat);
}
+}
+
+void CanvasItem::_update_texture_repeat_changed(bool p_propagate) {
+ if (!is_inside_tree()) {
+ return;
+ }
+ _refresh_texture_repeat_cache();
+
RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache);
queue_redraw();
if (p_propagate) {
@@ -1169,26 +1218,39 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) {
notify_property_list_changed();
}
-void CanvasItem::set_clip_children(bool p_enabled) {
- if (clip_children == p_enabled) {
+void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) {
+ ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX);
+
+ if (clip_children_mode == p_clip_mode) {
return;
}
- clip_children = p_enabled;
+ clip_children_mode = p_clip_mode;
if (Object::cast_to<CanvasGroup>(this) != nullptr) {
//avoid accidental bugs, make this not work on CanvasGroup
return;
}
- RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED);
+
+ RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode));
}
-bool CanvasItem::is_clipping_children() const {
- return clip_children;
+CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const {
+ return clip_children_mode;
}
CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const {
return texture_repeat;
}
+CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() {
+ _refresh_texture_filter_cache();
+ return (TextureFilter)texture_filter_cache;
+}
+
+CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() {
+ _refresh_texture_repeat_cache();
+ return (TextureRepeat)texture_repeat_cache;
+}
+
CanvasItem::CanvasItem() :
xform_change(this) {
canvas_item = RenderingServer::get_singleton()->canvas_item_create();
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index b80289fdb4..4e78a175dc 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -66,8 +66,16 @@ public:
TEXTURE_REPEAT_MAX,
};
+ enum ClipChildrenMode {
+ CLIP_CHILDREN_DISABLED,
+ CLIP_CHILDREN_ONLY,
+ CLIP_CHILDREN_AND_DRAW,
+ CLIP_CHILDREN_MAX,
+ };
+
private:
- mutable SelfList<Node> xform_change;
+ mutable SelfList<Node>
+ xform_change;
RID canvas_item;
StringName canvas_group;
@@ -81,11 +89,11 @@ private:
List<CanvasItem *>::Element *C = nullptr;
int light_mask = 1;
+ uint32_t visibility_layer = 1;
Window *window = nullptr;
bool visible = true;
bool parent_visible_in_tree = false;
- bool clip_children = false;
bool pending_update = false;
bool top_level = false;
bool drawing = false;
@@ -95,6 +103,8 @@ private:
bool notify_local_transform = false;
bool notify_transform = false;
+ ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
+
RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE;
@@ -121,7 +131,9 @@ private:
static CanvasItem *current_item_drawn;
friend class Viewport;
+ void _refresh_texture_repeat_cache();
void _update_texture_repeat_changed(bool p_propagate);
+ void _refresh_texture_filter_cache();
void _update_texture_filter_changed(bool p_propagate);
protected:
@@ -200,8 +212,8 @@ public:
void queue_redraw();
void move_to_front();
- void set_clip_children(bool p_enabled);
- bool is_clipping_children() const;
+ void set_clip_children_mode(ClipChildrenMode p_clip_mode);
+ ClipChildrenMode get_clip_children_mode() const;
virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
@@ -212,6 +224,12 @@ public:
void set_self_modulate(const Color &p_self_modulate);
Color get_self_modulate() const;
+ void set_visibility_layer(uint32_t p_visibility_layer);
+ uint32_t get_visibility_layer() const;
+
+ void set_visibility_layer_bit(uint32_t p_visibility_layer, bool p_enable);
+ bool get_visibility_layer_bit(uint32_t p_visibility_layer) const;
+
/* DRAWING API */
void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, real_t p_dash = 2.0);
@@ -310,6 +328,9 @@ public:
virtual void set_texture_repeat(TextureRepeat p_texture_repeat);
TextureRepeat get_texture_repeat() const;
+ TextureFilter get_texture_filter_in_tree();
+ TextureRepeat get_texture_repeat_in_tree();
+
// Used by control nodes to retrieve the parent's anchorable area
virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); };
@@ -321,6 +342,7 @@ public:
VARIANT_ENUM_CAST(CanvasItem::TextureFilter)
VARIANT_ENUM_CAST(CanvasItem::TextureRepeat)
+VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode)
class CanvasTexture : public Texture2D {
GDCLASS(CanvasTexture, Texture2D);
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 214efe432b..be5788739b 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -38,6 +38,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid()) {
RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index());
+ vp->_gui_set_root_order_dirty();
}
}
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index 6dd83e4636..56e719968b 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -100,7 +100,7 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene
}
if (p_replace) {
- queue_delete();
+ queue_free();
base->remove_child(this);
}
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index 2d2103f031..946929aa89 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -329,11 +329,9 @@ void MultiplayerAPI::_bind_methods() {
/// MultiplayerAPIExtension
Error MultiplayerAPIExtension::poll() {
- int err;
- if (GDVIRTUAL_CALL(_poll, err)) {
- return (Error)err;
- }
- return OK;
+ int err = OK;
+ GDVIRTUAL_CALL(_poll, err);
+ return (Error)err;
}
void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) {
@@ -342,26 +340,20 @@ void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p
Ref<MultiplayerPeer> MultiplayerAPIExtension::get_multiplayer_peer() {
Ref<MultiplayerPeer> peer;
- if (GDVIRTUAL_CALL(_get_multiplayer_peer, peer)) {
- return peer;
- }
- return nullptr;
+ GDVIRTUAL_CALL(_get_multiplayer_peer, peer);
+ return peer;
}
int MultiplayerAPIExtension::get_unique_id() {
- int id;
- if (GDVIRTUAL_CALL(_get_unique_id, id)) {
- return id;
- }
- return 1;
+ int id = 1;
+ GDVIRTUAL_CALL(_get_unique_id, id);
+ return id;
}
Vector<int> MultiplayerAPIExtension::get_peer_ids() {
Vector<int> ids;
- if (GDVIRTUAL_CALL(_get_peer_ids, ids)) {
- return ids;
- }
- return Vector<int>();
+ GDVIRTUAL_CALL(_get_peer_ids, ids);
+ return ids;
}
Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
@@ -372,35 +364,27 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
for (int i = 0; i < p_argcount; i++) {
args.push_back(*p_arg[i]);
}
- int ret;
- if (GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret)) {
- return (Error)ret;
- }
- return FAILED;
+ int ret = FAILED;
+ GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret);
+ return (Error)ret;
}
int MultiplayerAPIExtension::get_remote_sender_id() {
- int id;
- if (GDVIRTUAL_CALL(_get_remote_sender_id, id)) {
- return id;
- }
- return 0;
+ int id = 0;
+ GDVIRTUAL_CALL(_get_remote_sender_id, id);
+ return id;
}
Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) {
- int err;
- if (GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err)) {
- return (Error)err;
- }
- return ERR_UNAVAILABLE;
+ int err = ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err);
+ return (Error)err;
}
Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) {
- int err;
- if (GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err)) {
- return (Error)err;
- }
- return ERR_UNAVAILABLE;
+ int err = ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err);
+ return (Error)err;
}
void MultiplayerAPIExtension::_bind_methods() {
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 9b63118f7c..b4e5b11abd 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -78,6 +78,10 @@ bool MultiplayerPeer::is_refusing_new_connections() const {
return refuse_connections;
}
+bool MultiplayerPeer::is_server_relay_supported() const {
+ return false;
+}
+
void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel);
ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel);
@@ -86,8 +90,12 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer);
ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer);
+ ClassDB::bind_method(D_METHOD("get_packet_channel"), &MultiplayerPeer::get_packet_channel);
+ ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode);
ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll);
+ ClassDB::bind_method(D_METHOD("close"), &MultiplayerPeer::close);
+ ClassDB::bind_method(D_METHOD("disconnect_peer", "peer", "force"), &MultiplayerPeer::disconnect_peer, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status);
ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id);
@@ -96,6 +104,8 @@ void MultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections);
ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections);
+ ClassDB::bind_method(D_METHOD("is_server_relay_supported"), &MultiplayerPeer::is_server_relay_supported);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel");
@@ -177,6 +187,14 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const {
return MultiplayerPeer::is_refusing_new_connections();
}
+bool MultiplayerPeerExtension::is_server_relay_supported() const {
+ bool can_relay;
+ if (GDVIRTUAL_CALL(_is_server_relay_supported, can_relay)) {
+ return can_relay;
+ }
+ return MultiplayerPeer::is_server_relay_supported();
+}
+
void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
@@ -197,6 +215,8 @@ void MultiplayerPeerExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_packet_peer);
GDVIRTUAL_BIND(_is_server);
GDVIRTUAL_BIND(_poll);
+ GDVIRTUAL_BIND(_close);
+ GDVIRTUAL_BIND(_disconnect_peer, "p_peer", "p_force");
GDVIRTUAL_BIND(_get_unique_id);
GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable");
GDVIRTUAL_BIND(_is_refusing_new_connections);
diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h
index ab7483ece5..4b5909538e 100644
--- a/scene/main/multiplayer_peer.h
+++ b/scene/main/multiplayer_peer.h
@@ -74,14 +74,20 @@ public:
virtual TransferMode get_transfer_mode() const;
virtual void set_refuse_new_connections(bool p_enable);
virtual bool is_refusing_new_connections() const;
+ virtual bool is_server_relay_supported() const;
virtual void set_target_peer(int p_peer_id) = 0;
virtual int get_packet_peer() const = 0;
+ virtual TransferMode get_packet_mode() const = 0;
+ virtual int get_packet_channel() const = 0;
+
+ virtual void disconnect_peer(int p_peer, bool p_force = false) = 0;
virtual bool is_server() const = 0;
virtual void poll() = 0;
+ virtual void close() = 0;
virtual int get_unique_id() const = 0;
@@ -123,14 +129,21 @@ public:
virtual bool is_refusing_new_connections() const override;
GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional.
+ virtual bool is_server_relay_supported() const override;
+ GDVIRTUAL0RC(bool, _is_server_relay_supported); // Optional.
+
EXBIND1(set_transfer_channel, int);
EXBIND0RC(int, get_transfer_channel);
EXBIND1(set_transfer_mode, TransferMode);
EXBIND0RC(TransferMode, get_transfer_mode);
EXBIND1(set_target_peer, int);
EXBIND0RC(int, get_packet_peer);
+ EXBIND0RC(TransferMode, get_packet_mode);
+ EXBIND0RC(int, get_packet_channel);
EXBIND0RC(bool, is_server);
EXBIND0(poll);
+ EXBIND0(close);
+ EXBIND2(disconnect_peer, int, bool);
EXBIND0RC(int, get_unique_id);
EXBIND0RC(ConnectionStatus, get_connection_status);
};
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index a2b0f1a825..304504a82e 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -322,62 +322,62 @@ void Node::_propagate_exit_tree() {
data.depth = -1;
}
-void Node::move_child(Node *p_child, int p_pos) {
+void Node::move_child(Node *p_child, int p_index) {
ERR_FAIL_NULL(p_child);
ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node.");
// We need to check whether node is internal and move it only in the relevant node range.
if (p_child->_is_internal_front()) {
- if (p_pos < 0) {
- p_pos += data.internal_children_front;
+ if (p_index < 0) {
+ p_index += data.internal_children_front;
}
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, p_pos);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, p_index);
} else if (p_child->_is_internal_back()) {
- if (p_pos < 0) {
- p_pos += data.internal_children_back;
+ if (p_index < 0) {
+ p_index += data.internal_children_back;
}
- ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos));
- _move_child(p_child, data.children.size() - data.internal_children_back + p_pos);
+ ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index));
+ _move_child(p_child, data.children.size() - data.internal_children_back + p_index);
} else {
- if (p_pos < 0) {
- p_pos += get_child_count(false);
+ if (p_index < 0) {
+ p_index += get_child_count(false);
}
- ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos));
- _move_child(p_child, p_pos + data.internal_children_front);
+ ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index));
+ _move_child(p_child, p_index + data.internal_children_front);
}
}
-void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
+void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) {
ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup).");
// Specifying one place beyond the end
- // means the same as moving to the last position
+ // means the same as moving to the last index
if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly.
if (p_child->_is_internal_front()) {
- if (p_pos == data.internal_children_front) {
- p_pos--;
+ if (p_index == data.internal_children_front) {
+ p_index--;
}
} else if (p_child->_is_internal_back()) {
- if (p_pos == data.children.size()) {
- p_pos--;
+ if (p_index == data.children.size()) {
+ p_index--;
}
} else {
- if (p_pos == data.children.size() - data.internal_children_back) {
- p_pos--;
+ if (p_index == data.children.size() - data.internal_children_back) {
+ p_index--;
}
}
}
- if (p_child->data.pos == p_pos) {
+ if (p_child->data.index == p_index) {
return; //do nothing
}
- int motion_from = MIN(p_pos, p_child->data.pos);
- int motion_to = MAX(p_pos, p_child->data.pos);
+ int motion_from = MIN(p_index, p_child->data.index);
+ int motion_to = MAX(p_index, p_child->data.index);
- data.children.remove_at(p_child->data.pos);
- data.children.insert(p_pos, p_child);
+ data.children.remove_at(p_child->data.index);
+ data.children.insert(p_index, p_child);
if (data.tree) {
data.tree->tree_changed();
@@ -386,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
data.blocked++;
//new pos first
for (int i = motion_from; i <= motion_to; i++) {
- data.children[i]->data.pos = i;
+ data.children[i]->data.index = i;
}
// notification second
move_child_notify(p_child);
@@ -1024,11 +1024,9 @@ String increase_numeric_string(const String &s) {
void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const {
if (name == StringName()) {
- //no name and a new name is needed, create one.
+ // No name and a new name is needed, create one.
name = p_child->get_class();
- // Adjust casing according to project setting.
- name = adjust_name_casing(name);
}
//quickly test if proposed name exists
@@ -1106,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
//add a child node quickly, without name validation
p_child->data.name = p_name;
- p_child->data.pos = data.children.size();
+ p_child->data.index = data.children.size();
data.children.push_back(p_child);
p_child->data.parent = this;
@@ -1173,9 +1171,9 @@ void Node::remove_child(Node *p_child) {
Node **children = data.children.ptrw();
int idx = -1;
- if (p_child->data.pos >= 0 && p_child->data.pos < child_count) {
- if (children[p_child->data.pos] == p_child) {
- idx = p_child->data.pos;
+ if (p_child->data.index >= 0 && p_child->data.index < child_count) {
+ if (children[p_child->data.index] == p_child) {
+ idx = p_child->data.index;
}
}
@@ -1211,12 +1209,12 @@ void Node::remove_child(Node *p_child) {
children = data.children.ptrw();
for (int i = idx; i < child_count; i++) {
- children[i]->data.pos = i;
+ children[i]->data.index = i;
children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
p_child->data.parent = nullptr;
- p_child->data.pos = -1;
+ p_child->data.index = -1;
if (data.inside_tree) {
p_child->_propagate_after_exit_tree();
@@ -1343,12 +1341,23 @@ Node *Node::get_node(const NodePath &p_path) const {
Node *node = get_node_or_null(p_path);
if (unlikely(!node)) {
+ // Try to get a clear description of this node in the error message.
+ String desc;
+ if (is_inside_tree()) {
+ desc = get_path();
+ } else {
+ desc = get_name();
+ if (desc.is_empty()) {
+ desc = get_class();
+ }
+ }
+
if (p_path.is_absolute()) {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, desc));
} else {
ERR_FAIL_V_MSG(nullptr,
- vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path()));
+ vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, desc));
}
}
@@ -1411,14 +1420,14 @@ TypedArray<Node> Node::find_children(const String &p_pattern, const String &p_ty
if (cptr[i]->is_class(p_type)) {
ret.append(cptr[i]);
} else if (cptr[i]->get_script_instance()) {
- Ref<Script> script = cptr[i]->get_script_instance()->get_script();
- while (script.is_valid()) {
- if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == script->get_path()) || p_type == script->get_path()) {
+ Ref<Script> scr = cptr[i]->get_script_instance()->get_script();
+ while (scr.is_valid()) {
+ if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == scr->get_path()) || p_type == scr->get_path()) {
ret.append(cptr[i]);
break;
}
- script = script->get_base_script();
+ scr = scr->get_base_script();
}
}
@@ -1466,26 +1475,16 @@ bool Node::is_greater_than(const Node *p_node) const {
ERR_FAIL_COND_V(data.depth < 0, false);
ERR_FAIL_COND_V(p_node->data.depth < 0, false);
-#ifdef NO_ALLOCA
-
- Vector<int> this_stack;
- Vector<int> that_stack;
- this_stack.resize(data.depth);
- that_stack.resize(p_node->data.depth);
-
-#else
int *this_stack = (int *)alloca(sizeof(int) * data.depth);
int *that_stack = (int *)alloca(sizeof(int) * p_node->data.depth);
-#endif
-
const Node *n = this;
int idx = data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, data.depth, false);
- this_stack[idx--] = n->data.pos;
+ this_stack[idx--] = n->data.index;
n = n->data.parent;
}
ERR_FAIL_COND_V(idx != -1, false);
@@ -1493,7 +1492,7 @@ bool Node::is_greater_than(const Node *p_node) const {
idx = p_node->data.depth - 1;
while (n) {
ERR_FAIL_INDEX_V(idx, p_node->data.depth, false);
- that_stack[idx--] = n->data.pos;
+ that_stack[idx--] = n->data.index;
n = n->data.parent;
}
@@ -1904,9 +1903,9 @@ int Node::get_index(bool p_include_internal) const {
ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false.");
if (data.parent && !p_include_internal) {
- return data.pos - data.parent->data.internal_children_front;
+ return data.index - data.parent->data.internal_children_front;
}
- return data.pos;
+ return data.index;
}
Ref<Tween> Node::create_tween() {
@@ -2131,9 +2130,9 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
if (p_flags & DUPLICATE_SCRIPTS) {
bool is_valid = false;
- Variant script = N->get()->get(script_property_name, &is_valid);
+ Variant scr = N->get()->get(script_property_name, &is_valid);
if (is_valid) {
- current_node->set(script_property_name, script);
+ current_node->set(script_property_name, scr);
}
}
@@ -2401,12 +2400,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) {
}
Node *parent = data.parent;
- int pos_in_parent = data.pos;
+ int index_in_parent = data.index;
if (data.parent) {
parent->remove_child(this);
parent->add_child(p_node);
- parent->move_child(p_node, pos_in_parent);
+ parent->move_child(p_node, index_in_parent);
}
while (get_child_count()) {
@@ -2581,7 +2580,7 @@ void Node::print_orphan_nodes() {
#endif
}
-void Node::queue_delete() {
+void Node::queue_free() {
if (is_inside_tree()) {
get_tree()->queue_delete(this);
} else {
@@ -2769,7 +2768,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group);
ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group);
- ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child);
+ ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_index"), &Node::move_child);
ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups);
ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner);
ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner);
@@ -2823,7 +2822,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport);
- ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_delete);
+ ClassDB::bind_method(D_METHOD("queue_free"), &Node::queue_free);
ClassDB::bind_method(D_METHOD("request_ready"), &Node::request_ready);
@@ -2959,7 +2958,7 @@ void Node::_bind_methods() {
}
String Node::_get_name_num_separator() {
- switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_num_separator").operator int()) {
+ switch (GLOBAL_GET("editor/node_naming/name_num_separator").operator int()) {
case 0:
return "";
case 1:
diff --git a/scene/main/node.h b/scene/main/node.h
index 4e6530cccd..4a3ec253b1 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -91,6 +91,7 @@ private:
SceneTree::Group *group = nullptr;
};
+ // This Data struct is to avoid namespace pollution in derived classes.
struct Data {
String scene_file_path;
Ref<SceneState> instance_state;
@@ -104,7 +105,7 @@ private:
int internal_children_front = 0;
int internal_children_back = 0;
- int pos = -1;
+ int index = -1;
int depth = -1;
int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed.
StringName name;
@@ -186,8 +187,8 @@ private:
Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; }
- _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
+ _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; }
+ _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; }
friend class SceneTree;
@@ -346,8 +347,8 @@ public:
void get_groups(List<GroupInfo> *p_groups) const;
int get_persistent_group_count() const;
- void move_child(Node *p_child, int p_pos);
- void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false);
+ void move_child(Node *p_child, int p_index);
+ void _move_child(Node *p_child, int p_index, bool p_ignore_end = false);
void set_owner(Node *p_owner);
Node *get_owner() const;
@@ -459,7 +460,7 @@ public:
#endif
static String adjust_name_casing(const String &p_name);
- void queue_delete();
+ void queue_free();
//hacks for speed
static void init_node_hrcr();
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 3f71de1b18..41eefe0f85 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -44,6 +44,7 @@
#include "node.h"
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
+#include "scene/gui/control.h"
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
@@ -105,10 +106,10 @@ bool SceneTreeTimer::is_ignore_time_scale() {
}
void SceneTreeTimer::release_connections() {
- List<Connection> connections;
- get_all_signal_connections(&connections);
+ List<Connection> signal_connections;
+ get_all_signal_connections(&signal_connections);
- for (const Connection &connection : connections) {
+ for (const Connection &connection : signal_connections) {
disconnect(connection.signal.get_name(), connection.callable);
}
}
@@ -207,15 +208,15 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) {
return;
}
- Node **nodes = g.nodes.ptrw();
- int node_count = g.nodes.size();
+ Node **gr_nodes = g.nodes.ptrw();
+ int gr_node_count = g.nodes.size();
if (p_use_priority) {
SortArray<Node *, Node::ComparatorWithPriority> node_sort;
- node_sort.sort(nodes, node_count);
+ node_sort.sort(gr_nodes, gr_node_count);
} else {
SortArray<Node *, Node::Comparator> node_sort;
- node_sort.sort(nodes, node_count);
+ node_sort.sort(gr_nodes, gr_node_count);
}
g.changed = false;
}
@@ -253,36 +254,36 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
- nodes[i]->callp(p_function, p_args, p_argcount, ce);
+ gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
+ MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
- nodes[i]->callp(p_function, p_args, p_argcount, ce);
+ gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
- MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount);
+ MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
}
}
}
@@ -306,34 +307,34 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->notification(p_notification);
+ gr_nodes[i]->notification(p_notification);
} else {
- MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->notification(p_notification);
+ gr_nodes[i]->notification(p_notification);
} else {
- MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
+ MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
}
}
}
@@ -357,34 +358,34 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
_update_group_order(g);
Vector<Node *> nodes_copy = g.nodes;
- Node **nodes = nodes_copy.ptrw();
- int node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
call_lock++;
if (p_call_flags & GROUP_CALL_REVERSE) {
- for (int i = node_count - 1; i >= 0; i--) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = gr_node_count - 1; i >= 0; i--) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->set(p_name, p_value);
+ gr_nodes[i]->set(p_name, p_value);
} else {
- MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
}
}
} else {
- for (int i = 0; i < node_count; i++) {
- if (call_lock && call_skip.has(nodes[i])) {
+ for (int i = 0; i < gr_node_count; i++) {
+ if (call_lock && call_skip.has(gr_nodes[i])) {
continue;
}
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
- nodes[i]->set(p_name, p_value);
+ gr_nodes[i]->set(p_name, p_value);
} else {
- MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
+ MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
}
}
}
@@ -484,7 +485,7 @@ bool SceneTree::process(double p_time) {
#ifndef _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
//simple hack to reload fallback environment if it changed from editor
- String env_path = ProjectSettings::get_singleton()->get(SNAME("rendering/environment/defaults/default_environment"));
+ String env_path = GLOBAL_GET(SNAME("rendering/environment/defaults/default_environment"));
env_path = env_path.strip_edges(); //user may have added a space or two
String cpath;
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
@@ -846,13 +847,13 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
//performance is not lost because only if something is added/removed the vector is copied.
Vector<Node *> nodes_copy = g.nodes;
- int node_count = nodes_copy.size();
- Node **nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
call_lock++;
- for (int i = 0; i < node_count; i++) {
- Node *n = nodes[i];
+ for (int i = 0; i < gr_node_count; i++) {
+ Node *n = gr_nodes[i];
if (call_lock && call_skip.has(n)) {
continue;
}
@@ -865,7 +866,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio
}
n->notification(p_notification);
- //ERR_FAIL_COND(node_count != g.nodes.size());
+ //ERR_FAIL_COND(gr_node_count != g.nodes.size());
}
call_lock--;
@@ -890,17 +891,19 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
//performance is not lost because only if something is added/removed the vector is copied.
Vector<Node *> nodes_copy = g.nodes;
- int node_count = nodes_copy.size();
- Node **nodes = nodes_copy.ptrw();
+ int gr_node_count = nodes_copy.size();
+ Node **gr_nodes = nodes_copy.ptrw();
call_lock++;
- for (int i = node_count - 1; i >= 0; i--) {
+ Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input.
+
+ for (int i = gr_node_count - 1; i >= 0; i--) {
if (p_viewport->is_input_handled()) {
break;
}
- Node *n = nodes[i];
+ Node *n = gr_nodes[i];
if (call_lock && call_skip.has(n)) {
continue;
}
@@ -913,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
case CALL_INPUT_TYPE_INPUT:
n->_call_input(p_input);
break;
- case CALL_INPUT_TYPE_SHORTCUT_INPUT:
+ case CALL_INPUT_TYPE_SHORTCUT_INPUT: {
+ const Control *c = Object::cast_to<Control>(n);
+ if (c) {
+ // If calling shortcut input on a control, ensure it respects the shortcut context.
+ // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
+ if (c->get_shortcut_context() == nullptr) {
+ no_context_node_ids.append(n->get_instance_id());
+ continue;
+ }
+ if (!c->is_focus_owner_in_shortcut_context()) {
+ continue;
+ }
+ }
n->_call_shortcut_input(p_input);
break;
+ }
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
n->_call_unhandled_input(p_input);
break;
@@ -925,6 +941,13 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal
}
}
+ for (const ObjectID &id : no_context_node_ids) {
+ Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id));
+ if (n) {
+ n->_call_shortcut_input(p_input);
+ }
+ }
+
call_lock--;
if (call_lock == 0) {
call_skip.clear();
@@ -1367,7 +1390,7 @@ SceneTree::SceneTree() {
root = memnew(Window);
root->set_process_mode(Node::PROCESS_MODE_PAUSABLE);
root->set_name("root");
- root->set_title(ProjectSettings::get_singleton()->get("application/config/name"));
+ root->set_title(GLOBAL_GET("application/config/name"));
#ifndef _3D_DISABLED
if (!root->get_world_3d().is_valid()) {
@@ -1390,6 +1413,9 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")));
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
+ const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false);
+ root->set_transparent_background(transparent_background);
+
const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"));
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 05b4f181c2..2385e4f54a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -60,8 +60,8 @@
#include "servers/rendering/rendering_server_globals.h"
void ViewportTexture::setup_local_to_scene() {
- Node *local_scene = get_local_scene();
- if (!local_scene) {
+ Node *loc_scene = get_local_scene();
+ if (!loc_scene) {
return;
}
@@ -71,7 +71,7 @@ void ViewportTexture::setup_local_to_scene() {
vp = nullptr;
- Node *vpn = local_scene->get_node(path);
+ Node *vpn = loc_scene->get_node(path);
ERR_FAIL_COND_MSG(!vpn, "ViewportTexture: Path to node is invalid.");
vp = Object::cast_to<Viewport>(vpn);
@@ -362,6 +362,7 @@ void Viewport::_notification(int p_what) {
current_canvas = find_world_2d()->get_canvas();
RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas);
+ RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask);
_update_audio_listener_2d();
#ifndef _3D_DISABLED
RenderingServer::get_singleton()->viewport_set_scenario(viewport, find_world_3d()->get_scenario());
@@ -499,6 +500,13 @@ void Viewport::_notification(int p_what) {
// exit event if the change in focus results in the mouse exiting
// the window.
} break;
+
+ case NOTIFICATION_PREDELETE: {
+ if (gui_parent) {
+ gui_parent->gui.tooltip_popup = nullptr;
+ gui_parent->gui.tooltip_label = nullptr;
+ }
+ } break;
}
}
@@ -628,19 +636,19 @@ void Viewport::_process_picking() {
PhysicsDirectSpaceState2D::ShapeResult res[64];
for (const CanvasLayer *E : canvas_layers) {
- Transform2D canvas_transform;
+ Transform2D canvas_layer_transform;
ObjectID canvas_layer_id;
if (E) {
// A descendant CanvasLayer.
- canvas_transform = E->get_transform();
+ canvas_layer_transform = E->get_transform();
canvas_layer_id = E->get_instance_id();
} else {
// This Viewport's builtin canvas.
- canvas_transform = get_canvas_transform();
+ canvas_layer_transform = get_canvas_transform();
canvas_layer_id = ObjectID();
}
- Vector2 point = canvas_transform.affine_inverse().xform(pos);
+ Vector2 point = canvas_layer_transform.affine_inverse().xform(pos);
PhysicsDirectSpaceState2D::PointParameters point_params;
point_params.position = point;
@@ -986,11 +994,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) {
return;
}
- if (parent && parent->find_world_2d() == p_world_2d) {
- WARN_PRINT("Unable to use parent world_2d as world_2d");
- return;
- }
-
if (is_inside_tree()) {
RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
}
@@ -1154,9 +1157,7 @@ void Viewport::_gui_cancel_tooltip() {
gui.tooltip_timer = Ref<SceneTreeTimer>();
}
if (gui.tooltip_popup) {
- gui.tooltip_popup->queue_delete();
- gui.tooltip_popup = nullptr;
- gui.tooltip_label = nullptr;
+ gui.tooltip_popup->queue_free();
}
}
@@ -1219,8 +1220,6 @@ void Viewport::_gui_show_tooltip() {
// Remove previous popup if we change something.
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
- gui.tooltip_popup = nullptr;
- gui.tooltip_label = nullptr;
}
if (!tooltip_owner) {
@@ -1252,16 +1251,23 @@ void Viewport::_gui_show_tooltip() {
panel->set_flag(Window::FLAG_POPUP, false);
panel->set_wrap_controls(true);
panel->add_child(base_tooltip);
+ panel->gui_parent = this;
gui.tooltip_popup = panel;
tooltip_owner->add_child(gui.tooltip_popup);
- Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
+ Point2 tooltip_offset = GLOBAL_GET("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
+ r.size = r.size.min(panel->get_max_size());
Window *window = gui.tooltip_popup->get_parent_visible_window();
- Rect2i vr = window->get_usable_parent_rect();
+ Rect2i vr;
+ if (gui.tooltip_popup->is_embedded()) {
+ vr = gui.tooltip_popup->_get_embedder()->get_visible_rect();
+ } else {
+ vr = window->get_usable_parent_rect();
+ }
if (r.size.x + r.position.x > vr.size.x + vr.position.x) {
// Place it in the opposite direction. If it fails, just hug the border.
@@ -1399,10 +1405,6 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
}
Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
- if (Object::cast_to<Viewport>(p_node)) {
- return nullptr;
- }
-
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1486,7 +1488,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mb->get_position();
- gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask != MouseButton::NONE) {
@@ -1640,8 +1641,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.key_event_accepted = false;
Point2 mpos = mm->get_position();
- gui.last_mouse_pos = mpos;
-
// Drag & drop.
if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
gui.drag_accum += mm->get_relative();
@@ -2755,6 +2754,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ev = p_event;
}
+ Ref<InputEventMouse> me = ev;
+ if (me.is_valid()) {
+ gui.last_mouse_pos = me->get_position();
+ }
+
if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) {
set_input_as_handled();
return;
@@ -3241,6 +3245,29 @@ Transform2D Viewport::get_screen_transform() const {
return _get_input_pre_xform().affine_inverse() * get_final_transform();
}
+void Viewport::set_canvas_cull_mask(uint32_t p_canvas_cull_mask) {
+ canvas_cull_mask = p_canvas_cull_mask;
+ RenderingServer::get_singleton()->viewport_set_canvas_cull_mask(viewport, canvas_cull_mask);
+}
+
+uint32_t Viewport::get_canvas_cull_mask() const {
+ return canvas_cull_mask;
+}
+
+void Viewport::set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable) {
+ ERR_FAIL_INDEX(p_layer, 32);
+ if (p_enable) {
+ set_canvas_cull_mask(canvas_cull_mask | (1 << p_layer));
+ } else {
+ set_canvas_cull_mask(canvas_cull_mask & (~(1 << p_layer)));
+ }
+}
+
+bool Viewport::get_canvas_cull_mask_bit(uint32_t p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, 32, false);
+ return (canvas_cull_mask & (1 << p_layer));
+}
+
#ifndef _3D_DISABLED
AudioListener3D *Viewport::get_audio_listener_3d() const {
return audio_listener_3d;
@@ -3723,6 +3750,7 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform);
ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform);
+ ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform);
ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect);
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
@@ -3811,6 +3839,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_embedding_subwindows", "enable"), &Viewport::set_embedding_subwindows);
ClassDB::bind_method(D_METHOD("is_embedding_subwindows"), &Viewport::is_embedding_subwindows);
+ ClassDB::bind_method(D_METHOD("set_canvas_cull_mask", "mask"), &Viewport::set_canvas_cull_mask);
+ ClassDB::bind_method(D_METHOD("get_canvas_cull_mask"), &Viewport::get_canvas_cull_mask);
+
+ ClassDB::bind_method(D_METHOD("set_canvas_cull_mask_bit", "layer", "enable"), &Viewport::set_canvas_cull_mask_bit);
+ ClassDB::bind_method(D_METHOD("get_canvas_cull_mask_bit", "layer"), &Viewport::get_canvas_cull_mask_bit);
+
ClassDB::bind_method(D_METHOD("set_default_canvas_item_texture_repeat", "mode"), &Viewport::set_default_canvas_item_texture_repeat);
ClassDB::bind_method(D_METHOD("get_default_canvas_item_texture_repeat"), &Viewport::get_default_canvas_item_texture_repeat);
@@ -3916,6 +3950,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "positional_shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_positional_shadow_atlas_quadrant_subdiv", "get_positional_shadow_atlas_quadrant_subdiv", 3);
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_canvas_transform", "get_canvas_transform");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_canvas_transform", "get_global_canvas_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_cull_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_canvas_cull_mask", "get_canvas_cull_mask");
ADD_SIGNAL(MethodInfo("size_changed"));
ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
@@ -4050,16 +4085,10 @@ Viewport::Viewport() {
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
#ifndef _3D_DISABLED
- Viewport::Scaling3DMode scaling_3d_mode = (Viewport::Scaling3DMode)(int)GLOBAL_GET("rendering/scaling_3d/mode");
- set_scaling_3d_mode(scaling_3d_mode);
-
+ set_scaling_3d_mode((Viewport::Scaling3DMode)(int)GLOBAL_GET("rendering/scaling_3d/mode"));
set_scaling_3d_scale(GLOBAL_GET("rendering/scaling_3d/scale"));
-
- float fsr_sharpness = GLOBAL_GET("rendering/scaling_3d/fsr_sharpness");
- set_fsr_sharpness(fsr_sharpness);
-
- float texture_mipmap_bias = GLOBAL_GET("rendering/textures/default_filters/texture_mipmap_bias");
- set_texture_mipmap_bias(texture_mipmap_bias);
+ set_fsr_sharpness((float)GLOBAL_GET("rendering/scaling_3d/fsr_sharpness"));
+ set_texture_mipmap_bias((float)GLOBAL_GET("rendering/textures/default_filters/texture_mipmap_bias"));
#endif // _3D_DISABLED
set_sdf_oversize(sdf_oversize); // Set to server.
@@ -4135,7 +4164,7 @@ Transform2D SubViewport::_stretch_transform() {
Transform2D transform = Transform2D();
Size2i view_size_2d_override = _get_size_2d_override();
if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
- Size2 scale = _get_size() / view_size_2d_override;
+ Size2 scale = Size2(_get_size()) / Size2(view_size_2d_override);
transform.scale(scale);
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 471dc41246..8911aea335 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -208,6 +208,7 @@ private:
friend class ViewportTexture;
Viewport *parent = nullptr;
+ Viewport *gui_parent = nullptr; // Whose gui.tooltip_popup it is.
AudioListener2D *audio_listener_2d = nullptr;
Camera2D *camera_2d = nullptr;
@@ -316,6 +317,8 @@ private:
SDFOversize sdf_oversize = SDF_OVERSIZE_120_PERCENT;
SDFScale sdf_scale = SDF_SCALE_50_PERCENT;
+ uint32_t canvas_cull_mask = 0xffffffff; // by default show everything
+
enum SubWindowDrag {
SUB_WINDOW_DRAG_DISABLED,
SUB_WINDOW_DRAG_MOVE,
@@ -638,6 +641,12 @@ public:
void pass_mouse_focus_to(Viewport *p_viewport, Control *p_control);
+ void set_canvas_cull_mask(uint32_t p_layers);
+ uint32_t get_canvas_cull_mask() const;
+
+ void set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable);
+ bool get_canvas_cull_mask_bit(uint32_t p_layer) const;
+
virtual Transform2D get_screen_transform() const;
#ifndef _3D_DISABLED
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 64869b2936..ebb11ecee8 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -157,26 +157,18 @@ void Window::set_flag(Flags p_flag, bool p_enabled) {
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
}
-#else
- DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id);
-#endif
}
}
bool Window::get_flag(Flags p_flag) const {
ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
}
-#else
- flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id);
-#endif
}
return flags[p_flag];
}
@@ -232,6 +224,14 @@ bool Window::is_embedded() const {
return _get_embedder() != nullptr;
}
+bool Window::is_in_edited_scene_root() const {
+#ifdef TOOLS_ENABLED
+ return (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this));
+#else
+ return false;
+#endif
+}
+
void Window::_make_window() {
ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID);
@@ -259,15 +259,12 @@ void Window::_make_window() {
#endif
DisplayServer::get_singleton()->window_set_title(tr_title, window_id);
DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id);
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
_update_window_size();
@@ -465,14 +462,10 @@ void Window::set_visible(bool p_visible) {
//update transient exclusive
if (transient_parent) {
if (exclusive && visible) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -519,13 +512,9 @@ void Window::_make_transient() {
window->transient_children.insert(this);
if (is_inside_tree() && is_visible() && exclusive) {
if (transient_parent->exclusive_child == nullptr) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else if (transient_parent->exclusive_child != this) {
ERR_PRINT("Making child transient exclusive, but parent has another exclusive child");
}
@@ -568,27 +557,19 @@ void Window::set_exclusive(bool p_exclusive) {
exclusive = p_exclusive;
if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) {
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
- } else {
+ if (is_in_edited_scene_root()) {
DisplayServer::get_singleton()->window_set_exclusive(window_id, false);
+ } else {
+ DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
}
-#else
- DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive);
-#endif
}
if (transient_parent) {
if (p_exclusive && is_inside_tree() && is_visible()) {
ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child.");
-#ifdef TOOLS_ENABLED
- if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) {
+ if (!is_in_edited_scene_root()) {
transient_parent->exclusive_child = this;
}
-#else
- transient_parent->exclusive_child = this;
-#endif
} else {
if (transient_parent->exclusive_child == this) {
transient_parent->exclusive_child = nullptr;
@@ -606,6 +587,18 @@ bool Window::is_visible() const {
}
void Window::_update_window_size() {
+ // Force window to respect size limitations of rendering server
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ if (rendering_server) {
+ Size2i max_window_size = rendering_server->get_maximum_viewport_size();
+
+ if (max_window_size != Size2i()) {
+ size = size.min(max_window_size);
+ min_size = min_size.min(max_window_size);
+ max_size = max_size.min(max_window_size);
+ }
+ }
+
Size2i size_limit;
if (wrap_controls) {
size_limit = get_contents_minimum_size();
@@ -651,9 +644,9 @@ void Window::_update_window_size() {
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
}
- DisplayServer::get_singleton()->window_set_size(size, window_id);
DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
+ DisplayServer::get_singleton()->window_set_size(size, window_id);
}
//update the viewport
@@ -666,7 +659,7 @@ void Window::_update_viewport_size() {
Size2i final_size;
Size2i final_size_override;
Rect2i attach_to_screen_rect(Point2i(), size);
- Transform2D stretch_transform;
+ Transform2D stretch_transform_new;
float font_oversampling = 1.0;
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
@@ -674,8 +667,8 @@ void Window::_update_viewport_size() {
final_size = size;
final_size_override = Size2(size) / content_scale_factor;
- stretch_transform = Transform2D();
- stretch_transform.scale(Size2(content_scale_factor, content_scale_factor));
+ stretch_transform_new = Transform2D();
+ stretch_transform_new.scale(Size2(content_scale_factor, content_scale_factor));
} else {
//actual screen video mode
Size2 video_mode = size;
@@ -752,7 +745,7 @@ void Window::_update_viewport_size() {
font_oversampling = (screen_size.x / viewport_size.x) * content_scale_factor;
Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
- stretch_transform.scale(scale);
+ stretch_transform_new.scale(scale);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
@@ -764,7 +757,7 @@ void Window::_update_viewport_size() {
}
bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
- _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform, allocate);
+ _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform_new, allocate);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
@@ -1264,12 +1257,16 @@ void Window::popup(const Rect2i &p_screen_rect) {
set_transient(true);
set_visible(true);
- int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
- Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
- if (screen_rect != Rect2i() && !screen_rect.intersects(Rect2i(position, size))) {
+ Rect2i parent_rect;
+ if (is_embedded()) {
+ parent_rect = _get_embedder()->get_visible_rect();
+ } else {
+ int screen_id = DisplayServer::get_singleton()->window_get_current_screen(get_window_id());
+ parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen_id);
+ }
+ if (parent_rect != Rect2i() && !parent_rect.intersects(Rect2i(position, size))) {
ERR_PRINT(vformat("Window %d spawned at invalid position: %s.", get_window_id(), position));
- // Window appeared on unavailable screen area, so force it to the center.
- set_position(screen_rect.size / 2 - size / 2);
+ set_position((parent_rect.size - size) / 2);
}
_post_popup();
@@ -1294,17 +1291,17 @@ bool Window::has_focus() const {
Rect2i Window::get_usable_parent_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2());
- Rect2i parent;
+ Rect2i parent_rect;
if (is_embedded()) {
- parent = _get_embedder()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
const Window *w = is_visible() ? this : get_parent_visible_window();
//find a parent that can contain us
ERR_FAIL_COND_V(!w, Rect2());
- parent = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
+ parent_rect = DisplayServer::get_singleton()->screen_get_usable_rect(DisplayServer::get_singleton()->window_get_current_screen(w->get_window_id()));
}
- return parent;
+ return parent_rect;
}
void Window::add_child_notify(Node *p_child) {
@@ -1572,9 +1569,9 @@ Window::LayoutDirection Window::get_layout_direction() const {
bool Window::is_layout_rtl() const {
if (layout_dir == LAYOUT_DIRECTION_INHERITED) {
- Window *parent = Object::cast_to<Window>(get_parent());
- if (parent) {
- return parent->is_layout_rtl();
+ Window *parent_w = Object::cast_to<Window>(get_parent());
+ if (parent_w) {
+ return parent_w->is_layout_rtl();
} else {
if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) {
return true;
@@ -1843,6 +1840,11 @@ void Window::_bind_methods() {
}
Window::Window() {
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ if (rendering_server) {
+ max_size = rendering_server->get_maximum_viewport_size();
+ }
+
theme_owner = memnew(ThemeOwner);
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
}
diff --git a/scene/main/window.h b/scene/main/window.h
index 786f0ada38..03597b309a 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -234,6 +234,8 @@ public:
void set_clamp_to_embedder(bool p_enable);
bool is_clamped_to_embedder() const;
+ bool is_in_edited_scene_root() const;
+
bool can_draw() const;
void set_ime_active(bool p_active);
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index a9b7e9acbe..f445634a45 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -169,8 +169,10 @@ static bool _collect_inheritance_chain(const Ref<SceneState> &p_state, const Nod
state = state->get_base_scene_state();
}
- for (int i = inheritance_states.size() - 1; i >= 0; --i) {
- r_states_stack.push_back(inheritance_states[i]);
+ if (inheritance_states.size() > 0) {
+ for (int i = inheritance_states.size() - 1; i >= 0; --i) {
+ r_states_stack.push_back(inheritance_states[i]);
+ }
}
return found;
@@ -214,10 +216,12 @@ Vector<SceneState::PackState> PropertyUtils::get_node_states_stack(const Node *p
{
states_stack_ret.resize(states_stack.size());
_FastPackState *ps = states_stack.ptr();
- for (int i = states_stack.size() - 1; i >= 0; --i) {
- states_stack_ret.write[i].state.reference_ptr(ps->state);
- states_stack_ret.write[i].node = ps->node;
- ++ps;
+ if (states_stack.size() > 0) {
+ for (int i = states_stack.size() - 1; i >= 0; --i) {
+ states_stack_ret.write[i].state.reference_ptr(ps->state);
+ states_stack_ret.write[i].node = ps->node;
+ ++ps;
+ }
}
}
return states_stack_ret;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index f2ac1c2e58..dfd9c6eb2f 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -35,7 +35,7 @@
#include "scene/scene_string_names.h"
bool Animation::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
+ String prop_name = p_name;
if (p_name == SNAME("_compression")) {
ERR_FAIL_COND_V(tracks.size() > 0, false); //can only set compression if no tracks exist
@@ -63,9 +63,9 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
compression.enabled = true;
return true;
- } else if (name.begins_with("tracks/")) {
- int track = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("tracks/")) {
+ int track = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (tracks.size() == track && what == "type") {
String type = p_value;
@@ -431,7 +431,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
+ String prop_name = p_name;
if (p_name == SNAME("_compression")) {
ERR_FAIL_COND_V(!compression.enabled, false);
@@ -456,15 +456,15 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = comp;
return true;
- } else if (name == "length") {
+ } else if (prop_name == "length") {
r_ret = length;
- } else if (name == "loop_mode") {
+ } else if (prop_name == "loop_mode") {
r_ret = loop_mode;
- } else if (name == "step") {
+ } else if (prop_name == "step") {
r_ret = step;
- } else if (name.begins_with("tracks/")) {
- int track = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("tracks/")) {
+ int track = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
ERR_FAIL_INDEX_V(track, tracks.size(), false);
if (what == "type") {
switch (track_get_type(track)) {
@@ -5239,9 +5239,7 @@ bool Animation::_fetch_compressed(uint32_t p_compressed_track, double p_time, Ve
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5384,9 +5382,7 @@ void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track
double page_base_time = compression.pages[page_index].time_offset;
const uint8_t *page_data = compression.pages[page_index].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5456,9 +5452,7 @@ int Animation::_get_compressed_key_count(uint32_t p_compressed_track) const {
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
@@ -5492,9 +5486,7 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
for (uint32_t i = 0; i < compression.pages.size(); i++) {
const uint8_t *page_data = compression.pages[i].data.ptr();
-#ifndef _MSC_VER
-#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported
-#endif
+ // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported.
const uint32_t *indices = (const uint32_t *)page_data;
const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]];
uint32_t time_key_count = indices[p_compressed_track * 3 + 1];
diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp
index 26204583ef..ce68936370 100644
--- a/scene/resources/audio_stream_wav.cpp
+++ b/scene/resources/audio_stream_wav.cpp
@@ -580,8 +580,8 @@ Error AudioStreamWAV::save_to_wav(const String &p_path) {
file->store_32(sub_chunk_2_size); //Subchunk2Size
// Add data
- Vector<uint8_t> data = get_data();
- const uint8_t *read_data = data.ptr();
+ Vector<uint8_t> stream_data = get_data();
+ const uint8_t *read_data = stream_data.ptr();
switch (format) {
case AudioStreamWAV::FORMAT_8_BITS:
for (unsigned int i = 0; i < data_bytes; i++) {
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 0505f6b559..1b06e09bb8 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -639,9 +639,7 @@ void BitMap::resize(const Size2i &p_new_size) {
}
Ref<Image> BitMap::convert_to_image() const {
- Ref<Image> image;
- image.instantiate();
- image->create(width, height, false, Image::FORMAT_L8);
+ Ref<Image> image = Image::create_empty(width, height, false, Image::FORMAT_L8);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index b0454004a0..f7ed8d98cb 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -33,17 +33,17 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
- float radius = get_radius();
- float height = get_height();
+ float c_radius = get_radius();
+ float c_height = get_height();
Vector<Vector3> points;
- Vector3 d(0, height * 0.5 - radius, 0);
+ Vector3 d(0, c_height * 0.5 - c_radius, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg_to_rad((float)i);
float rb = Math::deg_to_rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp
index e7960f1ba4..5bcefcd0e4 100644
--- a/scene/resources/convex_polygon_shape_3d.cpp
+++ b/scene/resources/convex_polygon_shape_3d.cpp
@@ -33,18 +33,18 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
- Vector<Vector3> points = get_points();
+ Vector<Vector3> poly_points = get_points();
- if (points.size() > 3) {
- Vector<Vector3> varr = Variant(points);
+ if (poly_points.size() > 3) {
+ Vector<Vector3> varr = Variant(poly_points);
Geometry3D::MeshData md;
Error err = ConvexHullComputer::convex_hull(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
- for (int i = 0; i < md.edges.size(); i++) {
- lines.write[i * 2 + 0] = md.vertices[md.edges[i].a];
- lines.write[i * 2 + 1] = md.vertices[md.edges[i].b];
+ for (uint32_t i = 0; i < md.edges.size(); i++) {
+ lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
+ lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
return lines;
}
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 0ea5264935..eda9af9dde 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -936,6 +936,46 @@ Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
}
}
+Transform2D Curve2D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_loop, real_t p_lookahead) const {
+ real_t path_length = get_baked_length(); // Ensure baked.
+ ERR_FAIL_COND_V_MSG(path_length == 0, Transform2D(), "Length of Curve2D is 0.");
+
+ Vector2 pos = sample_baked(p_offset, p_cubic);
+
+ real_t ahead = p_offset + p_lookahead;
+
+ if (p_loop && ahead >= path_length) {
+ // If our lookahead will loop, we need to check if the path is closed.
+ int point_count = get_point_count();
+ if (point_count > 0) {
+ Vector2 start_point = get_point_position(0);
+ Vector2 end_point = get_point_position(point_count - 1);
+ if (start_point == end_point) {
+ // Since the path is closed we want to 'smooth off'
+ // the corner at the start/end.
+ // So we wrap the lookahead back round.
+ ahead = Math::fmod(ahead, path_length);
+ }
+ }
+ }
+
+ Vector2 ahead_pos = sample_baked(ahead, p_cubic);
+
+ Vector2 tangent_to_curve;
+ if (ahead_pos == pos) {
+ // This will happen at the end of non-looping or non-closed paths.
+ // We'll try a look behind instead, in order to get a meaningful angle.
+ tangent_to_curve =
+ (pos - sample_baked(p_offset - p_lookahead, p_cubic)).normalized();
+ } else {
+ tangent_to_curve = (ahead_pos - pos).normalized();
+ }
+
+ Vector2 normal_of_curve = -tangent_to_curve.orthogonal();
+
+ return Transform2D(normal_of_curve, tangent_to_curve, pos);
+}
+
PackedVector2Array Curve2D::get_baked_points() const {
if (baked_cache_dirty) {
_bake();
@@ -1184,6 +1224,7 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("sample_baked_with_rotation", "offset", "cubic", "loop", "lookahead"), &Curve2D::sample_baked_with_rotation, DEFVAL(false), DEFVAL(true), DEFVAL(4.0));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point);
ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset);
@@ -1667,6 +1708,10 @@ Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) cons
idx = (end + start) / 2;
}
+ if (idx == count - 1) {
+ return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
+ }
+
real_t offset_begin = baked_dist_cache[idx];
real_t offset_end = baked_dist_cache[idx + 1];
@@ -1675,10 +1720,6 @@ Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) cons
real_t frac = (p_offset - offset_begin) / idx_interval;
- if (idx == count - 1) {
- return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
- }
-
Vector3 forward = (rp[idx + 1] - rp[idx]).normalized();
Vector3 up = r[idx];
Vector3 up1 = r[idx + 1];
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 88b6dda096..fa1d35aab1 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -216,6 +216,7 @@ public:
real_t get_baked_length() const;
Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const;
+ Transform2D sample_baked_with_rotation(real_t p_offset, bool p_cubic = false, bool p_loop = true, real_t p_lookahead = 4.0) const;
PackedVector2Array get_baked_points() const; //useful for going through
Vector2 get_closest_point(const Vector2 &p_to_point) const;
real_t get_closest_offset(const Vector2 &p_to_point) const;
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index a5951db8ea..e5f417cbcc 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -33,17 +33,17 @@
#include "servers/physics_server_3d.h"
Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
- float radius = get_radius();
- float height = get_height();
+ float c_radius = get_radius();
+ float c_height = get_height();
Vector<Vector3> points;
- Vector3 d(0, height * 0.5, 0);
+ Vector3 d(0, c_height * 0.5, 0);
for (int i = 0; i < 360; i++) {
float ra = Math::deg_to_rad((float)i);
float rb = Math::deg_to_rad((float)i + 1);
- Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
- Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
+ Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * c_radius;
+ Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * c_radius;
points.push_back(Vector3(a.x, 0, a.y) + d);
points.push_back(Vector3(b.x, 0, b.y) + d);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index f03e3813cc..aa271e6f4b 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -433,7 +433,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_color", "TextEdit", control_font_color);
- theme->set_color("font_selected_color", "TextEdit", control_font_pressed_color);
+ theme->set_color("font_selected_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "TextEdit", control_font_disabled_color);
theme->set_color("font_placeholder_color", "TextEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1));
@@ -476,7 +476,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("completion_scroll_hovered_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.4));
theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67));
theme->set_color("font_color", "CodeEdit", control_font_color);
- theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0));
+ theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0, 0));
theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f));
theme->set_color("font_placeholder_color", "CodeEdit", control_font_placeholder_color);
theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1));
@@ -553,6 +553,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("grabber_disabled", "HSlider", icons["slider_grabber_disabled"]);
theme->set_icon("tick", "HSlider", icons["hslider_tick"]);
+ theme->set_constant("grabber_offset", "HSlider", 0);
+
// VSlider
theme->set_stylebox("slider", "VSlider", style_slider);
@@ -564,6 +566,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("grabber_disabled", "VSlider", icons["slider_grabber_disabled"]);
theme->set_icon("tick", "VSlider", icons["vslider_tick"]);
+ theme->set_constant("grabber_offset", "VSlider", 0);
+
// SpinBox
theme->set_icon("updown", "SpinBox", icons["updown"]);
@@ -876,7 +880,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_width", "ColorPicker", 30 * scale);
theme->set_constant("label_width", "ColorPicker", 10 * scale);
+ theme->set_icon("folded_arrow", "ColorPicker", icons["arrow_right"]);
+ theme->set_icon("expanded_arrow", "ColorPicker", icons["arrow_down"]);
theme->set_icon("screen_picker", "ColorPicker", icons["color_picker_pipette"]);
+ theme->set_icon("shape_circle", "ColorPicker", icons["picker_shape_circle"]);
+ theme->set_icon("shape_rect", "ColorPicker", icons["picker_shape_rectangle"]);
+ theme->set_icon("shape_rect_wheel", "ColorPicker", icons["picker_shape_rectangle_wheel"]);
theme->set_icon("add_preset", "ColorPicker", icons["add"]);
theme->set_icon("color_hue", "ColorPicker", icons["color_picker_hue"]);
theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]);
@@ -950,7 +959,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font_size("mono_font_size", "RichTextLabel", -1);
theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1));
- theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0));
+ theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
@@ -971,6 +980,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0));
+ theme->set_constant("text_highlight_h_padding", "RichTextLabel", 3 * scale);
+ theme->set_constant("text_highlight_v_padding", "RichTextLabel", 3 * scale);
+
// Containers
theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
diff --git a/scene/resources/default_theme/picker_shape_circle.svg b/scene/resources/default_theme/picker_shape_circle.svg
new file mode 100644
index 0000000000..8e7fb7f06e
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_circle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><rect height="11" rx="5.5" transform="translate(1 2)" width="11"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/scene/resources/default_theme/picker_shape_rectangle.svg b/scene/resources/default_theme/picker_shape_rectangle.svg
new file mode 100644
index 0000000000..3c7dd46884
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_rectangle.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h16v16h-16z"/></clipPath><g clip-path="url(#a)" fill="#eaeaea"><path d="m0 0h11v11h-11z" transform="translate(1 2)"/><path d="m0 0h2v11h-2z" transform="translate(13 2)"/></g></svg>
diff --git a/scene/resources/default_theme/picker_shape_rectangle_wheel.svg b/scene/resources/default_theme/picker_shape_rectangle_wheel.svg
new file mode 100644
index 0000000000..e85665a8f2
--- /dev/null
+++ b/scene/resources/default_theme/picker_shape_rectangle_wheel.svg
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ height="16"
+ viewBox="0 0 16 16"
+ width="16"
+ version="1.1"
+ id="svg11"
+ sodipodi:docname="PickerShapeRectangleWheel.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs15" />
+ <sodipodi:namedview
+ id="namedview13"
+ pagecolor="#505050"
+ bordercolor="#ffffff"
+ borderopacity="1"
+ inkscape:pageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="1"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="0.53125"
+ inkscape:cy="5.28125"
+ inkscape:window-width="1920"
+ inkscape:window-height="1001"
+ inkscape:window-x="-9"
+ inkscape:window-y="-9"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg11">
+ <inkscape:grid
+ type="xygrid"
+ id="grid944" />
+ </sodipodi:namedview>
+ <clipPath
+ id="a">
+ <path
+ d="m0 0h16v16h-16z"
+ id="path2" />
+ </clipPath>
+ <g
+ clip-path="url(#a)"
+ fill="#eaeaea"
+ id="g9"
+ transform="matrix(0.85714286,0,0,0.85714286,1.1428571,1.1428571)">
+ <path
+ d="M 7,2 A 5,5 0 1 0 12,7 5.006,5.006 0 0 0 7,2 M 7,0 A 7,7 0 1 1 0,7 7,7 0 0 1 7,0 Z"
+ transform="translate(1,1)"
+ id="path5" />
+ <path
+ d="M 0,0 H 7 V 7 H 0 Z"
+ transform="translate(4.5,4.5)"
+ id="path7" />
+ </g>
+</svg>
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index ebdaaaa95f..23bd8a4be4 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -78,7 +78,7 @@ float Environment::get_sky_custom_fov() const {
void Environment::set_sky_rotation(const Vector3 &p_rotation) {
bg_sky_rotation = p_rotation;
- RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation));
+ RS::get_singleton()->environment_set_sky_orientation(environment, Basis::from_euler(p_rotation));
}
Vector3 Environment::get_sky_rotation() const {
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 6a278f1f39..1eb94dcb94 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1065,12 +1065,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
}
int chars = len / 9;
for (int i = 0; i < chars; i++) {
- const int32_t *data = &arr[i * 9];
- char32_t c = data[0];
- set_glyph_texture_idx(0, Vector2i(16, 0), c, data[1]);
- set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(data[2], data[3], data[4], data[5]));
- set_glyph_offset(0, Vector2i(16, 0), c, Size2(data[6], data[7]));
- set_glyph_advance(0, 16, c, Vector2(data[8], 0));
+ const int32_t *char_data = &arr[i * 9];
+ char32_t c = char_data[0];
+ set_glyph_texture_idx(0, Vector2i(16, 0), c, char_data[1]);
+ set_glyph_uv_rect(0, Vector2i(16, 0), c, Rect2(char_data[2], char_data[3], char_data[4], char_data[5]));
+ set_glyph_offset(0, Vector2i(16, 0), c, Size2(char_data[6], char_data[7]));
+ set_glyph_advance(0, 16, c, Vector2(char_data[8], 0));
}
} else if (tokens.size() == 1 && tokens[0] == "kernings") {
// Compatibility, BitmapFont.
@@ -1082,8 +1082,8 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
for (int i = 0; i < len / 3; i++) {
- const int32_t *data = &arr[i * 3];
- set_kerning(0, 16, Vector2i(data[0], data[1]), Vector2(data[2], 0));
+ const int32_t *kern_data = &arr[i * 3];
+ set_kerning(0, 16, Vector2i(kern_data[0], kern_data[1]), Vector2(kern_data[2], 0));
}
} else if (tokens.size() == 1 && tokens[0] == "height") {
// Compatibility, BitmapFont.
@@ -1108,12 +1108,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
#endif // DISABLE_DEPRECATED
if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- set_language_support_override(lang, p_value);
+ String lang_code = tokens[1];
+ set_language_support_override(lang_code, p_value);
return true;
} else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- set_script_support_override(script, p_value);
+ String script_code = tokens[1];
+ set_script_support_override(script_code, p_value);
return true;
} else if (tokens.size() >= 3 && tokens[0] == "cache") {
int cache_index = tokens[1].to_int();
@@ -1187,12 +1187,12 @@ bool FontFile::_set(const StringName &p_name, const Variant &p_value) {
bool FontFile::_get(const StringName &p_name, Variant &r_ret) const {
Vector<String> tokens = p_name.operator String().split("/");
if (tokens.size() == 2 && tokens[0] == "language_support_override") {
- String lang = tokens[1];
- r_ret = get_language_support_override(lang);
+ String lang_code = tokens[1];
+ r_ret = get_language_support_override(lang_code);
return true;
} else if (tokens.size() == 2 && tokens[0] == "script_support_override") {
- String script = tokens[1];
- r_ret = get_script_support_override(script);
+ String script_code = tokens[1];
+ r_ret = get_script_support_override(script_code);
return true;
} else if (tokens.size() >= 3 && tokens[0] == "cache") {
int cache_index = tokens[1].to_int();
@@ -1341,6 +1341,19 @@ void FontFile::reset_state() {
/*************************************************************************/
+// OEM encoding mapping for 0x80..0xFF range.
+static const char32_t _oem_to_unicode[][129] = {
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\u0160\u2039\u015a\u0164\u017d\u0179\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0161\u203a\u015b\u0165\u017e\u017a\xa0\u02c7\u02d8\u0141\xa4\u0104\xa6\xa7\xa8\xa9\u015e\xab\xac\xad\xae\u017b\xb0\xb1\u02db\u0142\xb4\xb5\xb6\xb7\xb8\u0105\u015f\xbb\u013d\u02dd\u013e\u017c\u0154\xc1\xc2\u0102\xc4\u0139\u0106\xc7\u010c\xc9\u0118\xcb\u011a\xcd\xce\u010e\u0110\u0143\u0147\xd3\xd4\u0150\xd6\xd7\u0158\u016e\xda\u0170\xdc\xdd\u0162\xdf\u0155\xe1\xe2\u0103\xe4\u013a\u0107\xe7\u010d\xe9\u0119\xeb\u011b\xed\xee\u010f\u0111\u0144\u0148\xf3\xf4\u0151\xf6\xf7\u0159\u016f\xfa\u0171\xfc\xfd\u0163\u02d9", // 1250 - Latin 2
+ U"\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f", // 1251 - Cyrillic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\u017d\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\u017e\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", // 1252 - Latin 1
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\u0385\u0386\xa3\xa4\xa5\xa6\xa7\xa8\xa9\ufffe\xab\xac\xad\xae\u2015\xb0\xb1\xb2\xb3\u0384\xb5\xb6\xb7\u0388\u0389\u038a\xbb\u038c\xbd\u038e\u038f\u0390\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e\u039f\u03a0\u03a1\ufffe\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03a9\u03aa\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9\u03ca\u03cb\u03cc\u03cd\u03ce\ufffe", // 1253 - Greek
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0160\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\u0161\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\u011e\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\u0130\u015e\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\u011f\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u0131\u015f\xff", // 1254 - Turkish
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\ufffe\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\ufffe\ufffe\ufffe\ufffe\xa0\xa1\xa2\xa3\u20aa\xa5\xa6\xa7\xa8\xa9\xd7\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xf7\xbb\xbc\xbd\xbe\xbf\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9\ufffe\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05f0\u05f1\u05f2\u05f3\u05f4\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\ufffe\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\ufffe\ufffe\u200e\u200f\ufffe", // 1255 - Hebrew
+ U"\u20ac\u067e\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\u0679\u2039\u0152\u0686\u0698\u0688\u06af\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u06a9\u2122\u0691\u203a\u0153\u200c\u200d\u06ba\xa0\u060c\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\u06be\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\u061b\xbb\xbc\xbd\xbe\u061f\u06c1\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\xd7\u0637\u0638\u0639\u063a\u0640\u0641\u0642\u0643\xe0\u0644\xe2\u0645\u0646\u0647\u0648\xe7\xe8\xe9\xea\xeb\u0649\u064a\xee\xef\u064b\u064c\u064d\u064e\xf4\u064f\u0650\xf7\u0651\xf9\u0652\xfb\xfc\u200e\u200f\u06d2", // 1256 - Arabic
+ U"\u20ac\ufffe\u201a\ufffe\u201e\u2026\u2020\u2021\ufffe\u2030\ufffe\u2039\ufffe\xa8\u02c7\xb8\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffe\u2122\ufffe\u203a\ufffe\xaf\u02db\ufffe\xa0\ufffe\xa2\xa3\xa4\ufffe\xa6\xa7\xd8\xa9\u0156\xab\xac\xad\xae\xc6\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xf8\xb9\u0157\xbb\xbc\xbd\xbe\xe6\u0104\u012e\u0100\u0106\xc4\xc5\u0118\u0112\u010c\xc9\u0179\u0116\u0122\u0136\u012a\u013b\u0160\u0143\u0145\xd3\u014c\xd5\xd6\xd7\u0172\u0141\u015a\u016a\xdc\u017b\u017d\xdf\u0105\u012f\u0101\u0107\xe4\xe5\u0119\u0113\u010d\xe9\u017a\u0117\u0123\u0137\u012b\u013c\u0161\u0144\u0146\xf3\u014d\xf5\xf6\xf7\u0173\u0142\u015b\u016b\xfc\u017c\u017e\u02d9", // 1257 - Baltic
+ U"\u20ac\ufffe\u201a\u0192\u201e\u2026\u2020\u2021\u02c6\u2030\ufffe\u2039\u0152\ufffe\ufffe\ufffe\ufffe\u2018\u2019\u201c\u201d\u2022\u2013\u2014\u02dc\u2122\ufffe\u203a\u0153\ufffe\ufffe\u0178\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\u0102\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\u0300\xcd\xce\xcf\u0110\xd1\u0309\xd3\xd4\u01a0\xd6\xd7\xd8\xd9\xda\xdb\xdc\u01af\u0303\xdf\xe0\xe1\xe2\u0103\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\u0301\xed\xee\xef\u0111\xf1\u0323\xf3\xf4\u01a1\xf6\xf7\xf8\xf9\xfa\xfb\xfc\u01b0\u20ab\xff", // 1258 - Vietnamese
+};
+
Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
@@ -1371,10 +1384,12 @@ Error FontFile::load_bitmap_font(const String &p_path) {
f->get_buffer((unsigned char *)&magic, 4);
if (magic[0] == 'B' && magic[1] == 'M' && magic[2] == 'F') {
// Binary BMFont file.
- ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported."), (int)magic[3]));
+ ERR_FAIL_COND_V_MSG(magic[3] != 3, ERR_CANT_CREATE, vformat(RTR("Version %d of BMFont is not supported (should be 3)."), (int)magic[3]));
uint8_t block_type = f->get_8();
uint32_t block_size = f->get_32();
+ bool unicode = false;
+ uint8_t encoding = 9;
while (!f->eof_reached()) {
uint64_t off = f->get_position();
switch (block_type) {
@@ -1382,14 +1397,48 @@ Error FontFile::load_bitmap_font(const String &p_path) {
ERR_FAIL_COND_V_MSG(block_size < 15, ERR_CANT_CREATE, RTR("Invalid BMFont info block size."));
base_size = f->get_16();
uint8_t flags = f->get_8();
- ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
if (flags & (1 << 3)) {
st_flags.set_flag(TextServer::FONT_BOLD);
}
if (flags & (1 << 2)) {
st_flags.set_flag(TextServer::FONT_ITALIC);
}
- f->get_8(); // non-unicode charset, skip
+ unicode = (flags & 0x02);
+ uint8_t encoding_id = f->get_8(); // non-unicode charset
+ if (!unicode) {
+ switch (encoding_id) {
+ case 0x00: {
+ encoding = 2;
+ } break;
+ case 0xB2: {
+ encoding = 6;
+ } break;
+ case 0xBA: {
+ encoding = 7;
+ } break;
+ case 0xEE: {
+ encoding = 0;
+ } break;
+ case 0xA1: {
+ encoding = 3;
+ } break;
+ case 0xB1: {
+ encoding = 5;
+ } break;
+ case 0xCC: {
+ encoding = 1;
+ } break;
+ case 0xA2: {
+ encoding = 4;
+ } break;
+ case 0xA3: {
+ encoding = 8;
+ } break;
+ default: {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %x, parsing as Unicode (should be 0x00 - Latin 1, 0xB2 - Arabic, 0xBA - Baltic, 0xEE - Latin 2, 0xA1 - Greek, 0xB1 - Hebrew, 0xCC - Cyrillic, 0xA2 - Turkish, 0xA3 - Vietnamese).", encoding_id));
+ } break;
+ };
+ }
f->get_16(); // stretch_h, skip
f->get_8(); // aa, skip
f->get_32(); // padding, skip
@@ -1492,6 +1541,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Rect2 uv_rect;
char32_t idx = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
uv_rect.position.x = (int16_t)f->get_16();
uv_rect.position.y = (int16_t)f->get_16();
uv_rect.size.width = (int16_t)f->get_16();
@@ -1508,24 +1565,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
int texture_idx = f->get_8();
uint8_t channel = f->get_8();
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1546,6 +1604,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Vector2i kpk;
kpk.x = f->get_32();
kpk.y = f->get_32();
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.y));
+ kpk.y = 0x00;
+ }
+ }
set_kerning(0, base_size, kpk, Vector2((int16_t)f->get_16(), 0));
}
} break;
@@ -1561,6 +1633,8 @@ Error FontFile::load_bitmap_font(const String &p_path) {
} else {
// Text BMFont file.
f->seek(0);
+ bool unicode = false;
+ uint8_t encoding = 9;
while (true) {
String line = f->get_line();
@@ -1625,7 +1699,37 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("face")) {
font_name = keys["face"];
}
- ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, RTR("Non-unicode version of BMFont is not supported."));
+ if (keys.has("unicode")) {
+ unicode = keys["unicode"].to_int();
+ }
+ if (!unicode) {
+ if (keys.has("charset")) {
+ String encoding_name = keys["charset"].to_upper();
+ if (encoding_name == "" || encoding_name == "ASCII" || encoding_name == "ANSI") {
+ encoding = 2;
+ } else if (encoding_name == "ARABIC") {
+ encoding = 6;
+ } else if (encoding_name == "BALTIC") {
+ encoding = 7;
+ } else if (encoding_name == "EASTEUROPE") {
+ encoding = 0;
+ } else if (encoding_name == "GREEK") {
+ encoding = 3;
+ } else if (encoding_name == "HEBREW") {
+ encoding = 5;
+ } else if (encoding_name == "RUSSIAN") {
+ encoding = 1;
+ } else if (encoding_name == "TURKISH") {
+ encoding = 4;
+ } else if (encoding_name == "VIETNAMESE") {
+ encoding = 8;
+ } else {
+ WARN_PRINT(vformat("Unknown BMFont OEM encoding %s, parsing as Unicode (should be ANSI, ASCII, ARABIC, BALTIC, EASTEUROPE, GREEK, HEBREW, RUSSIAN, TURKISH or VIETNAMESE).", encoding_name));
+ }
+ } else {
+ encoding = 2;
+ }
+ }
} else if (type == "common") {
if (keys.has("lineHeight")) {
height = keys["lineHeight"].to_int();
@@ -1719,6 +1823,14 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("id")) {
idx = keys["id"].to_int();
+ if (!unicode && encoding < 9) {
+ if (idx >= 0x80 && idx <= 0xFF) {
+ idx = _oem_to_unicode[encoding][idx - 0x80];
+ } else if (idx > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", idx));
+ idx = 0x00;
+ }
+ }
}
if (keys.has("x")) {
uv_rect.position.x = keys["x"].to_int();
@@ -1753,24 +1865,25 @@ Error FontFile::load_bitmap_font(const String &p_path) {
channel = keys["chnl"].to_int();
}
- ERR_FAIL_COND_V_MSG(!packed && channel != 15, ERR_CANT_CREATE, RTR("Invalid glyph channel."));
int ch_off = 0;
- switch (channel) {
- case 1:
- ch_off = 2;
- break; // B
- case 2:
- ch_off = 1;
- break; // G
- case 4:
- ch_off = 0;
- break; // R
- case 8:
- ch_off = 3;
- break; // A
- default:
- ch_off = 0;
- break;
+ if (packed) {
+ switch (channel) {
+ case 1:
+ ch_off = 2;
+ break; // B
+ case 2:
+ ch_off = 1;
+ break; // G
+ case 4:
+ ch_off = 0;
+ break; // R
+ case 8:
+ ch_off = 3;
+ break; // A
+ default:
+ ch_off = 0;
+ break;
+ }
}
set_glyph_advance(0, base_size, idx, advance);
set_glyph_offset(0, Vector2i(base_size, 0), idx, offset);
@@ -1791,6 +1904,20 @@ Error FontFile::load_bitmap_font(const String &p_path) {
if (keys.has("second")) {
kpk.y = keys["second"].to_int();
}
+ if (!unicode && encoding < 9) {
+ if (kpk.x >= 0x80 && kpk.x <= 0xFF) {
+ kpk.x = _oem_to_unicode[encoding][kpk.x - 0x80];
+ } else if (kpk.x > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.x = 0x00;
+ }
+ if (kpk.y >= 0x80 && kpk.y <= 0xFF) {
+ kpk.y = _oem_to_unicode[encoding][kpk.y - 0x80];
+ } else if (kpk.y > 0xFF) {
+ WARN_PRINT(vformat("Invalid BMFont OEM character %x (should be 0x00-0xFF).", kpk.x));
+ kpk.y = 0x00;
+ }
+ }
if (keys.has("amount")) {
set_kerning(0, base_size, kpk, Vector2(keys["amount"].to_int(), 0));
}
@@ -1813,8 +1940,8 @@ Error FontFile::load_bitmap_font(const String &p_path) {
Error FontFile::load_dynamic_font(const String &p_path) {
reset_state();
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
- set_data(data);
+ Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path);
+ set_data(font_data);
return OK;
}
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index de3d502102..b728c24e0d 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -829,9 +829,9 @@ void ImporterMesh::_set_data(const Dictionary &p_data) {
ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX);
Array arr = s["arrays"];
Dictionary lods;
- String name;
+ String surf_name;
if (s.has("name")) {
- name = s["name"];
+ surf_name = s["name"];
}
if (s.has("lods")) {
lods = s["lods"];
@@ -848,7 +848,7 @@ void ImporterMesh::_set_data(const Dictionary &p_data) {
if (s.has("flags")) {
flags = s["flags"];
}
- add_surface(prim, arr, b_shapes, lods, material, name, flags);
+ add_surface(prim, arr, b_shapes, lods, material, surf_name, flags);
}
}
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 838927e34f..10d193f950 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -107,18 +107,15 @@ Shader::Mode Material::get_shader_mode() const {
}
bool Material::_can_do_next_pass() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_do_next_pass, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_do_next_pass, ret);
+ return ret;
}
+
bool Material::_can_use_render_priority() const {
- bool ret;
- if (GDVIRTUAL_CALL(_can_use_render_priority, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_can_use_render_priority, ret);
+ return ret;
}
void Material::_bind_methods() {
@@ -2348,7 +2345,7 @@ void BaseMaterial3D::set_on_top_of_alpha() {
set_flag(FLAG_DISABLE_DEPTH_TEST, true);
}
-void BaseMaterial3D::set_proximity_fade(bool p_enable) {
+void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) {
proximity_fade_enabled = p_enable;
_queue_shader_change();
notify_property_list_changed();
@@ -2624,7 +2621,7 @@ void BaseMaterial3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_refraction_texture_channel", "channel"), &BaseMaterial3D::set_refraction_texture_channel);
ClassDB::bind_method(D_METHOD("get_refraction_texture_channel"), &BaseMaterial3D::get_refraction_texture_channel);
- ClassDB::bind_method(D_METHOD("set_proximity_fade", "enabled"), &BaseMaterial3D::set_proximity_fade);
+ ClassDB::bind_method(D_METHOD("set_proximity_fade_enabled", "enabled"), &BaseMaterial3D::set_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("is_proximity_fade_enabled"), &BaseMaterial3D::is_proximity_fade_enabled);
ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &BaseMaterial3D::set_proximity_fade_distance);
@@ -2808,7 +2805,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1,suffix:px"), "set_point_size", "get_point_size");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE);
ADD_GROUP("Proximity Fade", "proximity_fade_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enabled"), "set_proximity_fade_enabled", "is_proximity_fade_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance");
ADD_GROUP("MSDF", "msdf_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range");
diff --git a/scene/resources/material.h b/scene/resources/material.h
index dd9589c577..b3c2159e70 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -719,7 +719,7 @@ public:
void set_on_top_of_alpha();
- void set_proximity_fade(bool p_enable);
+ void set_proximity_fade_enabled(bool p_enable);
bool is_proximity_fade_enabled() const;
void set_proximity_fade_distance(float p_distance);
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index b42e65c8df..706db3af16 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -313,11 +313,11 @@ Ref<TriangleMesh> Mesh::generate_surface_triangle_mesh(int p_surface) const {
}
}
- Ref<TriangleMesh> triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
- triangle_mesh->create(faces);
- surface_triangle_meshes.set(p_surface, triangle_mesh);
+ Ref<TriangleMesh> tr_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
+ tr_mesh->create(faces);
+ surface_triangle_meshes.set(p_surface, tr_mesh);
- return triangle_mesh;
+ return tr_mesh;
}
void Mesh::generate_debug_mesh_lines(Vector<Vector3> &r_lines) {
@@ -1251,7 +1251,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
index_count = d["index_count"];
}
- Vector<uint8_t> blend_shapes;
+ Vector<uint8_t> blend_shapes_new;
if (d.has("blend_shape_data")) {
Array blend_shape_data = d["blend_shape_data"];
@@ -1263,7 +1263,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
Vector<uint8_t> shape = blend_shape_data[i];
_fix_array_compatibility(shape, old_format, new_format, vertex_count, blend_vertex_array, blend_attribute_array, blend_skin_array);
- blend_shapes.append_array(blend_vertex_array);
+ blend_shapes_new.append_array(blend_vertex_array);
}
}
@@ -1273,7 +1273,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
print_verbose("Mesh format post-conversion: " + itos(new_format));
ERR_FAIL_COND_V(!d.has("aabb"), false);
- AABB aabb = d["aabb"];
+ AABB aabb_new = d["aabb"];
Vector<AABB> bone_aabb;
if (d.has("skeleton_aabb")) {
@@ -1285,7 +1285,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
}
}
- add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb);
+ add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb_new, blend_shapes_new, bone_aabb);
} else {
ERR_FAIL_V(false);
@@ -1462,9 +1462,9 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
}
}
- String name;
+ String surf_name;
if (d.has("name")) {
- name = d["name"];
+ surf_name = d["name"];
}
bool _2d = false;
@@ -1474,7 +1474,7 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) {
surface_data.push_back(surface);
surface_materials.push_back(material);
- surface_names.push_back(name);
+ surface_names.push_back(surf_name);
surface_2d.push_back(_2d);
}
@@ -1576,9 +1576,8 @@ void ArrayMesh::_recompute_aabb() {
}
}
}
-#ifndef _MSC_VER
-#warning need to add binding to add_surface using future MeshSurfaceData object
-#endif
+
+// TODO: Need to add binding to add_surface using future MeshSurfaceData object.
void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
_create_if_empty();
@@ -1657,17 +1656,17 @@ int ArrayMesh::get_surface_count() const {
void ArrayMesh::add_blend_shape(const StringName &p_name) {
ERR_FAIL_COND_MSG(surfaces.size(), "Can't add a shape key count if surfaces are already created.");
- StringName name = p_name;
+ StringName shape_name = p_name;
- if (blend_shapes.has(name)) {
+ if (blend_shapes.has(shape_name)) {
int count = 2;
do {
- name = String(p_name) + " " + itos(count);
+ shape_name = String(p_name) + " " + itos(count);
count++;
- } while (blend_shapes.has(name));
+ } while (blend_shapes.has(shape_name));
}
- blend_shapes.push_back(name);
+ blend_shapes.push_back(shape_name);
if (mesh.is_valid()) {
RS::get_singleton()->mesh_set_blend_shape_count(mesh, blend_shapes.size());
@@ -1686,17 +1685,17 @@ StringName ArrayMesh::get_blend_shape_name(int p_index) const {
void ArrayMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
ERR_FAIL_INDEX(p_index, blend_shapes.size());
- StringName name = p_name;
- int found = blend_shapes.find(name);
+ StringName shape_name = p_name;
+ int found = blend_shapes.find(shape_name);
if (found != -1 && found != p_index) {
int count = 2;
do {
- name = String(p_name) + " " + itos(count);
+ shape_name = String(p_name) + " " + itos(count);
count++;
- } while (blend_shapes.find(name) != -1);
+ } while (blend_shapes.find(shape_name) != -1);
}
- blend_shapes.write[p_index] = name;
+ blend_shapes.write[p_index] = shape_name;
}
void ArrayMesh::clear_blend_shapes() {
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 2d3f9d9afc..7c78b757c7 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -33,10 +33,10 @@
#include "box_shape_3d.h"
bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.begins_with("item/")) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ String prop_name = p_name;
+ if (prop_name.begins_with("item/")) {
+ int idx = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (!item_map.has(idx)) {
create_item(idx);
}
@@ -72,10 +72,10 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
}
bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- int idx = name.get_slicec('/', 1).to_int();
+ String prop_name = p_name;
+ int idx = prop_name.get_slicec('/', 1).to_int();
ERR_FAIL_COND_V(!item_map.has(idx), false);
- String what = name.get_slicec('/', 2);
+ String what = prop_name.get_slicec('/', 2);
if (what == "name") {
r_ret = get_item_name(idx);
@@ -100,14 +100,14 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const {
void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const {
for (const KeyValue<int, Item> &E : item_map) {
- String name = vformat("%s/%d/", PNAME("item"), E.key);
- p_list->push_back(PropertyInfo(Variant::STRING, name + PNAME("name")));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
- p_list->push_back(PropertyInfo(Variant::ARRAY, name + PNAME("shapes")));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
- p_list->push_back(PropertyInfo(Variant::OBJECT, name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
+ String prop_name = vformat("%s/%d/", PNAME("item"), E.key);
+ p_list->push_back(PropertyInfo(Variant::STRING, prop_name + PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("mesh"), PROPERTY_HINT_RESOURCE_TYPE, "Mesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("mesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, prop_name + PNAME("shapes")));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("navmesh"), PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"));
+ p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prop_name + PNAME("navmesh_transform"), PROPERTY_HINT_NONE, "suffix:m"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + PNAME("preview"), PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT));
}
}
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 90ea879012..de97498674 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -527,7 +527,7 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
ADD_GROUP("Cells", "cell_");
@@ -590,16 +590,16 @@ void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
#ifndef DISABLE_DEPRECATED
bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name.find("/") != -1) {
+ String prop_name = p_name;
+ if (prop_name.find("/") != -1) {
// Compatibility with pre-3.5 "category/path" property names.
- name = name.replace("/", "_");
- if (name == "sample_partition_type_sample_partition_type") {
+ prop_name = prop_name.replace("/", "_");
+ if (prop_name == "sample_partition_type_sample_partition_type") {
set("sample_partition_type", p_value);
- } else if (name == "filter_filter_walkable_low_height_spans") {
+ } else if (prop_name == "filter_filter_walkable_low_height_spans") {
set("filter_walkable_low_height_spans", p_value);
} else {
- set(name, p_value);
+ set(prop_name, p_value);
}
return true;
@@ -608,16 +608,16 @@ bool NavigationMesh::_set(const StringName &p_name, const Variant &p_value) {
}
bool NavigationMesh::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name.find("/") != -1) {
+ String prop_name = p_name;
+ if (prop_name.find("/") != -1) {
// Compatibility with pre-3.5 "category/path" property names.
- name = name.replace("/", "_");
- if (name == "sample_partition_type_sample_partition_type") {
+ prop_name = prop_name.replace("/", "_");
+ if (prop_name == "sample_partition_type_sample_partition_type") {
r_ret = get("sample_partition_type");
- } else if (name == "filter_filter_walkable_low_height_spans") {
+ } else if (prop_name == "filter_filter_walkable_low_height_spans") {
r_ret = get("filter_walkable_low_height_spans");
} else {
- r_ret = get(name);
+ r_ret = get(prop_name);
}
return true;
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index e0bedad595..1c99fa5554 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -150,15 +150,15 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
} else if (n.instance >= 0) {
//instance a scene into this node
if (n.instance & FLAG_INSTANCE_IS_PLACEHOLDER) {
- String path = props[n.instance & FLAG_MASK];
+ String scene_path = props[n.instance & FLAG_MASK];
if (disable_placeholders) {
- Ref<PackedScene> sdata = ResourceLoader::load(path, "PackedScene");
+ Ref<PackedScene> sdata = ResourceLoader::load(scene_path, "PackedScene");
ERR_FAIL_COND_V(!sdata.is_valid(), nullptr);
node = sdata->instantiate(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE);
ERR_FAIL_COND_V(!node, nullptr);
} else {
InstancePlaceholder *ip = memnew(InstancePlaceholder);
- ip->set_instance_path(path);
+ ip->set_instance_path(scene_path);
node = ip;
}
node->set_scene_instance_load_placeholder(true);
@@ -938,8 +938,8 @@ Error SceneState::pack(Node *p_scene) {
// If using scene inheritance, pack the scene it inherits from.
if (scene->get_scene_inherited_state().is_valid()) {
- String path = scene->get_scene_inherited_state()->get_path();
- Ref<PackedScene> instance = ResourceLoader::load(path);
+ String scene_path = scene->get_scene_inherited_state()->get_path();
+ Ref<PackedScene> instance = ResourceLoader::load(scene_path);
if (instance.is_valid()) {
base_scene_idx = _vm_get_variant(instance, variant_map);
}
@@ -1546,7 +1546,7 @@ Array SceneState::get_connection_binds(int p_idx) const {
return binds;
}
-bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method) {
+bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance) {
// this method cannot be const because of this
Ref<SceneState> ss = this;
@@ -1578,6 +1578,10 @@ bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p
}
}
+ if (p_no_inheritance) {
+ break;
+ }
+
ss = ss->get_base_scene_state();
} while (ss.is_valid());
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 8e1a1d29b6..c6f82ddd5e 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -176,7 +176,7 @@ public:
int get_connection_unbinds(int p_idx) const;
Array get_connection_binds(int p_idx) const;
- bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method);
+ bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance = false);
Vector<NodePath> get_editable_instances() const;
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index e51c786786..b77430c154 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -115,6 +115,7 @@ void ParticleProcessMaterial::init_shaders() {
shader_names->sub_emitter_frequency = "sub_emitter_frequency";
shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end";
+ shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision";
shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity";
shader_names->collision_friction = "collision_friction";
@@ -235,6 +236,9 @@ void ParticleProcessMaterial::_update_shader() {
if (sub_emitter_mode == SUB_EMITTER_AT_END) {
code += "uniform int sub_emitter_amount_at_end;\n";
}
+ if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) {
+ code += "uniform int sub_emitter_amount_at_collision;\n";
+ }
code += "uniform bool sub_emitter_keep_velocity;\n";
}
@@ -830,6 +834,13 @@ void ParticleProcessMaterial::_update_shader() {
code += " TRANSFORM[3].z = 0.0;\n";
}
+ // scale by scale
+ code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
+ code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
+ code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
+ code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
+ code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
+
if (collision_mode == COLLISION_RIGID) {
code += " if (COLLIDED) {\n";
code += " if (length(VELOCITY) > 3.0) {\n";
@@ -844,21 +855,6 @@ void ParticleProcessMaterial::_update_shader() {
}
code += " }\n";
code += " }\n";
- }
-
- // scale by scale
- code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
- code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
- code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
- code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
- code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
-
- if (collision_mode == COLLISION_RIGID) {
- code += " if (COLLIDED) {\n";
- code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n";
- code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
- code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n";
- code += " }\n";
} else if (collision_mode == COLLISION_HIDE_ON_CONTACT) {
code += " if (COLLIDED) {\n";
code += " ACTIVE = false;\n";
@@ -874,7 +870,7 @@ void ParticleProcessMaterial::_update_shader() {
code += " if (DELTA >= interval_rem) emit_count = 1;\n";
} break;
case SUB_EMITTER_AT_COLLISION: {
- code += " if (COLLIDED) emit_count = 1;\n";
+ code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n";
} break;
case SUB_EMITTER_AT_END: {
code += " float unit_delta = DELTA/LIFETIME;\n";
@@ -1433,6 +1429,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const
p_property.usage = PROPERTY_USAGE_NONE;
}
+ if (p_property.name == "sub_emitter_amount_at_collision" && sub_emitter_mode != SUB_EMITTER_AT_COLLISION) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -1488,6 +1488,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const {
return sub_emitter_amount_at_end;
}
+void ParticleProcessMaterial::set_sub_emitter_amount_at_collision(int p_amount) {
+ sub_emitter_amount_at_collision = p_amount;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_collision, p_amount);
+}
+
+int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const {
+ return sub_emitter_amount_at_collision;
+}
+
void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
sub_emitter_keep_velocity = p_enable;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable);
@@ -1640,6 +1649,9 @@ void ParticleProcessMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end);
ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision);
+
ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity);
ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity);
@@ -1752,6 +1764,7 @@ void ParticleProcessMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
ADD_GROUP("Attractor Interaction", "attractor_interaction_");
@@ -1859,6 +1872,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() :
set_sub_emitter_mode(SUB_EMITTER_DISABLED);
set_sub_emitter_frequency(4);
set_sub_emitter_amount_at_end(1);
+ set_sub_emitter_amount_at_collision(1);
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h
index 9430e5797d..64d828b3e7 100644
--- a/scene/resources/particle_process_material.h
+++ b/scene/resources/particle_process_material.h
@@ -246,6 +246,7 @@ private:
StringName sub_emitter_frequency;
StringName sub_emitter_amount_at_end;
+ StringName sub_emitter_amount_at_collision;
StringName sub_emitter_keep_velocity;
StringName collision_friction;
@@ -265,9 +266,9 @@ private:
float spread = 0.0f;
float flatness = 0.0f;
- float params_min[PARAM_MAX];
- float params_max[PARAM_MAX];
- float params[PARAM_MAX];
+ float params_min[PARAM_MAX] = {};
+ float params_max[PARAM_MAX] = {};
+ float params[PARAM_MAX] = {};
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
@@ -304,6 +305,7 @@ private:
SubEmitterMode sub_emitter_mode;
double sub_emitter_frequency = 0.0;
int sub_emitter_amount_at_end = 0;
+ int sub_emitter_amount_at_collision = 0;
bool sub_emitter_keep_velocity = false;
//do not save emission points here
@@ -418,6 +420,9 @@ public:
void set_sub_emitter_amount_at_end(int p_amount);
int get_sub_emitter_amount_at_end() const;
+ void set_sub_emitter_amount_at_collision(int p_amount);
+ int get_sub_emitter_amount_at_collision() const;
+
void set_sub_emitter_keep_velocity(bool p_enable);
bool get_sub_emitter_keep_velocity() const;
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 5e18671c11..2c80e234e9 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -441,9 +441,9 @@ Dictionary PolygonPathFinder::_get_data() const {
Dictionary d;
Vector<Vector2> p;
Vector<int> ind;
- Array connections;
+ Array path_connections;
p.resize(MAX(0, points.size() - 2));
- connections.resize(MAX(0, points.size() - 2));
+ path_connections.resize(MAX(0, points.size() - 2));
ind.resize(edges.size() * 2);
Vector<real_t> penalties;
penalties.resize(MAX(0, points.size() - 2));
@@ -463,7 +463,7 @@ Dictionary PolygonPathFinder::_get_data() const {
cw[idx++] = E;
}
}
- connections[i] = c;
+ path_connections[i] = c;
}
}
{
@@ -478,7 +478,7 @@ Dictionary PolygonPathFinder::_get_data() const {
d["bounds"] = bounds;
d["points"] = p;
d["penalties"] = penalties;
- d["connections"] = connections;
+ d["connections"] = path_connections;
d["segments"] = ind;
return d;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index c017c90370..eb83a37c7b 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -771,6 +771,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
thisrow = 0;
prevrow = 0;
+ const real_t side_normal_y = (bottom_radius - top_radius) / height;
for (j = 0; j <= (rings + 1); j++) {
v = j;
v /= (rings + 1);
@@ -789,7 +790,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto
Vector3 p = Vector3(x * radius, y, z * radius);
points.push_back(p);
- normals.push_back(Vector3(x, 0.0, z));
+ normals.push_back(Vector3(x, side_normal_y, z).normalized());
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v * 0.5));
point++;
@@ -1078,7 +1079,7 @@ void PlaneMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X, Face Y, Face Z"), "set_orientation", "get_orientation");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X,Face Y,Face Z"), "set_orientation", "get_orientation");
BIND_ENUM_CONSTANT(FACE_X)
BIND_ENUM_CONSTANT(FACE_Y)
@@ -2443,17 +2444,17 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_clear(text_rid);
TS->shaped_text_set_direction(text_rid, text_direction);
- String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
- TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, font->get_opentype_features(), language);
+ String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
+ TS->shaped_text_add_string(text_rid, txt, font->get_rids(), font_size, font->get_opentype_features(), language);
for (int i = 0; i < TextServer::SPACING_MAX; i++) {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
Array stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
- GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt);
+ GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
- stt = TS->parse_structured_text(st_parser, st_args, text);
+ stt = TS->parse_structured_text(st_parser, st_args, txt);
}
TS->shaped_text_set_bidi_override(text_rid, stt);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 0d798d2e27..85b538b1d9 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -445,7 +445,14 @@ Error ResourceLoaderText::load() {
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
path = ResourceUID::get_singleton()->get_id_path(uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(path) != uid) {
+ WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data());
+#endif
}
}
@@ -1114,10 +1121,10 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
//go with external resources
DummyReadData dummy_read;
- VariantParser::ResourceParser rp;
- rp.ext_func = _parse_ext_resource_dummys;
- rp.sub_func = _parse_sub_resource_dummys;
- rp.userdata = &dummy_read;
+ VariantParser::ResourceParser rp_new;
+ rp_new.ext_func = _parse_ext_resource_dummys;
+ rp_new.sub_func = _parse_sub_resource_dummys;
+ rp_new.userdata = &dummy_read;
while (next_tag.name == "ext_resource") {
if (!next_tag.fields.has("path")) {
@@ -1161,7 +1168,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
dummy_read.external_resources[dr] = lindex;
dummy_read.rev_external_resources[id] = dr;
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
if (error) {
_printerr();
@@ -1244,7 +1251,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (main_res && error == ERR_FILE_EOF) {
@@ -1288,7 +1295,7 @@ Error ResourceLoaderText::save_as_binary(const String &p_path) {
return error;
}
- Ref<PackedScene> packed_scene = _parse_node_tag(rp);
+ Ref<PackedScene> packed_scene = _parse_node_tag(rp_new);
if (!packed_scene.is_valid()) {
return error;
@@ -1363,13 +1370,13 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
DummyReadData dummy_read;
dummy_read.no_placeholders = true;
- VariantParser::ResourceParser rp;
- rp.ext_func = _parse_ext_resource_dummys;
- rp.sub_func = _parse_sub_resource_dummys;
- rp.userdata = &dummy_read;
+ VariantParser::ResourceParser rp_new;
+ rp_new.ext_func = _parse_ext_resource_dummys;
+ rp_new.sub_func = _parse_sub_resource_dummys;
+ rp_new.userdata = &dummy_read;
while (next_tag.name == "ext_resource") {
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp_new);
if (error) {
_printerr();
@@ -1396,7 +1403,7 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (error == ERR_FILE_EOF) {
@@ -1444,7 +1451,7 @@ Error ResourceLoaderText::get_classes_used(HashSet<StringName> *r_classes) {
String assign;
Variant value;
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new);
if (error) {
if (error == ERR_FILE_MISSING_DEPENDENCIES) {
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index fe43f345d4..61daf801e8 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -105,6 +105,7 @@ void Shape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts);
ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts);
ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw);
+ ClassDB::bind_method(D_METHOD("get_rect"), &Shape2D::get_rect);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias");
}
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index 885cf0f1b8..1b7354853d 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -127,7 +127,7 @@ void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_b
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
@@ -230,7 +230,7 @@ void SkeletonModification2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_draw_gizmo"), &SkeletonModification2D::get_editor_draw_gizmo);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification2D::SkeletonModification2D() {
diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp
index d3c62e441f..6593f476f5 100644
--- a/scene/resources/skeleton_modification_2d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp
@@ -212,7 +212,7 @@ void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() {
Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4);
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color");
+ bone_ik_color = EDITOR_GET("editors/2d/bone_ik_color");
}
#endif // TOOLS_ENABLED
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index 2c0f6e779e..fa487cb061 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -142,7 +142,7 @@ void SkeletonModification3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification3D::clamp_angle);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
}
SkeletonModification3D::SkeletonModification3D() {
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
index 3251ee4189..82dc30ec5f 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_3d_ccdik.cpp
@@ -98,7 +98,7 @@ void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list)
p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::INT, base_string + "ccdik_axis",
- PROPERTY_HINT_ENUM, "X Axis, Y Axis, Z Axis", PROPERTY_USAGE_DEFAULT));
+ PROPERTY_HINT_ENUM, "X Axis,Y Axis,Z Axis", PROPERTY_USAGE_DEFAULT));
p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_joint_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (ccdik_data_chain[i].enable_constraint) {
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
index 69167cb308..8ada7d0a5b 100644
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ b/scene/resources/skeleton_modification_3d_lookat.cpp
@@ -67,7 +67,7 @@ bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret
void SkeletonModification3DLookAt::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "lock_rotation_to_plane", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
if (lock_rotation_to_plane) {
- p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane, Y plane, Z plane", PROPERTY_USAGE_DEFAULT));
+ p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane,Y plane,Z plane", PROPERTY_USAGE_DEFAULT));
}
p_list->push_back(PropertyInfo(Variant::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
}
diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp
index 1c04ba0cd4..9d320e0b2c 100644
--- a/scene/resources/skin.cpp
+++ b/scene/resources/skin.cpp
@@ -86,13 +86,13 @@ void Skin::reset_state() {
}
bool Skin::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name == "bind_count") {
+ String prop_name = p_name;
+ if (prop_name == "bind_count") {
set_bind_count(p_value);
return true;
- } else if (name.begins_with("bind/")) {
- int index = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("bind/")) {
+ int index = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
set_bind_bone(index, p_value);
return true;
@@ -108,13 +108,13 @@ bool Skin::_set(const StringName &p_name, const Variant &p_value) {
}
bool Skin::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name == "bind_count") {
+ String prop_name = p_name;
+ if (prop_name == "bind_count") {
r_ret = get_bind_count();
return true;
- } else if (name.begins_with("bind/")) {
- int index = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
+ } else if (prop_name.begins_with("bind/")) {
+ int index = prop_name.get_slicec('/', 1).to_int();
+ String what = prop_name.get_slicec('/', 2);
if (what == "bone") {
r_ret = get_bind_bone(index);
return true;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 3533e86c3a..838566f696 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -143,10 +143,10 @@ Array SpriteFrames::_get_animations() const {
get_animation_list(&sorted_names);
sorted_names.sort_custom<StringName::AlphCompare>();
- for (const StringName &name : sorted_names) {
- const Anim &anim = animations[name];
+ for (const StringName &anim_name : sorted_names) {
+ const Anim &anim = animations[anim_name];
Dictionary d;
- d["name"] = name;
+ d["name"] = anim_name;
d["speed"] = anim.speed;
d["loop"] = anim.loop;
Array frames;
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index cd893d8c23..f379f88bed 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -43,12 +43,9 @@ float StyleBox::get_style_margin(Side p_side) const {
}
bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const {
- bool ret;
- if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret);
+ return ret;
}
void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const {
@@ -109,11 +106,8 @@ Point2 StyleBox::get_offset() const {
Size2 StyleBox::get_center_size() const {
Size2 ret;
- if (GDVIRTUAL_CALL(_get_center_size, ret)) {
- return ret;
- }
-
- return Size2();
+ GDVIRTUAL_CALL(_get_center_size, ret);
+ return ret;
}
Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const {
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 9829c7e86b..94967352c8 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -986,7 +986,7 @@ void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const
format = 0;
}
- uint32_t nformat;
+ uint32_t nformat = 0;
LocalVector<Vertex> nvertices;
LocalVector<int> nindices;
_create_list(p_existing, p_surface, &nvertices, &nindices, nformat);
diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp
index 823d742d72..ca1cd54349 100644
--- a/scene/resources/text_line.cpp
+++ b/scene/resources/text_line.cpp
@@ -218,7 +218,48 @@ Array TextLine::get_objects() const {
}
Rect2 TextLine::get_object_rect(Variant p_key) const {
- return TS->shaped_text_get_object_rect(rid, p_key);
+ Vector2 ofs;
+
+ float length = TS->shaped_text_get_width(rid);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= width) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(rid) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += width - length;
+ } else {
+ ofs.y += width - length;
+ }
+ } break;
+ }
+ }
+ if (TS->shaped_text_get_orientation(rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.y += TS->shaped_text_get_ascent(rid);
+ } else {
+ ofs.x += TS->shaped_text_get_ascent(rid);
+ }
+
+ Rect2 rect = TS->shaped_text_get_object_rect(rid, p_key);
+ rect.position += ofs;
+
+ return rect;
}
void TextLine::set_horizontal_alignment(HorizontalAlignment p_alignment) {
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 7e9a2591e4..59bb24c8b8 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -540,16 +540,90 @@ Rect2 TextParagraph::get_line_object_rect(int p_line, Variant p_key) const {
const_cast<TextParagraph *>(this)->_shape_lines();
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)lines_rid.size(), Rect2());
- Rect2 xrect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
- for (int i = 0; i < p_line; i++) {
- Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
+
+ Vector2 ofs;
+
+ float h_offset = 0.f;
+ if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x;
+ } else {
+ h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y;
+ }
+
+ for (int i = 0; i <= p_line; i++) {
+ float l_width = width;
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- xrect.position.y += lsize.y;
+ ofs.x = 0.f;
+ ofs.y += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
} else {
- xrect.position.x += lsize.x;
+ ofs.y = 0.f;
+ ofs.x += TS->shaped_text_get_ascent(lines_rid[i]);
+ if (i <= dropcap_lines) {
+ if (TS->shaped_text_get_inferred_direction(dropcap_rid) == TextServer::DIRECTION_LTR) {
+ ofs.x -= h_offset;
+ }
+ l_width -= h_offset;
+ }
+ }
+ float length = TS->shaped_text_get_width(lines_rid[i]);
+ if (width > 0) {
+ switch (alignment) {
+ case HORIZONTAL_ALIGNMENT_FILL:
+ if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ break;
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ break;
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ if (length <= l_width) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += Math::floor((l_width - length) / 2.0);
+ } else {
+ ofs.y += Math::floor((l_width - length) / 2.0);
+ }
+ } else if (TS->shaped_text_get_inferred_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ }
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x += l_width - length;
+ } else {
+ ofs.y += l_width - length;
+ }
+ } break;
+ }
+ }
+ if (i != p_line) {
+ if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
+ ofs.x = 0.f;
+ ofs.y += TS->shaped_text_get_descent(lines_rid[i]);
+ } else {
+ ofs.y = 0.f;
+ ofs.x += TS->shaped_text_get_descent(lines_rid[i]);
+ }
}
}
- return xrect;
+
+ Rect2 rect = TS->shaped_text_get_object_rect(lines_rid[p_line], p_key);
+ rect.position += ofs;
+
+ return rect;
}
Size2 TextParagraph::get_line_size(int p_line) const {
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 15678c9281..5232e8fcab 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -60,20 +60,14 @@ Size2 Texture2D::get_size() const {
}
bool Texture2D::is_pixel_opaque(int p_x, int p_y) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret);
+ return ret;
}
bool Texture2D::has_alpha() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_alpha, ret)) {
- return ret;
- }
-
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_has_alpha, ret);
+ return ret;
}
void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {
@@ -122,7 +116,7 @@ void Texture2D::_bind_methods() {
GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose")
GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose")
- GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
+ GDVIRTUAL_BIND(_draw_rect_region, "to_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv");
}
Texture2D::Texture2D() {
@@ -653,7 +647,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
Image::Format format = Image::Format(f->get_32());
if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) {
- //look for a PNG or WEBP file inside
+ //look for a PNG or WebP file inside
int sw = w;
int sh = h;
@@ -740,7 +734,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
}
}
- image->create(w, h, true, mipmap_images[0]->get_format(), img_data);
+ image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);
return image;
}
@@ -766,10 +760,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
f->get_buffer(wr, data.size());
}
- Ref<Image> image;
- image.instantiate();
-
- image->create(tw, th, mipmaps - i ? true : false, format, data);
+ Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);
return image;
}
@@ -1209,6 +1200,8 @@ Error ImageTexture3D::create(Image::Format p_format, int p_width, int p_height,
if (texture.is_valid()) {
RenderingServer::get_singleton()->texture_replace(texture, tex);
+ } else {
+ texture = tex;
}
return OK;
@@ -1286,15 +1279,15 @@ Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &
f->get_32(); // ignored (data format)
f->get_32(); //ignored
- int mipmaps = f->get_32();
+ int mipmap_count = f->get_32();
f->get_32(); //ignored
f->get_32(); //ignored
- r_mipmaps = mipmaps != 0;
+ r_mipmaps = mipmap_count != 0;
r_data.clear();
- for (int i = 0; i < (r_depth + mipmaps); i++) {
+ for (int i = 0; i < (r_depth + mipmap_count); i++) {
Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);
ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);
if (i == 0) {
@@ -1489,7 +1482,15 @@ void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) {
if (atlas == p_atlas) {
return;
}
+ // Support recursive AtlasTextures.
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->disconnect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
atlas = p_atlas;
+ if (Ref<AtlasTexture>(atlas).is_valid()) {
+ atlas->connect(CoreStringNames::get_singleton()->changed, callable_mp((Resource *)this, &AtlasTexture::emit_changed));
+ }
+
emit_changed();
}
@@ -2326,11 +2327,11 @@ void GradientTexture2D::_update() {
image.instantiate();
if (gradient->get_points_count() <= 1) { // No need to interpolate.
- image->create(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
+ image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8);
image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1));
} else {
if (use_hdr) {
- image->create(width, height, false, Image::FORMAT_RGBAF);
+ image->initialize_data(width, height, false, Image::FORMAT_RGBAF);
Gradient &g = **gradient;
// `create()` isn't available for non-uint8_t data, so fill in the data manually.
for (int y = 0; y < height; y++) {
@@ -2357,7 +2358,7 @@ void GradientTexture2D::_update() {
}
}
}
- image->create(width, height, false, Image::FORMAT_RGBA8, data);
+ image->set_data(width, height, false, Image::FORMAT_RGBA8, data);
}
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 4e529de8ee..9a9f0ad1af 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -238,7 +238,7 @@ private:
Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
mutable Ref<BitMap> alpha_cache;
@@ -415,7 +415,7 @@ class ImageTextureLayered : public TextureLayered {
LayeredType layered_type;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 0;
int height = 0;
@@ -495,7 +495,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int layers = 0;
@@ -587,7 +587,7 @@ class ImageTexture3D : public Texture3D {
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int width = 1;
int height = 1;
int depth = 1;
@@ -641,7 +641,7 @@ private:
Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps);
String path_to_file;
mutable RID texture;
- Image::Format format = Image::FORMAT_MAX;
+ Image::Format format = Image::FORMAT_L8;
int w = 0;
int h = 0;
int d = 0;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 3321392821..ed0d5ee688 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -40,20 +40,20 @@ bool Theme::_set(const StringName &p_name, const Variant &p_value) {
if (sname.contains("/")) {
String type = sname.get_slicec('/', 1);
String theme_type = sname.get_slicec('/', 0);
- String name = sname.get_slicec('/', 2);
+ String prop_name = sname.get_slicec('/', 2);
if (type == "icons") {
- set_icon(name, theme_type, p_value);
+ set_icon(prop_name, theme_type, p_value);
} else if (type == "styles") {
- set_stylebox(name, theme_type, p_value);
+ set_stylebox(prop_name, theme_type, p_value);
} else if (type == "fonts") {
- set_font(name, theme_type, p_value);
+ set_font(prop_name, theme_type, p_value);
} else if (type == "font_sizes") {
- set_font_size(name, theme_type, p_value);
+ set_font_size(prop_name, theme_type, p_value);
} else if (type == "colors") {
- set_color(name, theme_type, p_value);
+ set_color(prop_name, theme_type, p_value);
} else if (type == "constants") {
- set_constant(name, theme_type, p_value);
+ set_constant(prop_name, theme_type, p_value);
} else if (type == "base_type") {
set_type_variation(theme_type, p_value);
} else {
@@ -72,32 +72,32 @@ bool Theme::_get(const StringName &p_name, Variant &r_ret) const {
if (sname.contains("/")) {
String type = sname.get_slicec('/', 1);
String theme_type = sname.get_slicec('/', 0);
- String name = sname.get_slicec('/', 2);
+ String prop_name = sname.get_slicec('/', 2);
if (type == "icons") {
- if (!has_icon(name, theme_type)) {
+ if (!has_icon(prop_name, theme_type)) {
r_ret = Ref<Texture2D>();
} else {
- r_ret = get_icon(name, theme_type);
+ r_ret = get_icon(prop_name, theme_type);
}
} else if (type == "styles") {
- if (!has_stylebox(name, theme_type)) {
+ if (!has_stylebox(prop_name, theme_type)) {
r_ret = Ref<StyleBox>();
} else {
- r_ret = get_stylebox(name, theme_type);
+ r_ret = get_stylebox(prop_name, theme_type);
}
} else if (type == "fonts") {
- if (!has_font(name, theme_type)) {
+ if (!has_font(prop_name, theme_type)) {
r_ret = Ref<Font>();
} else {
- r_ret = get_font(name, theme_type);
+ r_ret = get_font(prop_name, theme_type);
}
} else if (type == "font_sizes") {
- r_ret = get_font_size(name, theme_type);
+ r_ret = get_font_size(prop_name, theme_type);
} else if (type == "colors") {
- r_ret = get_color(name, theme_type);
+ r_ret = get_color(prop_name, theme_type);
} else if (type == "constants") {
- r_ret = get_constant(name, theme_type);
+ r_ret = get_constant(prop_name, theme_type);
} else if (type == "base_type") {
r_ret = get_type_variation_base(theme_type);
} else {
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 65f3767449..3caf6484d9 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -1801,11 +1801,11 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) {
// Get the best tile.
Ref<Texture2D> texture = counts[terrain_set][terrain].texture;
Rect2i region = counts[terrain_set][terrain].region;
- image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
+ image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8);
image->blit_rect(texture->get_image(), region, Point2i());
image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST);
} else {
- image->create(1, 1, false, Image::FORMAT_RGBA8);
+ image->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain));
}
Ref<ImageTexture> icon = ImageTexture::create_from_image(image);
@@ -3779,14 +3779,14 @@ bool TileSetAtlasSource::get_use_texture_padding() const {
}
Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
- Ref<Texture2D> texture = get_texture();
- if (!texture.is_valid()) {
+ Ref<Texture2D> txt = get_texture();
+ if (!txt.is_valid()) {
return Vector2i();
}
ERR_FAIL_COND_V(texture_region_size.x <= 0 || texture_region_size.y <= 0, Vector2i());
- Size2i valid_area = texture->get_size() - margins;
+ Size2i valid_area = txt->get_size() - margins;
// Compute the number of valid tiles in the tiles atlas
Size2i grid_size = Size2i();
@@ -4602,9 +4602,7 @@ void TileSetAtlasSource::_update_padded_texture() {
return;
}
- Ref<Image> image;
- image.instantiate();
- image->create(size.x, size.y, false, src->get_format());
+ Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format());
for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) {
for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) {
@@ -5017,7 +5015,7 @@ void TileData::add_custom_data_layer(int p_to_pos) {
void TileData::move_custom_data_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, custom_data.size());
ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
- custom_data.insert(p_to_pos, navigation[p_from_index]);
+ custom_data.insert(p_to_pos, custom_data[p_from_index]);
custom_data.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index e156679711..8f175e99a6 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -277,6 +277,9 @@ public:
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
+ bool operator!=(const TerrainsPattern &p_terrains_pattern) const {
+ return !operator==(p_terrains_pattern);
+ };
void set_terrain(int p_terrain);
int get_terrain() const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 320889679d..b30ca3e721 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -456,11 +456,9 @@ void VisualShaderNodeCustom::update_ports() {
}
String VisualShaderNodeCustom::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_name, ret)) {
- return ret;
- }
- return "Unnamed";
+ String ret = "Unnamed";
+ GDVIRTUAL_CALL(_get_name, ret);
+ return ret;
}
int VisualShaderNodeCustom::get_input_port_count() const {
@@ -559,11 +557,9 @@ String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, Vis
}
bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) {
- return ret;
- }
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret);
+ return ret;
}
void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) {
@@ -955,7 +951,7 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
}
bool VisualShader::is_port_types_compatible(int p_a, int p_b) const {
- return MAX(0, p_a - 4) == (MAX(0, p_b - 4));
+ return MAX(0, p_a - 5) == (MAX(0, p_b - 5));
}
void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
@@ -1148,7 +1144,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
StringBuilder global_code;
StringBuilder global_code_per_node;
HashMap<Type, StringBuilder> global_code_per_func;
- StringBuilder code;
+ StringBuilder shader_code;
HashSet<StringName> classes;
global_code += String() + "shader_type canvas_item;\n";
@@ -1189,69 +1185,69 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
input_connections.insert(to_key, E);
}
- code += "\nvoid fragment() {\n";
+ shader_code += "\nvoid fragment() {\n";
HashSet<int> processed;
- Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
+ Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, shader_code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
ERR_FAIL_COND_V(err != OK, String());
switch (node->get_output_port_type(p_port)) {
case VisualShaderNode::PORT_TYPE_SCALAR: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ");\n";
} break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT: {
- code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n";
+ shader_code += " COLOR.rgb = vec3(float(n_out" + itos(p_node) + "p" + itos(p_port) + "));\n";
} break;
case VisualShaderNode::PORT_TYPE_BOOLEAN: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + " ? 1.0 : 0.0);\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n";
+ shader_code += " COLOR.rgb = vec3(n_out" + itos(p_node) + "p" + itos(p_port) + ", 0.0);\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
+ shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ";\n";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
+ shader_code += " COLOR.rgb = n_out" + itos(p_node) + "p" + itos(p_port) + ".xyz;\n";
} break;
default: {
- code += " COLOR.rgb = vec3(0.0);\n";
+ shader_code += " COLOR.rgb = vec3(0.0);\n";
} break;
}
- code += "}\n";
+ shader_code += "}\n";
//set code secretly
global_code += "\n\n";
String final_code = global_code;
final_code += global_code_per_node;
- final_code += code;
+ final_code += shader_code;
return final_code;
}
String VisualShader::validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const {
- String name = p_port_name;
+ String port_name = p_port_name;
- if (name.is_empty()) {
+ if (port_name.is_empty()) {
return String();
}
- while (name.length() && !is_ascii_char(name[0])) {
- name = name.substr(1, name.length() - 1);
+ while (port_name.length() && !is_ascii_char(port_name[0])) {
+ port_name = port_name.substr(1, port_name.length() - 1);
}
- if (!name.is_empty()) {
+ if (!port_name.is_empty()) {
String valid_name;
- for (int i = 0; i < name.length(); i++) {
- if (is_ascii_identifier_char(name[i])) {
- valid_name += String::chr(name[i]);
- } else if (name[i] == ' ') {
+ for (int i = 0; i < port_name.length(); i++) {
+ if (is_ascii_identifier_char(port_name[i])) {
+ valid_name += String::chr(port_name[i]);
+ } else if (port_name[i] == ' ') {
valid_name += "_";
}
}
- name = valid_name;
+ port_name = valid_name;
} else {
return String();
}
@@ -1263,7 +1259,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
if (!p_output && i == p_port_id) {
continue;
}
- if (name == p_node->get_input_port_name(i)) {
+ if (port_name == p_node->get_input_port_name(i)) {
return String();
}
}
@@ -1271,35 +1267,35 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN
if (p_output && i == p_port_id) {
continue;
}
- if (name == p_node->get_output_port_name(i)) {
+ if (port_name == p_node->get_output_port_name(i)) {
return String();
}
}
- return name;
+ return port_name;
}
String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const {
- String name = p_name; //validate name first
- while (name.length() && !is_ascii_char(name[0])) {
- name = name.substr(1, name.length() - 1);
+ String param_name = p_name; //validate name first
+ while (param_name.length() && !is_ascii_char(param_name[0])) {
+ param_name = param_name.substr(1, param_name.length() - 1);
}
- if (!name.is_empty()) {
+ if (!param_name.is_empty()) {
String valid_name;
- for (int i = 0; i < name.length(); i++) {
- if (is_ascii_identifier_char(name[i])) {
- valid_name += String::chr(name[i]);
- } else if (name[i] == ' ') {
+ for (int i = 0; i < param_name.length(); i++) {
+ if (is_ascii_identifier_char(param_name[i])) {
+ valid_name += String::chr(param_name[i]);
+ } else if (param_name[i] == ' ') {
valid_name += "_";
}
}
- name = valid_name;
+ param_name = valid_name;
}
- if (name.is_empty()) {
- name = p_parameter->get_caption();
+ if (param_name.is_empty()) {
+ param_name = p_parameter->get_caption();
}
int attempt = 1;
@@ -1312,7 +1308,7 @@ String VisualShader::validate_parameter_name(const String &p_name, const Ref<Vis
if (node == p_parameter) { //do not test on self
continue;
}
- if (node.is_valid() && node->get_parameter_name() == name) {
+ if (node.is_valid() && node->get_parameter_name() == param_name) {
exists = true;
break;
}
@@ -1325,17 +1321,17 @@ String VisualShader::validate_parameter_name(const String &p_name, const Ref<Vis
if (exists) {
//remove numbers, put new and try again
attempt++;
- while (name.length() && is_digit(name[name.length() - 1])) {
- name = name.substr(0, name.length() - 1);
+ while (param_name.length() && is_digit(param_name[param_name.length() - 1])) {
+ param_name = param_name.substr(0, param_name.length() - 1);
}
- ERR_FAIL_COND_V(name.is_empty(), String());
- name += itos(attempt);
+ ERR_FAIL_COND_V(param_name.is_empty(), String());
+ param_name += itos(attempt);
} else {
break;
}
}
- return name;
+ return param_name;
}
static const char *type_string[VisualShader::TYPE_MAX] = {
@@ -1352,12 +1348,12 @@ static const char *type_string[VisualShader::TYPE_MAX] = {
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
- if (name == "mode") {
+ String prop_name = p_name;
+ if (prop_name == "mode") {
set_mode(Shader::Mode(int(p_value)));
return true;
- } else if (name.begins_with("flags/")) {
- StringName flag = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("flags/")) {
+ StringName flag = prop_name.get_slicec('/', 1);
bool enable = p_value;
if (enable) {
flags.insert(flag);
@@ -1366,18 +1362,18 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
- } else if (name.begins_with("modes/")) {
- String mode = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("modes/")) {
+ String mode_name = prop_name.get_slicec('/', 1);
int value = p_value;
if (value == 0) {
- modes.erase(mode); //means it's default anyway, so don't store it
+ modes.erase(mode_name); //means it's default anyway, so don't store it
} else {
- modes[mode] = value;
+ modes[mode_name] = value;
}
_queue_update();
return true;
- } else if (name.begins_with("varyings/")) {
- String var_name = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("varyings/")) {
+ String var_name = prop_name.get_slicec('/', 1);
Varying value = Varying();
value.name = var_name;
if (value.from_string(p_value) && !varyings.has(var_name)) {
@@ -1386,8 +1382,8 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
_queue_update();
return true;
- } else if (name.begins_with("nodes/")) {
- String typestr = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("nodes/")) {
+ String typestr = prop_name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
for (int i = 0; i < TYPE_MAX; i++) {
if (typestr == type_string[i]) {
@@ -1396,7 +1392,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
}
- String index = name.get_slicec('/', 2);
+ String index = prop_name.get_slicec('/', 2);
if (index == "connections") {
Vector<int> conns = p_value;
if (conns.size() % 4 == 0) {
@@ -1408,7 +1404,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
int id = index.to_int();
- String what = name.get_slicec('/', 3);
+ String what = prop_name.get_slicec('/', 3);
if (what == "node") {
add_node(type, p_value, Vector2(), id);
@@ -1434,32 +1430,32 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
}
bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name;
- if (name == "mode") {
+ String prop_name = p_name;
+ if (prop_name == "mode") {
r_ret = get_mode();
return true;
- } else if (name.begins_with("flags/")) {
- StringName flag = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("flags/")) {
+ StringName flag = prop_name.get_slicec('/', 1);
r_ret = flags.has(flag);
return true;
- } else if (name.begins_with("modes/")) {
- String mode = name.get_slicec('/', 1);
- if (modes.has(mode)) {
- r_ret = modes[mode];
+ } else if (prop_name.begins_with("modes/")) {
+ String mode_name = prop_name.get_slicec('/', 1);
+ if (modes.has(mode_name)) {
+ r_ret = modes[mode_name];
} else {
r_ret = 0;
}
return true;
- } else if (name.begins_with("varyings/")) {
- String var_name = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("varyings/")) {
+ String var_name = prop_name.get_slicec('/', 1);
if (varyings.has(var_name)) {
r_ret = varyings[var_name].to_string();
} else {
r_ret = String();
}
return true;
- } else if (name.begins_with("nodes/")) {
- String typestr = name.get_slicec('/', 1);
+ } else if (prop_name.begins_with("nodes/")) {
+ String typestr = prop_name.get_slicec('/', 1);
Type type = TYPE_VERTEX;
for (int i = 0; i < TYPE_MAX; i++) {
if (typestr == type_string[i]) {
@@ -1468,7 +1464,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
}
- String index = name.get_slicec('/', 2);
+ String index = prop_name.get_slicec('/', 2);
if (index == "connections") {
Vector<int> conns;
for (const Connection &E : graph[type].connections) {
@@ -1483,7 +1479,7 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
int id = index.to_int();
- String what = name.get_slicec('/', 3);
+ String what = prop_name.get_slicec('/', 3);
if (what == "node") {
r_ret = get_node(type, id);
@@ -1509,11 +1505,10 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
}
void VisualShader::reset_state() {
-#ifndef _MSC_VER
-#warning everything needs to be cleared here
-#endif
+ // TODO: Everything needs to be cleared here.
emit_changed();
}
+
void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
//mode
p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog"));
@@ -1580,12 +1575,12 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const {
- const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
+Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<VisualShader::DefaultTextureParam> &r_def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &p_output_connections, int p_node, HashSet<int> &r_processed, bool p_for_preview, HashSet<StringName> &r_classes) const {
+ const Ref<VisualShaderNode> vsnode = graph[type].nodes[p_node].node;
if (vsnode->is_disabled()) {
- code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
- code += " // Node is disabled and code is not generated.\n";
+ r_code += "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
+ r_code += " // Node is disabled and code is not generated.\n";
return OK;
}
@@ -1593,16 +1588,16 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
int input_count = vsnode->get_input_port_count();
for (int i = 0; i < input_count; i++) {
ConnectionKey ck;
- ck.node = node;
+ ck.node = p_node;
ck.port = i;
- if (input_connections.has(ck)) {
- int from_node = input_connections[ck]->get().from_node;
- if (processed.has(from_node)) {
+ if (p_input_connections.has(ck)) {
+ int from_node = p_input_connections[ck]->get().from_node;
+ if (r_processed.has(from_node)) {
continue;
}
- Error err = _write_node(type, global_code, global_code_per_node, global_code_per_func, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview, r_classes);
+ Error err = _write_node(type, p_global_code, p_global_code_per_node, p_global_code_per_func, r_code, r_def_tex_params, p_input_connections, p_output_connections, from_node, r_processed, p_for_preview, r_classes);
if (err) {
return err;
}
@@ -1611,19 +1606,19 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
// then this node
- Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
+ Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, p_node);
for (int i = 0; i < params.size(); i++) {
- def_tex_params.push_back(params[i]);
+ r_def_tex_params.push_back(params[i]);
}
Ref<VisualShaderNodeInput> input = vsnode;
- bool skip_global = input.is_valid() && for_preview;
+ bool skip_global = input.is_valid() && p_for_preview;
if (!skip_global) {
Ref<VisualShaderNodeParameter> parameter = vsnode;
if (!parameter.is_valid() || !parameter->is_global_code_generated()) {
- if (global_code) {
- *global_code += vsnode->generate_global(get_mode(), type, node);
+ if (p_global_code) {
+ *p_global_code += vsnode->generate_global(get_mode(), type, p_node);
}
}
@@ -1632,12 +1627,12 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
class_name = vsnode->get_script_instance()->get_script()->get_path();
}
if (!r_classes.has(class_name)) {
- if (global_code_per_node) {
- *global_code_per_node += vsnode->generate_global_per_node(get_mode(), node);
+ if (p_global_code_per_node) {
+ *p_global_code_per_node += vsnode->generate_global_per_node(get_mode(), p_node);
}
for (int i = 0; i < TYPE_MAX; i++) {
- if (global_code_per_func) {
- (*global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+ if (p_global_code_per_func) {
+ (*p_global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), p_node);
}
}
r_classes.insert(class_name);
@@ -1645,11 +1640,11 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
if (!vsnode->is_code_generated()) { // just generate globals and ignore locals
- processed.insert(node);
+ r_processed.insert(p_node);
return OK;
}
- String node_name = "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
+ String node_name = "// " + vsnode->get_caption() + ":" + itos(p_node) + "\n";
String node_code;
Vector<String> input_vars;
@@ -1658,18 +1653,18 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
for (int i = 0; i < input_count; i++) {
ConnectionKey ck;
- ck.node = node;
+ ck.node = p_node;
ck.port = i;
- if (input_connections.has(ck)) {
+ if (p_input_connections.has(ck)) {
//connected to something, use that output
- int from_node = input_connections[ck]->get().from_node;
+ int from_node = p_input_connections[ck]->get().from_node;
if (graph[type].nodes[from_node].node->is_disabled()) {
continue;
}
- int from_port = input_connections[ck]->get().from_port;
+ int from_port = p_input_connections[ck]->get().from_port;
VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
VisualShaderNode::PortType out_type = graph[type].nodes[from_node].node->get_output_port_type(from_port);
@@ -1826,32 +1821,32 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
Variant defval = vsnode->get_input_port_default_value(i);
if (defval.get_type() == Variant::FLOAT) {
float val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " float " + inputs[i] + " = " + vformat("%.5f", val) + ";\n";
} else if (defval.get_type() == Variant::INT) {
int val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " int " + inputs[i] + " = " + itos(val) + ";\n";
} else if (defval.get_type() == Variant::BOOL) {
bool val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " bool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n";
} else if (defval.get_type() == Variant::VECTOR2) {
Vector2 val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec2 " + inputs[i] + " = " + vformat("vec2(%.5f, %.5f);\n", val.x, val.y);
} else if (defval.get_type() == Variant::VECTOR3) {
Vector3 val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z);
} else if (defval.get_type() == Variant::QUATERNION) {
Quaternion val = defval;
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
node_code += " vec4 " + inputs[i] + " = " + vformat("vec4(%.5f, %.5f, %.5f, %.5f);\n", val.x, val.y, val.z, val.w);
} else if (defval.get_type() == Variant::TRANSFORM3D) {
Transform3D val = defval;
val.basis.transpose();
- inputs[i] = "n_in" + itos(node) + "p" + itos(i);
+ inputs[i] = "n_in" + itos(p_node) + "p" + itos(i);
Array values;
for (int j = 0; j < 3; j++) {
values.push_back(val.basis[j].x);
@@ -1903,7 +1898,7 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
if (vsnode->is_simple_decl()) { // less code to generate for some simple_decl nodes
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
- String var_name = "n_out" + itos(node) + "p" + itos(j);
+ String var_name = "n_out" + itos(p_node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
outputs[i] = "float " + var_name;
@@ -1948,28 +1943,28 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
} else {
for (int i = 0, j = 0; i < initial_output_count; i++, j++) {
- outputs[i] = "n_out" + itos(node) + "p" + itos(j);
+ outputs[i] = "n_out" + itos(p_node) + "p" + itos(j);
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_SCALAR:
- code += " float " + outputs[i] + ";\n";
+ r_code += " float " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_SCALAR_INT:
- code += " int " + outputs[i] + ";\n";
+ r_code += " int " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D:
- code += " vec2 " + outputs[i] + ";\n";
+ r_code += " vec2 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D:
- code += " vec3 " + outputs[i] + ";\n";
+ r_code += " vec3 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D:
- code += " vec4 " + outputs[i] + ";\n";
+ r_code += " vec4 " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_BOOLEAN:
- code += " bool " + outputs[i] + ";\n";
+ r_code += " bool " + outputs[i] + ";\n";
break;
case VisualShaderNode::PORT_TYPE_TRANSFORM:
- code += " mat4 " + outputs[i] + ";\n";
+ r_code += " mat4 " + outputs[i] + ";\n";
break;
default:
break;
@@ -1992,73 +1987,73 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
}
- node_code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
+ node_code += vsnode->generate_code(get_mode(), type, p_node, inputs, outputs, p_for_preview);
if (!node_code.is_empty()) {
- code += node_name;
- code += node_code;
+ r_code += node_name;
+ r_code += node_code;
}
for (int i = 0; i < output_count; i++) {
if (expanded_output_ports[i]) {
switch (vsnode->get_output_port_type(i)) {
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
i += 2;
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
- if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
- String b = "n_out" + itos(node) + "p" + itos(i + 3);
- code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
+ r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
outputs[i + 3] = b;
}
i += 3;
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- if (vsnode->is_output_port_connected(i + 1) || (for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
- String r = "n_out" + itos(node) + "p" + itos(i + 1);
- code += " float " + r + " = n_out" + itos(node) + "p" + itos(i) + ".r;\n";
+ if (vsnode->is_output_port_connected(i + 1) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 1))) { // red-component
+ String r = "n_out" + itos(p_node) + "p" + itos(i + 1);
+ r_code += " float " + r + " = n_out" + itos(p_node) + "p" + itos(i) + ".r;\n";
outputs[i + 1] = r;
}
- if (vsnode->is_output_port_connected(i + 2) || (for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
- String g = "n_out" + itos(node) + "p" + itos(i + 2);
- code += " float " + g + " = n_out" + itos(node) + "p" + itos(i) + ".g;\n";
+ if (vsnode->is_output_port_connected(i + 2) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 2))) { // green-component
+ String g = "n_out" + itos(p_node) + "p" + itos(i + 2);
+ r_code += " float " + g + " = n_out" + itos(p_node) + "p" + itos(i) + ".g;\n";
outputs[i + 2] = g;
}
- if (vsnode->is_output_port_connected(i + 3) || (for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
- String b = "n_out" + itos(node) + "p" + itos(i + 3);
- code += " float " + b + " = n_out" + itos(node) + "p" + itos(i) + ".b;\n";
+ if (vsnode->is_output_port_connected(i + 3) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 3))) { // blue-component
+ String b = "n_out" + itos(p_node) + "p" + itos(i + 3);
+ r_code += " float " + b + " = n_out" + itos(p_node) + "p" + itos(i) + ".b;\n";
outputs[i + 3] = b;
}
- if (vsnode->is_output_port_connected(i + 4) || (for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
- String a = "n_out" + itos(node) + "p" + itos(i + 4);
- code += " float " + a + " = n_out" + itos(node) + "p" + itos(i) + ".a;\n";
+ if (vsnode->is_output_port_connected(i + 4) || (p_for_preview && vsnode->get_output_port_for_preview() == (i + 4))) { // alpha-component
+ String a = "n_out" + itos(p_node) + "p" + itos(i + 4);
+ r_code += " float " + a + " = n_out" + itos(p_node) + "p" + itos(i) + ".a;\n";
outputs[i + 4] = a;
}
@@ -2071,11 +2066,11 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
}
if (!node_code.is_empty()) {
- code += "\n";
+ r_code += "\n";
}
- code += "\n"; //
- processed.insert(node);
+ r_code += "\n"; //
+ r_processed.insert(p_node);
return OK;
}
@@ -2103,7 +2098,7 @@ void VisualShader::_update_shader() const {
StringBuilder global_code;
StringBuilder global_code_per_node;
HashMap<Type, StringBuilder> global_code_per_func;
- StringBuilder code;
+ StringBuilder shader_code;
Vector<VisualShader::DefaultTextureParam> default_tex_params;
HashSet<StringName> classes;
HashMap<int, int> insertion_pos;
@@ -2340,7 +2335,7 @@ void VisualShader::_update_shader() const {
if (shader_mode != Shader::MODE_PARTICLES) {
func_code += "\nvoid " + String(func_name[i]) + "() {\n";
}
- insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length());
+ insertion_pos.insert(i, shader_code.get_string_length() + func_code.get_string_length());
Error err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
ERR_FAIL_COND(err != OK);
@@ -2364,7 +2359,7 @@ void VisualShader::_update_shader() const {
} else {
func_code += varying_code;
func_code += "}\n";
- code += func_code;
+ shader_code += func_code;
}
}
@@ -2377,65 +2372,65 @@ void VisualShader::_update_shader() const {
bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty();
bool has_collide = !code_map[TYPE_COLLIDE].is_empty();
- code += "void start() {\n";
+ shader_code += "void start() {\n";
if (has_start || has_start_custom) {
- code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
- code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
- code += " float __radians;\n";
- code += " vec3 __vec3_buff1;\n";
- code += " vec3 __vec3_buff2;\n";
- code += " float __scalar_buff1;\n";
- code += " float __scalar_buff2;\n";
- code += " int __scalar_ibuff;\n";
- code += " vec4 __vec4_buff;\n";
- code += " vec3 __ndiff = normalize(__diff);\n\n";
+ shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ shader_code += " float __radians;\n";
+ shader_code += " vec3 __vec3_buff1;\n";
+ shader_code += " vec3 __vec3_buff2;\n";
+ shader_code += " float __scalar_buff1;\n";
+ shader_code += " float __scalar_buff2;\n";
+ shader_code += " int __scalar_ibuff;\n";
+ shader_code += " vec4 __vec4_buff;\n";
+ shader_code += " vec3 __ndiff = normalize(__diff);\n\n";
}
if (has_start) {
- code += " {\n";
- code += code_map[TYPE_START].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n";
+ shader_code += code_map[TYPE_START].replace("\n ", "\n ");
+ shader_code += " }\n";
if (has_start_custom) {
- code += " \n";
+ shader_code += " \n";
}
}
if (has_start_custom) {
- code += " {\n";
- code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n";
+ shader_code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n ");
+ shader_code += " }\n";
}
- code += "}\n\n";
- code += "void process() {\n";
+ shader_code += "}\n\n";
+ shader_code += "void process() {\n";
if (has_process || has_process_custom || has_collide) {
- code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
- code += " vec3 __vec3_buff1;\n";
- code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
- code += " vec3 __ndiff = normalize(__diff);\n\n";
+ shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n";
+ shader_code += " vec3 __vec3_buff1;\n";
+ shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n";
+ shader_code += " vec3 __ndiff = normalize(__diff);\n\n";
}
- code += " {\n";
+ shader_code += " {\n";
String tab = " ";
if (has_collide) {
- code += " if (COLLIDED) {\n\n";
- code += code_map[TYPE_COLLIDE].replace("\n ", "\n ");
+ shader_code += " if (COLLIDED) {\n\n";
+ shader_code += code_map[TYPE_COLLIDE].replace("\n ", "\n ");
if (has_process) {
- code += " } else {\n\n";
+ shader_code += " } else {\n\n";
tab += " ";
}
}
if (has_process) {
- code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab);
+ shader_code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab);
}
if (has_collide) {
- code += " }\n";
+ shader_code += " }\n";
}
- code += " }\n";
+ shader_code += " }\n";
if (has_process_custom) {
- code += " {\n\n";
- code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n ");
- code += " }\n";
+ shader_code += " {\n\n";
+ shader_code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n ");
+ shader_code += " }\n";
}
- code += "}\n\n";
+ shader_code += "}\n\n";
global_compute_code += "float __rand_from_seed(inout uint seed) {\n";
global_compute_code += " int k;\n";
@@ -2504,7 +2499,7 @@ void VisualShader::_update_shader() const {
final_code += global_compute_code;
final_code += global_code_per_node;
final_code += global_expressions;
- String tcode = code;
+ String tcode = shader_code;
for (int i = 0; i < TYPE_MAX; i++) {
if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) {
continue;
@@ -3648,12 +3643,12 @@ String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_VERTEX) {
- String name = get_input_port_name(p_index);
- return bool(name == "Model View Matrix");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Model View Matrix");
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
- String name = get_input_port_name(p_index);
- return bool(name == "AO" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "AO" || port_name == "Normal" || port_name == "Rim" || port_name == "Clearcoat" || port_name == "Anisotropy" || port_name == "Subsurf Scatter" || port_name == "Alpha Scissor Threshold");
}
return false;
}
@@ -3666,15 +3661,15 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::
int idx = 0;
int count = 0;
- String code;
+ String shader_code;
while (ports[idx].mode != Shader::MODE_MAX) {
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
if (!p_input_vars[count].is_empty()) {
String s = ports[idx].string;
if (s.contains(":")) {
- code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
+ shader_code += " " + s.get_slicec(':', 0) + " = " + p_input_vars[count] + "." + s.get_slicec(':', 1) + ";\n";
} else {
- code += " " + s + " = " + p_input_vars[count] + ";\n";
+ shader_code += " " + s + " = " + p_input_vars[count] + ";\n";
}
}
count++;
@@ -3682,7 +3677,7 @@ String VisualShaderNodeOutput::generate_code(Shader::Mode p_mode, VisualShader::
idx++;
}
- return code;
+ return shader_code;
}
VisualShaderNodeOutput::VisualShaderNodeOutput() {
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 3aba550f03..5ed5f22cd0 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -156,7 +156,7 @@ private:
}
};
- Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, HashMap<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, HashSet<int> &processed, bool for_preview, HashSet<StringName> &r_classes) const;
+ Error _write_node(Type p_type, StringBuilder *p_global_code, StringBuilder *p_global_code_per_node, HashMap<Type, StringBuilder> *p_global_code_per_func, StringBuilder &r_code, Vector<DefaultTextureParam> &r_def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &p_input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &p_output_connections, int p_node, HashSet<int> &r_processed, bool p_for_preview, HashSet<StringName> &r_classes) const;
void _input_type_changed(Type p_type, int p_id);
bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const;
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index de13912b75..04637983b5 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1642,17 +1642,20 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const
String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
+ code += " {\n";
- code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
- code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
- code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
- code += " _depth_view.xyz /= _depth_view.w;";
- code += vformat(" %s = -_depth_view.z;", p_output_vars[0]);
+ code += " float __log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
+ code += " vec3 __depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, __log_depth);\n";
+ code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(__depth_ndc, 1.0);\n";
+ code += " __depth_view.xyz /= __depth_view.w;\n";
+ code += vformat(" %s = -__depth_view.z;\n", p_output_vars[0]);
+ code += " }\n";
return code;
}
VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+ simple_decl = false;
}
////////////// Float Op
@@ -3204,6 +3207,7 @@ String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
+ code += " {\n";
String uv;
if (p_input_vars[0].is_empty()) {
@@ -3220,17 +3224,18 @@ String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualSh
String repeat = vformat("%s", p_input_vars[3]);
if (p_mode == Shader::MODE_CANVAS_ITEM) {
- code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
- code += " float __radius = length(__dir) * 2.0;\n";
- code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
- code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n";
+ code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
} else {
- code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
- code += " float __radius = length(__dir) * 2.0;\n";
- code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
- code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n";
+ code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
}
+ code += " }\n";
return code;
}
@@ -3238,6 +3243,8 @@ VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() {
set_input_port_default_value(1, Vector2(0.5, 0.5)); // center
set_input_port_default_value(2, 1.0); // zoom
set_input_port_default_value(3, 1.0); // repeat
+
+ simple_decl = false;
}
////////////// Dot Product
@@ -7256,22 +7263,26 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
+ code += " {\n";
String proximity_fade_distance = vformat("%s", p_input_vars[0]);
- code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
if (!RenderingServer::get_singleton()->is_low_end()) {
- code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
} else {
- code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n";
}
- code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
- code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+ code += " __depth_world_pos.xyz /= __depth_world_pos.w;\n";
+ code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+ code += " }\n";
return code;
}
VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
set_input_port_default_value(0, 1.0);
+
+ simple_decl = false;
}
////////////// Random Range
@@ -7416,11 +7427,11 @@ String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
-
- code += vformat(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
- code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
- code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
-
+ code += " {\n";
+ code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
+ code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
+ code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
+ code += " }\n";
return code;
}
@@ -7429,4 +7440,6 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() {
set_input_port_default_value(2, 1.0);
set_input_port_default_value(3, 0.0);
set_input_port_default_value(4, 1.0);
+
+ simple_decl = false;
}
diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp
index df6abe161e..f125b05a26 100644
--- a/scene/resources/visual_shader_particle_nodes.cpp
+++ b/scene/resources/visual_shader_particle_nodes.cpp
@@ -460,9 +460,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -481,9 +481,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3>
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -502,9 +502,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p
image.instantiate();
if (p_array.size() == 0) {
- image->create(1, 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBA8);
} else {
- image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
+ image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
}
for (int i = 0; i < p_array.size(); i++) {
@@ -1291,12 +1291,12 @@ String VisualShaderNodeParticleOutput::get_input_port_name(int p_port) const {
bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const {
if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
- String name = get_input_port_name(p_index);
- return bool(name == "Scale");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Scale");
}
if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
- String name = get_input_port_name(p_index);
- return bool(name == "Velocity");
+ String port_name = get_input_port_name(p_index);
+ return bool(port_name == "Velocity");
}
return false;
}
@@ -1604,24 +1604,24 @@ String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualSh
flags_arr.push_back("FLAG_EMIT_CUSTOM");
}
- String flags;
+ String flags_str;
for (int i = 0; i < flags_arr.size(); i++) {
if (i > 0) {
- flags += "|";
+ flags_str += "|";
}
- flags += flags_arr[i];
+ flags_str += flags_arr[i];
}
- if (flags.is_empty()) {
- flags = "uint(0)";
+ if (flags_str.is_empty()) {
+ flags_str = "uint(0)";
}
if (!default_condition) {
code += " if (" + p_input_vars[0] + ") {\n";
}
- code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n";
+ code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags_str + ");\n";
if (!default_condition) {
code += " }\n";
diff --git a/servers/audio/audio_effect.cpp b/servers/audio/audio_effect.cpp
index f38d0adfb2..ef0e3197e1 100644
--- a/servers/audio/audio_effect.cpp
+++ b/servers/audio/audio_effect.cpp
@@ -36,11 +36,9 @@ void AudioEffectInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_
}
}
bool AudioEffectInstance::process_silence() const {
- bool ret;
- if (GDVIRTUAL_CALL(_process_silence, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_process_silence, ret);
+ return ret;
}
void AudioEffectInstance::_bind_methods() {
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 1bfe6a3eb5..33d4c816f2 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -54,11 +54,9 @@ bool AudioStreamPlayback::is_playing() const {
}
int AudioStreamPlayback::get_loop_count() const {
- int ret;
- if (GDVIRTUAL_CALL(_get_loop_count, ret)) {
- return ret;
- }
- return 0;
+ int ret = 0;
+ GDVIRTUAL_CALL(_get_loop_count, ret);
+ return ret;
}
double AudioStreamPlayback::get_playback_position() const {
@@ -69,9 +67,7 @@ double AudioStreamPlayback::get_playback_position() const {
ERR_FAIL_V_MSG(0, "AudioStreamPlayback::get_playback_position unimplemented!");
}
void AudioStreamPlayback::seek(double p_time) {
- if (GDVIRTUAL_CALL(_seek, p_time)) {
- return;
- }
+ GDVIRTUAL_CALL(_seek, p_time);
}
int AudioStreamPlayback::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
@@ -201,58 +197,44 @@ Ref<AudioStreamPlayback> AudioStream::instantiate_playback() {
}
String AudioStream::get_stream_name() const {
String ret;
- if (GDVIRTUAL_CALL(_get_stream_name, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_get_stream_name, ret);
+ return ret;
}
double AudioStream::get_length() const {
- double ret;
- if (GDVIRTUAL_CALL(_get_length, ret)) {
- return ret;
- }
- return 0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_get_length, ret);
+ return ret;
}
bool AudioStream::is_monophonic() const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_monophonic, ret)) {
- return ret;
- }
- return true;
+ bool ret = true;
+ GDVIRTUAL_CALL(_is_monophonic, ret);
+ return ret;
}
double AudioStream::get_bpm() const {
double ret = 0;
- if (GDVIRTUAL_CALL(_get_bpm, ret)) {
- return ret;
- }
- return 0;
+ GDVIRTUAL_CALL(_get_bpm, ret);
+ return ret;
}
bool AudioStream::has_loop() const {
bool ret = 0;
- if (GDVIRTUAL_CALL(_has_loop, ret)) {
- return ret;
- }
- return 0;
+ GDVIRTUAL_CALL(_has_loop, ret);
+ return ret;
}
int AudioStream::get_bar_beats() const {
int ret = 0;
- if (GDVIRTUAL_CALL(_get_bar_beats, ret)) {
- return ret;
- }
- return 0;
+ GDVIRTUAL_CALL(_get_bar_beats, ret);
+ return ret;
}
int AudioStream::get_beat_count() const {
int ret = 0;
- if (GDVIRTUAL_CALL(_get_beat_count, ret)) {
- return ret;
- }
- return 0;
+ GDVIRTUAL_CALL(_get_beat_count, ret);
+ return ret;
}
void AudioStream::tag_used(float p_offset) {
diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp
index 14ece8d93e..8a71ef0be7 100644
--- a/servers/audio/effects/audio_effect_eq.cpp
+++ b/servers/audio/effects/audio_effect_eq.cpp
@@ -128,8 +128,8 @@ AudioEffectEQ::AudioEffectEQ(EQ::Preset p_preset) {
gain.resize(eq.get_band_count());
for (int i = 0; i < gain.size(); i++) {
gain.write[i] = 0.0;
- String name = "band_db/" + itos(eq.get_band_frequency(i)) + "_hz";
- prop_band_map[name] = i;
- band_names.push_back(name);
+ String band_name = "band_db/" + itos(eq.get_band_frequency(i)) + "_hz";
+ prop_band_map[band_name] = i;
+ band_names.push_back(band_name);
}
}
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 1254a6740a..e657570f9b 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -1454,7 +1454,7 @@ void AudioServer::update() {
}
void AudioServer::load_default_bus_layout() {
- String layout_path = ProjectSettings::get_singleton()->get("audio/buses/default_bus_layout");
+ String layout_path = GLOBAL_GET("audio/buses/default_bus_layout");
if (ResourceLoader::exists(layout_path)) {
Ref<AudioBusLayout> default_layout = ResourceLoader::load(layout_path);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 4b97bede56..07cb59aaee 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -581,6 +581,8 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_set_item_icon", "menu_root", "idx", "icon"), &DisplayServer::global_menu_set_item_icon);
ClassDB::bind_method(D_METHOD("global_menu_set_item_indentation_level", "menu_root", "idx", "level"), &DisplayServer::global_menu_set_item_indentation_level);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_count", "menu_root"), &DisplayServer::global_menu_get_item_count);
+
ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item);
ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear);
@@ -636,9 +638,6 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list);
ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position);
- ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "vsync_mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i()));
- ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window);
-
ClassDB::bind_method(D_METHOD("window_get_native_handle", "handle_type", "window_id"), &DisplayServer::window_get_native_handle, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_active_popup"), &DisplayServer::window_get_active_popup);
ClassDB::bind_method(D_METHOD("window_set_popup_safe_rect", "window", "rect"), &DisplayServer::window_set_popup_safe_rect);
@@ -661,7 +660,6 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_set_input_text_callback", "callback", "window_id"), &DisplayServer::window_set_input_text_callback, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_set_drop_files_callback", "callback", "window_id"), &DisplayServer::window_set_drop_files_callback, DEFVAL(MAIN_WINDOW_ID));
- ClassDB::bind_method(D_METHOD("window_attach_instance_id", "instance_id", "window_id"), &DisplayServer::window_attach_instance_id, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_attached_instance_id", "window_id"), &DisplayServer::window_get_attached_instance_id, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_max_size", "window_id"), &DisplayServer::window_get_max_size, DEFVAL(MAIN_WINDOW_ID));
@@ -695,6 +693,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_set_vsync_mode", "vsync_mode", "window_id"), &DisplayServer::window_set_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_vsync_mode", "window_id"), &DisplayServer::window_get_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_is_maximize_allowed", "window_id"), &DisplayServer::window_is_maximize_allowed, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_maximize_on_title_dbl_click"), &DisplayServer::window_maximize_on_title_dbl_click);
ClassDB::bind_method(D_METHOD("window_minimize_on_title_dbl_click"), &DisplayServer::window_minimize_on_title_dbl_click);
@@ -865,9 +864,9 @@ Vector<String> DisplayServer::get_create_function_rendering_drivers(int p_index)
return server_create_functions[p_index].get_rendering_drivers_function();
}
-DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr);
- return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error);
+ return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, r_error);
}
void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) {
diff --git a/servers/display_server.h b/servers/display_server.h
index 8eafccc040..55e9fb55dc 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -72,7 +72,7 @@ public:
WINDOW_VIEW,
};
- typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Size2i &, Error &r_error);
+ typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Point2i *, const Size2i &, Error &r_error);
typedef Vector<String> (*GetRenderingDriversFunction)();
private:
@@ -382,7 +382,7 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
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 Vector3i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector3i(); }
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
@@ -483,7 +483,7 @@ public:
static int get_create_function_count();
static const char *get_create_function_name(int p_index);
static Vector<String> get_create_function_rendering_drivers(int p_index);
- static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
+ static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
DisplayServer();
~DisplayServer();
diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h
index 3853ff4fdc..e1a27b6137 100644
--- a/servers/display_server_headless.h
+++ b/servers/display_server_headless.h
@@ -45,7 +45,7 @@ private:
return drivers;
}
- static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) {
+ static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error) {
r_error = OK;
RasterizerDummy::make_current();
return memnew(DisplayServerHeadless());
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 27f9ed2cb3..811ff231fc 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -60,6 +60,7 @@ void PhysicsDirectBodyState3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_inverse_mass);
GDVIRTUAL_BIND(_get_inverse_inertia);
+ GDVIRTUAL_BIND(_get_inverse_inertia_tensor);
GDVIRTUAL_BIND(_set_linear_velocity, "velocity");
GDVIRTUAL_BIND(_get_linear_velocity);
diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp
index 2164dca29e..0edce4ced6 100644
--- a/servers/movie_writer/movie_writer.cpp
+++ b/servers/movie_writer/movie_writer.cpp
@@ -105,6 +105,21 @@ void MovieWriter::get_supported_extensions(List<String> *r_extensions) const {
void MovieWriter::begin(const Size2i &p_movie_size, uint32_t p_fps, const String &p_base_path) {
project_name = GLOBAL_GET("application/config/name");
+
+ print_line(vformat("Movie Maker mode enabled, recording movie at %d FPS...", p_fps));
+
+ // Check for available disk space and warn the user if needed.
+ Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ String path = p_base_path.get_basename();
+ if (path.is_relative_path()) {
+ path = "res://" + path;
+ }
+ dir->open(path);
+ if (dir->get_space_left() < 10 * Math::pow(1024.0, 3.0)) {
+ // Less than 10 GiB available.
+ WARN_PRINT(vformat("Current available space on disk is low (%s). MovieWriter will fail during movie recording if the disk runs out of available space.", String::humanize_size(dir->get_space_left())));
+ }
+
mix_rate = get_audio_mix_rate();
AudioDriverDummy::get_dummy_singleton()->set_mix_rate(mix_rate);
AudioDriverDummy::get_dummy_singleton()->set_speaker_mode(AudioDriver::SpeakerMode(get_audio_speaker_mode()));
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 783d32641e..cab8816747 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -190,12 +190,10 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_face_m
bool enabled_geometry_face_random_color = get_debug_navigation_enable_geometry_face_random_color();
- Color debug_navigation_geometry_face_color = get_debug_navigation_geometry_face_color();
-
Ref<StandardMaterial3D> face_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
face_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
face_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- face_material->set_albedo(debug_navigation_geometry_face_color);
+ face_material->set_albedo(get_debug_navigation_geometry_face_color());
if (enabled_geometry_face_random_color) {
face_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
face_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
@@ -213,11 +211,9 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_edge_m
bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray();
- Color debug_navigation_geometry_edge_color = get_debug_navigation_geometry_edge_color();
-
Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_albedo(debug_navigation_geometry_edge_color);
+ line_material->set_albedo(get_debug_navigation_geometry_edge_color());
if (enabled_edge_lines_xray) {
line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
@@ -232,12 +228,10 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_face_d
return debug_navigation_geometry_face_disabled_material;
}
- Color debug_navigation_geometry_face_disabled_color = get_debug_navigation_geometry_face_disabled_color();
-
Ref<StandardMaterial3D> face_disabled_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
face_disabled_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
face_disabled_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
- face_disabled_material->set_albedo(debug_navigation_geometry_face_disabled_color);
+ face_disabled_material->set_albedo(get_debug_navigation_geometry_face_disabled_color());
debug_navigation_geometry_face_disabled_material = face_disabled_material;
@@ -251,11 +245,9 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_geometry_edge_d
bool enabled_edge_lines_xray = get_debug_navigation_enable_edge_lines_xray();
- Color debug_navigation_geometry_edge_disabled_color = get_debug_navigation_geometry_edge_disabled_color();
-
Ref<StandardMaterial3D> line_disabled_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_disabled_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_disabled_material->set_albedo(debug_navigation_geometry_edge_disabled_color);
+ line_disabled_material->set_albedo(get_debug_navigation_geometry_edge_disabled_color());
if (enabled_edge_lines_xray) {
line_disabled_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
@@ -272,11 +264,9 @@ Ref<StandardMaterial3D> NavigationServer3D::get_debug_navigation_edge_connection
bool enabled_edge_connections_xray = get_debug_navigation_enable_edge_connections_xray();
- Color debug_navigation_edge_connection_color = get_debug_navigation_edge_connection_color();
-
Ref<StandardMaterial3D> edge_connections_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
edge_connections_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- edge_connections_material->set_albedo(debug_navigation_edge_connection_color);
+ edge_connections_material->set_albedo(get_debug_navigation_edge_connection_color());
if (enabled_edge_connections_xray) {
edge_connections_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
}
diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp
index af90f96438..3fe062de57 100644
--- a/servers/physics_2d/godot_area_2d.cpp
+++ b/servers/physics_2d/godot_area_2d.cpp
@@ -304,12 +304,12 @@ void GodotArea2D::call_queries() {
void GodotArea2D::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const {
if (is_gravity_point()) {
- const real_t gravity_distance_scale = get_gravity_distance_scale();
+ const real_t gr_distance_scale = get_gravity_distance_scale();
Vector2 v = get_transform().xform(get_gravity_vector()) - p_position;
- if (gravity_distance_scale > 0) {
+ if (gr_distance_scale > 0) {
const real_t v_length = v.length();
if (v_length > 0) {
- const real_t v_scaled = v_length * gravity_distance_scale;
+ const real_t v_scaled = v_length * gr_distance_scale;
r_gravity = (v.normalized() * (get_gravity() / (v_scaled * v_scaled)));
} else {
r_gravity = Vector2();
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
index 90124cd991..4422be959a 100644
--- a/servers/physics_2d/godot_body_2d.cpp
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -65,10 +65,10 @@ void GodotBody2D::update_mass_properties() {
real_t area = get_shape_aabb(i).get_area();
- real_t mass = area * this->mass / total_area;
+ real_t mass_new = area * mass / total_area;
// NOTE: we assume that the shape origin is also its center of mass.
- center_of_mass_local += mass * get_shape_transform(i).get_origin();
+ center_of_mass_local += mass_new * get_shape_transform(i).get_origin();
}
center_of_mass_local /= mass;
@@ -90,12 +90,12 @@ void GodotBody2D::update_mass_properties() {
continue;
}
- real_t mass = area * this->mass / total_area;
+ real_t mass_new = area * mass / total_area;
Transform2D mtx = get_shape_transform(i);
Vector2 scale = mtx.get_scale();
Vector2 shape_origin = mtx.get_origin() - center_of_mass_local;
- inertia += shape->get_moment_of_inertia(mass, scale) + mass * shape_origin.length_squared();
+ inertia += shape->get_moment_of_inertia(mass_new, scale) + mass_new * shape_origin.length_squared();
}
}
@@ -578,14 +578,14 @@ void GodotBody2D::integrate_forces(real_t p_step) {
damp = 0;
}
- real_t angular_damp = 1.0 - p_step * total_angular_damp;
+ real_t angular_damp_new = 1.0 - p_step * total_angular_damp;
- if (angular_damp < 0) { // reached zero in the given time
- angular_damp = 0;
+ if (angular_damp_new < 0) { // reached zero in the given time
+ angular_damp_new = 0;
}
linear_velocity *= damp;
- angular_velocity *= angular_damp;
+ angular_velocity *= angular_damp_new;
linear_velocity += _inv_mass * force * p_step;
angular_velocity += _inv_inertia * torque * p_step;
diff --git a/servers/physics_2d/godot_body_pair_2d.cpp b/servers/physics_2d/godot_body_pair_2d.cpp
index 2f2af15da7..7b7c67bbc2 100644
--- a/servers/physics_2d/godot_body_pair_2d.cpp
+++ b/servers/physics_2d/godot_body_pair_2d.cpp
@@ -170,7 +170,7 @@ bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A,
Vector2 mnormal = motion / mlen;
- real_t min, max;
+ real_t min = 0.0, max = 0.0;
p_A->get_shape(p_shape_A)->project_rangev(mnormal, p_xform_A, min, max);
// Did it move enough in this direction to even attempt raycast?
diff --git a/servers/physics_2d/godot_collision_solver_2d.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp
index 52237539c0..9c7b8fbe53 100644
--- a/servers/physics_2d/godot_collision_solver_2d.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d.cpp
@@ -197,7 +197,7 @@ bool GodotCollisionSolver2D::solve_concave(const GodotShape2D *p_shape_A, const
real_t axis_scale = 1.0 / axis.length();
axis *= axis_scale;
- real_t smin, smax;
+ real_t smin = 0.0, smax = 0.0;
p_shape_A->project_rangev(axis, rel_transform, smin, smax);
smin *= axis_scale;
smax *= axis_scale;
diff --git a/servers/physics_2d/godot_collision_solver_2d_sat.cpp b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
index 8aa30ad6a4..f8924239ea 100644
--- a/servers/physics_2d/godot_collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d_sat.cpp
@@ -234,7 +234,7 @@ public:
axis = Vector2(0.0, 1.0);
}
- real_t min_A, max_A, min_B, max_B;
+ real_t min_A = 0.0, max_A = 0.0, min_B = 0.0, max_B = 0.0;
if (castA) {
shape_A->project_range_cast(motion_A, axis, *transform_A, min_A, max_A);
diff --git a/servers/physics_2d/godot_joints_2d.cpp b/servers/physics_2d/godot_joints_2d.cpp
index 0c21b08ea9..34eb66500d 100644
--- a/servers/physics_2d/godot_joints_2d.cpp
+++ b/servers/physics_2d/godot_joints_2d.cpp
@@ -436,13 +436,13 @@ void GodotDampedSpringJoint2D::solve(real_t p_step) {
// not 100% certain this is derived correctly, though it makes sense
real_t v_damp = -vrn * v_coef;
target_vrn = vrn + v_damp;
- Vector2 j = n * v_damp * n_mass;
+ Vector2 j_new = n * v_damp * n_mass;
if (dynamic_A) {
- A->apply_impulse(-j, rA);
+ A->apply_impulse(-j_new, rA);
}
if (dynamic_B) {
- B->apply_impulse(j, rB);
+ B->apply_impulse(j_new, rB);
}
}
diff --git a/servers/physics_2d/godot_shape_2d.cpp b/servers/physics_2d/godot_shape_2d.cpp
index 72ade3757b..da414ae233 100644
--- a/servers/physics_2d/godot_shape_2d.cpp
+++ b/servers/physics_2d/godot_shape_2d.cpp
@@ -225,16 +225,16 @@ void GodotSegmentShape2D::set_data(const Variant &p_data) {
b = r.size;
n = (b - a).orthogonal();
- Rect2 aabb;
- aabb.position = a;
- aabb.expand_to(b);
- if (aabb.size.x == 0) {
- aabb.size.x = 0.001;
+ Rect2 aabb_new;
+ aabb_new.position = a;
+ aabb_new.expand_to(b);
+ if (aabb_new.size.x == 0) {
+ aabb_new.size.x = 0.001;
}
- if (aabb.size.y == 0) {
- aabb.size.y = 0.001;
+ if (aabb_new.size.y == 0) {
+ aabb_new.size.y = 0.001;
}
- configure(aabb);
+ configure(aabb_new);
}
Variant GodotSegmentShape2D::get_data() const {
@@ -564,13 +564,13 @@ bool GodotConvexPolygonShape2D::intersect_segment(const Vector2 &p_begin, const
real_t GodotConvexPolygonShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const {
ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points.");
- Rect2 aabb;
- aabb.position = points[0].pos * p_scale;
+ Rect2 aabb_new;
+ aabb_new.position = points[0].pos * p_scale;
for (int i = 0; i < point_count; i++) {
- aabb.expand_to(points[i].pos * p_scale);
+ aabb_new.expand_to(points[i].pos * p_scale);
}
- return p_mass * aabb.size.dot(aabb.size) / 12.0;
+ return p_mass * aabb_new.size.dot(aabb_new.size) / 12.0;
}
void GodotConvexPolygonShape2D::set_data(const Variant &p_data) {
@@ -620,13 +620,13 @@ void GodotConvexPolygonShape2D::set_data(const Variant &p_data) {
}
ERR_FAIL_COND(point_count == 0);
- Rect2 aabb;
- aabb.position = points[0].pos;
+ Rect2 aabb_new;
+ aabb_new.position = points[0].pos;
for (int i = 1; i < point_count; i++) {
- aabb.expand_to(points[i].pos);
+ aabb_new.expand_to(points[i].pos);
}
- configure(aabb);
+ configure(aabb_new);
}
Variant GodotConvexPolygonShape2D::get_data() const {
@@ -705,18 +705,18 @@ bool GodotConcavePolygonShape2D::intersect_segment(const Vector2 &p_begin, const
stack[0] = 0;
while (true) {
uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &bvh = bvhptr[node];
+ const BVH &bvh2 = bvhptr[node];
bool done = false;
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = bvh.aabb.intersects_segment(p_begin, p_end);
+ bool valid = bvh2.aabb.intersects_segment(p_begin, p_end);
if (!valid) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
} else {
- if (bvh.left < 0) {
- const Segment &s = segmentptr[bvh.right];
+ if (bvh2.left < 0) {
+ const Segment &s = segmentptr[bvh2.right];
Vector2 a = pointptr[s.points[0]];
Vector2 b = pointptr[s.points[1]];
@@ -742,13 +742,13 @@ bool GodotConcavePolygonShape2D::intersect_segment(const Vector2 &p_begin, const
continue;
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = bvh.left | TEST_AABB_BIT;
+ stack[level + 1] = bvh2.left | TEST_AABB_BIT;
level++;
}
continue;
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = bvh.right | TEST_AABB_BIT;
+ stack[level + 1] = bvh2.right | TEST_AABB_BIT;
level++;
}
continue;
@@ -822,7 +822,7 @@ void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {
ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT32_ARRAY);
#endif
- Rect2 aabb;
+ Rect2 aabb_new;
if (p_data.get_type() == Variant::PACKED_VECTOR2_ARRAY) {
Vector<Vector2> p2arr = p_data;
@@ -835,7 +835,7 @@ void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {
bvh_depth = 1;
if (len == 0) {
- configure(aabb);
+ configure(aabb_new);
return;
}
@@ -868,9 +868,9 @@ void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {
}
points.resize(pointmap.size());
- aabb.position = pointmap.begin()->key;
+ aabb_new.position = pointmap.begin()->key;
for (const KeyValue<Point2, int> &E : pointmap) {
- aabb.expand_to(E.key);
+ aabb_new.expand_to(E.key);
points.write[E.value] = E.key;
}
@@ -889,7 +889,7 @@ void GodotConcavePolygonShape2D::set_data(const Variant &p_data) {
//dictionary with arrays
}
- configure(aabb);
+ configure(aabb_new);
}
Variant GodotConcavePolygonShape2D::get_data() const {
@@ -937,17 +937,17 @@ void GodotConcavePolygonShape2D::cull(const Rect2 &p_local_aabb, QueryCallback p
stack[0] = 0;
while (true) {
uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &bvh = bvhptr[node];
+ const BVH &bvh2 = bvhptr[node];
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = p_local_aabb.intersects(bvh.aabb);
+ bool valid = p_local_aabb.intersects(bvh2.aabb);
if (!valid) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
} else {
- if (bvh.left < 0) {
- const Segment &s = segmentptr[bvh.right];
+ if (bvh2.left < 0) {
+ const Segment &s = segmentptr[bvh2.right];
Vector2 a = pointptr[s.points[0]];
Vector2 b = pointptr[s.points[1]];
@@ -966,13 +966,13 @@ void GodotConcavePolygonShape2D::cull(const Rect2 &p_local_aabb, QueryCallback p
continue;
case VISIT_LEFT_BIT: {
stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = bvh.left | TEST_AABB_BIT;
+ stack[level + 1] = bvh2.left | TEST_AABB_BIT;
level++;
}
continue;
case VISIT_RIGHT_BIT: {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- stack[level + 1] = bvh.right | TEST_AABB_BIT;
+ stack[level + 1] = bvh2.right | TEST_AABB_BIT;
level++;
}
continue;
diff --git a/servers/physics_3d/godot_area_3d.cpp b/servers/physics_3d/godot_area_3d.cpp
index 9765d0bf58..d4d3b3e6aa 100644
--- a/servers/physics_3d/godot_area_3d.cpp
+++ b/servers/physics_3d/godot_area_3d.cpp
@@ -333,12 +333,12 @@ void GodotArea3D::call_queries() {
void GodotArea3D::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const {
if (is_gravity_point()) {
- const real_t gravity_distance_scale = get_gravity_distance_scale();
+ const real_t gr_distance_scale = get_gravity_distance_scale();
Vector3 v = get_transform().xform(get_gravity_vector()) - p_position;
- if (gravity_distance_scale > 0) {
+ if (gr_distance_scale > 0) {
const real_t v_length = v.length();
if (v_length > 0) {
- const real_t v_scaled = v_length * gravity_distance_scale;
+ const real_t v_scaled = v_length * gr_distance_scale;
r_gravity = (v.normalized() * (get_gravity() / (v_scaled * v_scaled)));
} else {
r_gravity = Vector3();
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index 19f065c319..53f4ab86f9 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -78,10 +78,10 @@ void GodotBody3D::update_mass_properties() {
real_t area = get_shape_area(i);
- real_t mass = area * this->mass / total_area;
+ real_t mass_new = area * mass / total_area;
// NOTE: we assume that the shape origin is also its center of mass.
- center_of_mass_local += mass * get_shape_transform(i).origin;
+ center_of_mass_local += mass_new * get_shape_transform(i).origin;
}
center_of_mass_local /= mass;
@@ -108,9 +108,9 @@ void GodotBody3D::update_mass_properties() {
const GodotShape3D *shape = get_shape(i);
- real_t mass = area * this->mass / total_area;
+ real_t mass_new = area * mass / total_area;
- Basis shape_inertia_tensor = Basis::from_scale(shape->get_moment_of_inertia(mass));
+ Basis shape_inertia_tensor = Basis::from_scale(shape->get_moment_of_inertia(mass_new));
Transform3D shape_transform = get_shape_transform(i);
Basis shape_basis = shape_transform.basis.orthonormalized();
@@ -118,7 +118,7 @@ void GodotBody3D::update_mass_properties() {
shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed();
Vector3 shape_origin = shape_transform.origin - center_of_mass_local;
- inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass;
+ inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass_new;
}
// Set the inertia to a valid value when there are no valid shapes.
@@ -637,14 +637,14 @@ void GodotBody3D::integrate_forces(real_t p_step) {
damp = 0;
}
- real_t angular_damp = 1.0 - p_step * total_angular_damp;
+ real_t angular_damp_new = 1.0 - p_step * total_angular_damp;
- if (angular_damp < 0) { // reached zero in the given time
- angular_damp = 0;
+ if (angular_damp_new < 0) { // reached zero in the given time
+ angular_damp_new = 0;
}
linear_velocity *= damp;
- angular_velocity *= angular_damp;
+ angular_velocity *= angular_damp_new;
linear_velocity += _inv_mass * force * p_step;
angular_velocity += _inv_inertia_tensor.xform(torque) * p_step;
@@ -707,27 +707,27 @@ void GodotBody3D::integrate_velocities(real_t p_step) {
Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity;
real_t ang_vel = total_angular_velocity.length();
- Transform3D transform = get_transform();
+ Transform3D transform_new = get_transform();
if (!Math::is_zero_approx(ang_vel)) {
Vector3 ang_vel_axis = total_angular_velocity / ang_vel;
Basis rot(ang_vel_axis, ang_vel * p_step);
Basis identity3(1, 0, 0, 0, 1, 0, 0, 0, 1);
- transform.origin += ((identity3 - rot) * transform.basis).xform(center_of_mass_local);
- transform.basis = rot * transform.basis;
- transform.orthonormalize();
+ transform_new.origin += ((identity3 - rot) * transform_new.basis).xform(center_of_mass_local);
+ transform_new.basis = rot * transform_new.basis;
+ transform_new.orthonormalize();
}
Vector3 total_linear_velocity = linear_velocity + biased_linear_velocity;
/*for(int i=0;i<3;i++) {
if (axis_lock&(1<<i)) {
- transform.origin[i]=0.0;
+ transform_new.origin[i]=0.0;
}
}*/
- transform.origin += total_linear_velocity * p_step;
+ transform_new.origin += total_linear_velocity * p_step;
- _set_transform(transform);
+ _set_transform(transform_new);
_set_inv_transform(get_transform().inverse());
_update_transform_dependent();
diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp
index eebbe0196d..7e6cc6f834 100644
--- a/servers/physics_3d/godot_body_pair_3d.cpp
+++ b/servers/physics_3d/godot_body_pair_3d.cpp
@@ -170,7 +170,7 @@ bool GodotBodyPair3D::_test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A,
Vector3 mnormal = motion / mlen;
- real_t min, max;
+ real_t min = 0.0, max = 0.0;
p_A->get_shape(p_shape_A)->project_range(mnormal, p_xform_A, min, max);
// Did it move enough in this direction to even attempt raycast?
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index 9fe0e3eb84..ca76a819ec 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -48,7 +48,7 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s
static const int max_supports = 16;
Vector3 supports[max_supports];
int support_count;
- GodotShape3D::FeatureType support_type;
+ GodotShape3D::FeatureType support_type = GodotShape3D::FeatureType::FEATURE_POINT;
p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
if (support_type == GodotShape3D::FEATURE_CIRCLE) {
@@ -338,7 +338,7 @@ bool GodotCollisionSolver3D::solve_concave(const GodotShape3D *p_shape_A, const
real_t axis_scale = 1.0 / axis.length();
axis *= axis_scale;
- real_t smin, smax;
+ real_t smin = 0.0, smax = 0.0;
p_shape_A->project_range(axis, rel_transform, smin, smax);
smin -= p_margin_A;
smax += p_margin_A;
diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index 56e644b57b..96253cb452 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -634,7 +634,7 @@ public:
axis = Vector3(0.0, 1.0, 0.0);
}
- real_t min_A, max_A, min_B, max_B;
+ real_t min_A = 0.0, max_A = 0.0, min_B = 0.0, max_B = 0.0;
shape_A->project_range(axis, *transform_A, min_A, max_A);
shape_B->project_range(axis, *transform_B, min_B, max_B);
@@ -964,8 +964,8 @@ static void _collision_sphere_convex_polygon(const GodotShape3D *p_a, const Tran
// edges of B
for (int i = 0; i < edge_count; i++) {
- Vector3 v1 = p_transform_b.xform(vertices[edges[i].a]);
- Vector3 v2 = p_transform_b.xform(vertices[edges[i].b]);
+ Vector3 v1 = p_transform_b.xform(vertices[edges[i].vertex_a]);
+ Vector3 v2 = p_transform_b.xform(vertices[edges[i].vertex_b]);
Vector3 v3 = p_transform_a.origin;
Vector3 n1 = v2 - v1;
@@ -1404,7 +1404,7 @@ static void _collision_box_convex_polygon(const GodotShape3D *p_a, const Transfo
Vector3 e1 = p_transform_a.basis.get_column(i);
for (int j = 0; j < edge_count; j++) {
- Vector3 e2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
+ Vector3 e2 = p_transform_b.basis.xform(vertices[edges[j].vertex_a]) - p_transform_b.basis.xform(vertices[edges[j].vertex_b]);
Vector3 axis = e1.cross(e2).normalized();
@@ -1460,8 +1460,8 @@ static void _collision_box_convex_polygon(const GodotShape3D *p_a, const Transfo
}
for (int e = 0; e < edge_count; e++) {
- Vector3 p1 = p_transform_b.xform(vertices[edges[e].a]);
- Vector3 p2 = p_transform_b.xform(vertices[edges[e].b]);
+ Vector3 p1 = p_transform_b.xform(vertices[edges[e].vertex_a]);
+ Vector3 p2 = p_transform_b.xform(vertices[edges[e].vertex_b]);
Vector3 n = (p2 - p1);
if (!separator.test_axis((point - p2).cross(n).cross(n).normalized())) {
@@ -1771,7 +1771,7 @@ static void _collision_capsule_convex_polygon(const GodotShape3D *p_a, const Tra
for (int i = 0; i < edge_count; i++) {
// cylinder
- Vector3 edge_axis = p_transform_b.basis.xform(vertices[edges[i].a]) - p_transform_b.basis.xform(vertices[edges[i].b]);
+ Vector3 edge_axis = p_transform_b.basis.xform(vertices[edges[i].vertex_a]) - p_transform_b.basis.xform(vertices[edges[i].vertex_b]);
Vector3 axis = edge_axis.cross(p_transform_a.basis.get_column(1)).normalized();
if (!separator.test_axis(axis)) {
@@ -1789,8 +1789,8 @@ static void _collision_capsule_convex_polygon(const GodotShape3D *p_a, const Tra
Vector3 sphere_pos = p_transform_a.origin + ((i == 0) ? capsule_axis : -capsule_axis);
for (int j = 0; j < edge_count; j++) {
- Vector3 n1 = sphere_pos - p_transform_b.xform(vertices[edges[j].a]);
- Vector3 n2 = p_transform_b.basis.xform(vertices[edges[j].a]) - p_transform_b.basis.xform(vertices[edges[j].b]);
+ Vector3 n1 = sphere_pos - p_transform_b.xform(vertices[edges[j].vertex_a]);
+ Vector3 n2 = p_transform_b.basis.xform(vertices[edges[j].vertex_a]) - p_transform_b.basis.xform(vertices[edges[j].vertex_b]);
Vector3 axis = n1.cross(n2).cross(n2).normalized();
@@ -2075,6 +2075,16 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D
separator.generate_contacts();
}
+static _FORCE_INLINE_ bool is_minkowski_face(const Vector3 &A, const Vector3 &B, const Vector3 &B_x_A, const Vector3 &C, const Vector3 &D, const Vector3 &D_x_C) {
+ // Test if arcs AB and CD intersect on the unit sphere
+ real_t CBA = C.dot(B_x_A);
+ real_t DBA = D.dot(B_x_A);
+ real_t ADC = A.dot(D_x_C);
+ real_t BDC = B.dot(D_x_C);
+
+ return (CBA * DBA < 0.0f) && (ADC * BDC < 0.0f) && (CBA * BDC > 0.0f);
+}
+
template <bool withMargin>
static void _collision_convex_polygon_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) {
const GodotConvexPolygonShape3D *convex_polygon_A = static_cast<const GodotConvexPolygonShape3D *>(p_a);
@@ -2129,16 +2139,27 @@ static void _collision_convex_polygon_convex_polygon(const GodotShape3D *p_a, co
}
// A<->B edges
+
for (int i = 0; i < edge_count_A; i++) {
- Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]) - p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
+ Vector3 p1 = p_transform_a.xform(vertices_A[edges_A[i].vertex_a]);
+ Vector3 q1 = p_transform_a.xform(vertices_A[edges_A[i].vertex_b]);
+ Vector3 e1 = q1 - p1;
+ Vector3 u1 = p_transform_a.basis.xform(faces_A[edges_A[i].face_a].plane.normal).normalized();
+ Vector3 v1 = p_transform_a.basis.xform(faces_A[edges_A[i].face_b].plane.normal).normalized();
for (int j = 0; j < edge_count_B; j++) {
- Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[j].a]) - p_transform_b.basis.xform(vertices_B[edges_B[j].b]);
+ Vector3 p2 = p_transform_b.xform(vertices_B[edges_B[j].vertex_a]);
+ Vector3 q2 = p_transform_b.xform(vertices_B[edges_B[j].vertex_b]);
+ Vector3 e2 = q2 - p2;
+ Vector3 u2 = p_transform_b.basis.xform(faces_B[edges_B[j].face_a].plane.normal).normalized();
+ Vector3 v2 = p_transform_b.basis.xform(faces_B[edges_B[j].face_b].plane.normal).normalized();
- Vector3 axis = e1.cross(e2).normalized();
+ if (is_minkowski_face(u1, v1, -e1, -u2, -v2, -e2)) {
+ Vector3 axis = e1.cross(e2).normalized();
- if (!separator.test_axis(axis)) {
- return;
+ if (!separator.test_axis(axis)) {
+ return;
+ }
}
}
}
@@ -2157,8 +2178,8 @@ static void _collision_convex_polygon_convex_polygon(const GodotShape3D *p_a, co
//edge-vertex (shell)
for (int i = 0; i < edge_count_A; i++) {
- Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].a]);
- Vector3 e2 = p_transform_a.basis.xform(vertices_A[edges_A[i].b]);
+ Vector3 e1 = p_transform_a.basis.xform(vertices_A[edges_A[i].vertex_a]);
+ Vector3 e2 = p_transform_a.basis.xform(vertices_A[edges_A[i].vertex_b]);
Vector3 n = (e2 - e1);
for (int j = 0; j < vertex_count_B; j++) {
@@ -2171,8 +2192,8 @@ static void _collision_convex_polygon_convex_polygon(const GodotShape3D *p_a, co
}
for (int i = 0; i < edge_count_B; i++) {
- Vector3 e1 = p_transform_b.basis.xform(vertices_B[edges_B[i].a]);
- Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[i].b]);
+ Vector3 e1 = p_transform_b.basis.xform(vertices_B[edges_B[i].vertex_a]);
+ Vector3 e2 = p_transform_b.basis.xform(vertices_B[edges_B[i].vertex_b]);
Vector3 n = (e2 - e1);
for (int j = 0; j < vertex_count_A; j++) {
@@ -2231,7 +2252,7 @@ static void _collision_convex_polygon_face(const GodotShape3D *p_a, const Transf
// A<->B edges
for (int i = 0; i < edge_count; i++) {
- Vector3 e1 = p_transform_a.xform(vertices[edges[i].a]) - p_transform_a.xform(vertices[edges[i].b]);
+ Vector3 e1 = p_transform_a.xform(vertices[edges[i].vertex_a]) - p_transform_a.xform(vertices[edges[i].vertex_b]);
for (int j = 0; j < 3; j++) {
Vector3 e2 = vertex[j] - vertex[(j + 1) % 3];
@@ -2266,8 +2287,8 @@ static void _collision_convex_polygon_face(const GodotShape3D *p_a, const Transf
//edge-vertex (shell)
for (int i = 0; i < edge_count; i++) {
- Vector3 e1 = p_transform_a.basis.xform(vertices[edges[i].a]);
- Vector3 e2 = p_transform_a.basis.xform(vertices[edges[i].b]);
+ Vector3 e1 = p_transform_a.basis.xform(vertices[edges[i].vertex_a]);
+ Vector3 e2 = p_transform_a.basis.xform(vertices[edges[i].vertex_b]);
Vector3 n = (e2 - e1);
for (int j = 0; j < 3; j++) {
diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp
index 5574be20b7..1443cd166b 100644
--- a/servers/physics_3d/godot_shape_3d.cpp
+++ b/servers/physics_3d/godot_shape_3d.cpp
@@ -411,9 +411,9 @@ void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *
}
bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const {
- AABB aabb(-half_extents, half_extents * 2.0);
+ AABB aabb_ext(-half_extents, half_extents * 2.0);
- return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal);
+ return aabb_ext.intersects_segment(p_begin, p_end, &r_result, &r_normal);
}
bool GodotBoxShape3D::intersect_point(const Vector3 &p_point) const {
@@ -817,48 +817,78 @@ GodotCylinderShape3D::GodotCylinderShape3D() {}
/********** CONVEX POLYGON *************/
void GodotConvexPolygonShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const {
- int vertex_count = mesh.vertices.size();
+ uint32_t vertex_count = mesh.vertices.size();
if (vertex_count == 0) {
return;
}
const Vector3 *vrts = &mesh.vertices[0];
- for (int i = 0; i < vertex_count; i++) {
- real_t d = p_normal.dot(p_transform.xform(vrts[i]));
+ if (vertex_count > 3 * extreme_vertices.size()) {
+ // For a large mesh, two calls to get_support() is faster than a full
+ // scan over all vertices.
- if (i == 0 || d > r_max) {
- r_max = d;
- }
- if (i == 0 || d < r_min) {
- r_min = d;
+ Vector3 n = p_transform.basis.xform_inv(p_normal).normalized();
+ r_min = p_normal.dot(p_transform.xform(get_support(-n)));
+ r_max = p_normal.dot(p_transform.xform(get_support(n)));
+ } else {
+ for (uint32_t i = 0; i < vertex_count; i++) {
+ real_t d = p_normal.dot(p_transform.xform(vrts[i]));
+
+ if (i == 0 || d > r_max) {
+ r_max = d;
+ }
+ if (i == 0 || d < r_min) {
+ r_min = d;
+ }
}
}
}
Vector3 GodotConvexPolygonShape3D::get_support(const Vector3 &p_normal) const {
- Vector3 n = p_normal;
-
- int vert_support_idx = -1;
- real_t support_max = 0;
-
- int vertex_count = mesh.vertices.size();
- if (vertex_count == 0) {
+ if (mesh.vertices.size() == 0) {
return Vector3();
}
- const Vector3 *vrts = &mesh.vertices[0];
-
- for (int i = 0; i < vertex_count; i++) {
- real_t d = n.dot(vrts[i]);
+ // Find an initial guess for the support vertex by checking the ones we
+ // found in _setup().
- if (i == 0 || d > support_max) {
- support_max = d;
- vert_support_idx = i;
+ int best_vertex = -1;
+ real_t max_support = 0.0;
+ for (uint32_t i = 0; i < extreme_vertices.size(); i++) {
+ real_t s = p_normal.dot(mesh.vertices[extreme_vertices[i]]);
+ if (best_vertex == -1 || s > max_support) {
+ best_vertex = extreme_vertices[i];
+ max_support = s;
}
}
+ if (extreme_vertices.size() == mesh.vertices.size()) {
+ // We've already checked every vertex, so we can return now.
+ return mesh.vertices[best_vertex];
+ }
- return vrts[vert_support_idx];
+ // Move along the surface until we reach the true support vertex.
+
+ int last_vertex = -1;
+ while (true) {
+ int next_vertex = -1;
+ for (uint32_t i = 0; i < vertex_neighbors[best_vertex].size(); i++) {
+ int vert = vertex_neighbors[best_vertex][i];
+ if (vert != last_vertex) {
+ real_t s = p_normal.dot(mesh.vertices[vert]);
+ if (s > max_support) {
+ next_vertex = vert;
+ max_support = s;
+ break;
+ }
+ }
+ }
+ if (next_vertex == -1) {
+ return mesh.vertices[best_vertex];
+ }
+ last_vertex = best_vertex;
+ best_vertex = next_vertex;
+ }
}
void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const {
@@ -915,13 +945,13 @@ void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max,
}
for (int i = 0; i < ec; i++) {
- real_t dot = (vertices[edges[i].a] - vertices[edges[i].b]).normalized().dot(p_normal);
+ real_t dot = (vertices[edges[i].vertex_a] - vertices[edges[i].vertex_b]).normalized().dot(p_normal);
dot = ABS(dot);
- if (dot < edge_support_threshold && (edges[i].a == vtx || edges[i].b == vtx)) {
+ if (dot < edge_support_threshold && (edges[i].vertex_a == vtx || edges[i].vertex_b == vtx)) {
r_amount = 2;
r_type = FEATURE_EDGE;
- r_supports[0] = vertices[edges[i].a];
- r_supports[1] = vertices[edges[i].b];
+ r_supports[0] = vertices[edges[i].vertex_a];
+ r_supports[1] = vertices[edges[i].vertex_b];
return;
}
}
@@ -1025,8 +1055,8 @@ Vector3 GodotConvexPolygonShape3D::get_closest_point_to(const Vector3 &p_point)
int ec = mesh.edges.size();
for (int i = 0; i < ec; i++) {
Vector3 s[2] = {
- vertices[edges[i].a],
- vertices[edges[i].b]
+ vertices[edges[i].vertex_a],
+ vertices[edges[i].vertex_b]
};
Vector3 closest = Geometry3D::get_closest_point_to_segment(p_point, s);
@@ -1058,7 +1088,7 @@ void GodotConvexPolygonShape3D::_setup(const Vector<Vector3> &p_vertices) {
AABB _aabb;
- for (int i = 0; i < mesh.vertices.size(); i++) {
+ for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
if (i == 0) {
_aabb.position = mesh.vertices[i];
} else {
@@ -1067,6 +1097,43 @@ void GodotConvexPolygonShape3D::_setup(const Vector<Vector3> &p_vertices) {
}
configure(_aabb);
+
+ // Pre-compute the extreme vertices in 26 directions. This will be used
+ // to speed up get_support() by letting us quickly get a good guess for
+ // the support vertex.
+
+ for (int x = -1; x < 2; x++) {
+ for (int y = -1; y < 2; y++) {
+ for (int z = -1; z < 2; z++) {
+ if (x != 0 || y != 0 || z != 0) {
+ Vector3 dir(x, y, z);
+ dir.normalize();
+ real_t max_support = 0.0;
+ int best_vertex = -1;
+ for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
+ real_t s = dir.dot(mesh.vertices[i]);
+ if (best_vertex == -1 || s > max_support) {
+ best_vertex = i;
+ max_support = s;
+ }
+ }
+ if (extreme_vertices.find(best_vertex) == -1)
+ extreme_vertices.push_back(best_vertex);
+ }
+ }
+ }
+ }
+
+ // Record all the neighbors of each vertex. This is used in get_support().
+
+ if (extreme_vertices.size() < mesh.vertices.size()) {
+ vertex_neighbors.resize(mesh.vertices.size());
+ for (uint32_t i = 0; i < mesh.edges.size(); i++) {
+ Geometry3D::MeshData::Edge &edge = mesh.edges[i];
+ vertex_neighbors[edge.vertex_a].push_back(edge.vertex_b);
+ vertex_neighbors[edge.vertex_b].push_back(edge.vertex_a);
+ }
+ }
}
void GodotConvexPolygonShape3D::set_data(const Variant &p_data) {
@@ -1074,7 +1141,12 @@ void GodotConvexPolygonShape3D::set_data(const Variant &p_data) {
}
Variant GodotConvexPolygonShape3D::get_data() const {
- return mesh.vertices;
+ Vector<Vector3> vertices;
+ vertices.resize(mesh.vertices.size());
+ for (uint32_t i = 0; i < mesh.vertices.size(); i++) {
+ vertices.write[i] = mesh.vertices[i];
+ }
+ return vertices;
}
GodotConvexPolygonShape3D::GodotConvexPolygonShape3D() {
@@ -1259,14 +1331,14 @@ Vector3 GodotConcavePolygonShape3D::get_support(const Vector3 &p_normal) const {
}
void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_params) const {
- const BVH *bvh = &p_params->bvh[p_idx];
+ const BVH *params_bvh = &p_params->bvh[p_idx];
- if (!bvh->aabb.intersects_segment(p_params->from, p_params->to)) {
+ if (!params_bvh->aabb.intersects_segment(p_params->from, p_params->to)) {
return;
}
- if (bvh->face_index >= 0) {
- const Face *f = &p_params->faces[bvh->face_index];
+ if (params_bvh->face_index >= 0) {
+ const Face *f = &p_params->faces[params_bvh->face_index];
GodotFaceShape3D *face = p_params->face;
face->normal = f->normal;
face->vertex[0] = p_params->vertices[f->indices[0]];
@@ -1285,11 +1357,11 @@ void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_
}
}
} else {
- if (bvh->left >= 0) {
- _cull_segment(bvh->left, p_params);
+ if (params_bvh->left >= 0) {
+ _cull_segment(params_bvh->left, p_params);
}
- if (bvh->right >= 0) {
- _cull_segment(bvh->right, p_params);
+ if (params_bvh->right >= 0) {
+ _cull_segment(params_bvh->right, p_params);
}
}
}
@@ -1339,14 +1411,14 @@ Vector3 GodotConcavePolygonShape3D::get_closest_point_to(const Vector3 &p_point)
}
bool GodotConcavePolygonShape3D::_cull(int p_idx, _CullParams *p_params) const {
- const BVH *bvh = &p_params->bvh[p_idx];
+ const BVH *params_bvh = &p_params->bvh[p_idx];
- if (!p_params->aabb.intersects(bvh->aabb)) {
+ if (!p_params->aabb.intersects(params_bvh->aabb)) {
return false;
}
- if (bvh->face_index >= 0) {
- const Face *f = &p_params->faces[bvh->face_index];
+ if (params_bvh->face_index >= 0) {
+ const Face *f = &p_params->faces[params_bvh->face_index];
GodotFaceShape3D *face = p_params->face;
face->normal = f->normal;
face->vertex[0] = p_params->vertices[f->indices[0]];
@@ -1356,14 +1428,14 @@ bool GodotConcavePolygonShape3D::_cull(int p_idx, _CullParams *p_params) const {
return true;
}
} else {
- if (bvh->left >= 0) {
- if (_cull(bvh->left, p_params)) {
+ if (params_bvh->left >= 0) {
+ if (_cull(params_bvh->left, p_params)) {
return true;
}
}
- if (bvh->right >= 0) {
- if (_cull(bvh->right, p_params)) {
+ if (params_bvh->right >= 0) {
+ if (_cull(params_bvh->right, p_params)) {
return true;
}
}
@@ -1919,14 +1991,14 @@ Vector3 GodotHeightMapShape3D::get_closest_point_to(const Vector3 &p_point) cons
}
void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const {
- const AABB &aabb = get_aabb();
+ const AABB &shape_aabb = get_aabb();
- Vector3 pos_local = aabb.position + local_origin;
+ Vector3 pos_local = shape_aabb.position + local_origin;
Vector3 clamped_point(p_point);
- clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + aabb.size.x);
- clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + aabb.size.y);
- clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.x + aabb.size.z);
+ clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + shape_aabb.size.x);
+ clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + shape_aabb.size.y);
+ clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.x + shape_aabb.size.z);
r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5);
r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5);
@@ -2070,19 +2142,19 @@ void GodotHeightMapShape3D::_setup(const Vector<real_t> &p_heights, int p_width,
depth = p_depth;
// Initialize aabb.
- AABB aabb;
- aabb.position = Vector3(0.0, p_min_height, 0.0);
- aabb.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1);
+ AABB aabb_new;
+ aabb_new.position = Vector3(0.0, p_min_height, 0.0);
+ aabb_new.size = Vector3(p_width - 1, p_max_height - p_min_height, p_depth - 1);
// Initialize origin as the aabb center.
- local_origin = aabb.position + 0.5 * aabb.size;
+ local_origin = aabb_new.position + 0.5 * aabb_new.size;
local_origin.y = 0.0;
- aabb.position -= local_origin;
+ aabb_new.position -= local_origin;
_build_accelerator();
- configure(aabb);
+ configure(aabb_new);
}
void GodotHeightMapShape3D::set_data(const Variant &p_data) {
@@ -2093,11 +2165,11 @@ void GodotHeightMapShape3D::set_data(const Variant &p_data) {
ERR_FAIL_COND(!d.has("depth"));
ERR_FAIL_COND(!d.has("heights"));
- int width = d["width"];
- int depth = d["depth"];
+ int width_new = d["width"];
+ int depth_new = d["depth"];
- ERR_FAIL_COND(width <= 0.0);
- ERR_FAIL_COND(depth <= 0.0);
+ ERR_FAIL_COND(width_new <= 0.0);
+ ERR_FAIL_COND(depth_new <= 0.0);
Variant heights_variant = d["heights"];
Vector<real_t> heights_buffer;
@@ -2151,10 +2223,10 @@ void GodotHeightMapShape3D::set_data(const Variant &p_data) {
ERR_FAIL_COND(min_height > max_height);
- ERR_FAIL_COND(heights_buffer.size() != (width * depth));
+ ERR_FAIL_COND(heights_buffer.size() != (width_new * depth_new));
// If specified, min and max height will be used as precomputed values.
- _setup(heights_buffer, width, depth, min_height, max_height);
+ _setup(heights_buffer, width_new, depth_new, min_height, max_height);
}
Variant GodotHeightMapShape3D::get_data() const {
@@ -2162,9 +2234,9 @@ Variant GodotHeightMapShape3D::get_data() const {
d["width"] = width;
d["depth"] = depth;
- const AABB &aabb = get_aabb();
- d["min_height"] = aabb.position.y;
- d["max_height"] = aabb.position.y + aabb.size.y;
+ const AABB &shape_aabb = get_aabb();
+ d["min_height"] = shape_aabb.position.y;
+ d["max_height"] = shape_aabb.position.y + shape_aabb.size.y;
d["heights"] = heights;
diff --git a/servers/physics_3d/godot_shape_3d.h b/servers/physics_3d/godot_shape_3d.h
index 1fc8f7c711..dc8e34e2bc 100644
--- a/servers/physics_3d/godot_shape_3d.h
+++ b/servers/physics_3d/godot_shape_3d.h
@@ -277,6 +277,8 @@ public:
struct GodotConvexPolygonShape3D : public GodotShape3D {
Geometry3D::MeshData mesh;
+ LocalVector<int> extreme_vertices;
+ LocalVector<LocalVector<int>> vertex_neighbors;
void _setup(const Vector<Vector3> &p_vertices);
diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp
index 173843072a..77110c5fbc 100644
--- a/servers/physics_3d/godot_soft_body_3d.cpp
+++ b/servers/physics_3d/godot_soft_body_3d.cpp
@@ -722,7 +722,14 @@ void GodotSoftBody3D::reoptimize_link_order() {
const int reop_not_dependent = -1;
const int reop_node_complete = -2;
- uint32_t i, link_count = links.size(), node_count = nodes.size();
+ uint32_t link_count = links.size();
+ uint32_t node_count = nodes.size();
+
+ if (link_count < 1 || node_count < 2) {
+ return;
+ }
+
+ uint32_t i;
Link *lr;
int ar, br;
Node *node0 = &(nodes[0]);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index a3feb97d5d..95425e72e8 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -490,7 +490,7 @@ public:
bool collide_separation_ray = false;
HashSet<RID> exclude_bodies;
HashSet<ObjectID> exclude_objects;
- bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping.
+ bool recovery_as_collision = false;
MotionParameters() {}
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 24cc7e8459..db21e1db06 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -99,6 +99,7 @@ void PhysicsDirectBodyState3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState3D::get_inverse_mass);
ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState3D::get_inverse_inertia);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &PhysicsDirectBodyState3D::get_inverse_inertia_tensor);
ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &PhysicsDirectBodyState3D::set_linear_velocity);
ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicsDirectBodyState3D::get_linear_velocity);
@@ -153,6 +154,7 @@ void PhysicsDirectBodyState3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inverse_inertia"), "", "get_inverse_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::BASIS, "inverse_inertia_tensor"), "", "get_inverse_inertia_tensor");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "total_gravity"), "", "get_total_gravity");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass"), "", "get_center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass_local"), "", "get_center_of_mass_local");
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index b21c4e9249..87877ad52d 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -527,7 +527,7 @@ public:
bool collide_separation_ray = false;
HashSet<RID> exclude_bodies;
HashSet<ObjectID> exclude_objects;
- bool recovery_as_collision = false; // Don't report margin recovery as collision by default, only used for floor snapping.
+ bool recovery_as_collision = false;
MotionParameters() {}
diff --git a/servers/rendering/dummy/environment/fog.h b/servers/rendering/dummy/environment/fog.h
index 623f94b95f..047b8e133d 100644
--- a/servers/rendering/dummy/environment/fog.h
+++ b/servers/rendering/dummy/environment/fog.h
@@ -41,7 +41,7 @@ public:
virtual RID fog_volume_allocate() override { return RID(); }
virtual void fog_volume_initialize(RID p_rid) override {}
- virtual void fog_free(RID p_rid) override {}
+ virtual void fog_volume_free(RID p_rid) override {}
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {}
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override {}
diff --git a/servers/rendering/dummy/rasterizer_canvas_dummy.h b/servers/rendering/dummy/rasterizer_canvas_dummy.h
index 64c4cf5024..65c64e8115 100644
--- a/servers/rendering/dummy/rasterizer_canvas_dummy.h
+++ b/servers/rendering/dummy/rasterizer_canvas_dummy.h
@@ -39,7 +39,6 @@ public:
void free_polygon(PolygonID p_polygon) override {}
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override {}
- void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override {}
RID light_create() override { return RID(); }
void light_set_texture(RID p_rid, RID p_texture) override {}
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h
index d867114384..0fde97e395 100644
--- a/servers/rendering/dummy/rasterizer_dummy.h
+++ b/servers/rendering/dummy/rasterizer_dummy.h
@@ -51,6 +51,7 @@ class RasterizerDummy : public RendererCompositor {
private:
uint64_t frame = 1;
double delta = 0;
+ double time = 0.0;
protected:
RasterizerCanvasDummy canvas;
@@ -82,6 +83,7 @@ public:
void begin_frame(double frame_step) override {
frame++;
delta = frame_step;
+ time += frame_step;
}
void prepare_for_blitting_render_targets() override {}
@@ -106,6 +108,7 @@ public:
uint64_t get_frame_number() const override { return frame; }
double get_frame_delta_time() const override { return delta; }
+ double get_total_time() const override { return time; }
RasterizerDummy() {}
~RasterizerDummy() {}
diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h
index e41373ed37..bc8f7c523b 100644
--- a/servers/rendering/dummy/rasterizer_scene_dummy.h
+++ b/servers/rendering/dummy/rasterizer_scene_dummy.h
@@ -93,17 +93,6 @@ public:
uint32_t geometry_instance_get_pair_mask() override { return 0; }
- /* SHADOW ATLAS API */
-
- RID shadow_atlas_create() override { return RID(); }
- void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override {}
- void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {}
- bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; }
-
- void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {}
- int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
- void set_directional_shadow_count(int p_count) override {}
-
/* SDFGI UPDATE */
void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
@@ -143,36 +132,12 @@ public:
void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
- RID light_instance_create(RID p_light) override { return RID(); }
- void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
- void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
- void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
- void light_instance_mark_visible(RID p_light_instance) override {}
-
RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); }
void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {}
void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override {}
RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override { return RID(); }
Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override { return Vector3(); }
- RID reflection_atlas_create() override { return RID(); }
- int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
- void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
-
- RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
- void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
- void reflection_probe_release_atlas_index(RID p_instance) override {}
- bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
- bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
- bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
- bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
-
- RID decal_instance_create(RID p_decal) override { return RID(); }
- void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
-
- RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
- void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
-
RID voxel_gi_instance_create(RID p_voxel_gi) override { return RID(); }
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override {}
bool voxel_gi_needs_update(RID p_probe) const override { return false; }
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index 79f484d513..13c342d823 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -81,6 +81,15 @@ public:
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
virtual uint64_t light_get_version(RID p_light) const override { return 0; }
+ /* LIGHT INSTANCE API */
+
+ RID light_instance_create(RID p_light) override { return RID(); }
+ void light_instance_free(RID p_light) override {}
+ void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
+ void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
+ void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
+ void light_instance_mark_visible(RID p_light_instance) override {}
+
/* PROBE API */
virtual RID reflection_probe_allocate() override { return RID(); }
virtual void reflection_probe_initialize(RID p_rid) override {}
@@ -110,7 +119,26 @@ public:
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; }
virtual bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
+ /* REFLECTION ATLAS */
+
+ virtual RID reflection_atlas_create() override { return RID(); }
+ virtual void reflection_atlas_free(RID p_ref_atlas) override {}
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
+
+ /* REFLECTION PROBE INSTANCE */
+
+ virtual RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
+ virtual void reflection_probe_instance_free(RID p_instance) override {}
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
+ virtual void reflection_probe_release_atlas_index(RID p_instance) override {}
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
+
/* LIGHTMAP CAPTURE */
+
virtual RID lightmap_allocate() override { return RID(); }
virtual void lightmap_initialize(RID p_rid) override {}
virtual void lightmap_free(RID p_rid) override {}
@@ -129,6 +157,25 @@ public:
virtual bool lightmap_is_interior(RID p_lightmap) const override { return false; }
virtual void lightmap_set_probe_capture_update_speed(float p_speed) override {}
virtual float lightmap_get_probe_capture_update_speed() const override { return 0; }
+
+ /* LIGHTMAP INSTANCE */
+
+ RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
+ void lightmap_instance_free(RID p_lightmap) override {}
+ void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
+
+ /* SHADOW ATLAS API */
+ virtual RID shadow_atlas_create() override { return RID(); }
+ virtual void shadow_atlas_free(RID p_atlas) override {}
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override {}
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {}
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; }
+
+ virtual void shadow_atlas_update(RID p_atlas) override {}
+
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {}
+ virtual int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
+ virtual void set_directional_shadow_count(int p_count) override {}
};
} // namespace RendererDummy
diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h
index ed8fefc558..b4e0a21ee1 100644
--- a/servers/rendering/dummy/storage/material_storage.h
+++ b/servers/rendering/dummy/storage/material_storage.h
@@ -54,7 +54,7 @@ public:
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override { return 0; }
virtual void global_shader_parameters_instance_free(RID p_instance) override {}
- virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override {}
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override {}
/* SHADER API */
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index c15b656d06..98acd5ad74 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -146,19 +146,28 @@ public:
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
+ /* DECAL INSTANCE */
+
+ virtual RID decal_instance_create(RID p_decal) override { return RID(); }
+ virtual void decal_instance_free(RID p_decal_instance) override {}
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+
/* RENDER TARGET */
virtual RID render_target_create() override { return RID(); }
virtual void render_target_free(RID p_rid) override {}
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
+ virtual Point2i render_target_get_position(RID p_render_target) const override { return Point2i(); }
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
- virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
- virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {}
+ virtual Size2i render_target_get_size(RID p_render_target) const override { return Size2i(); }
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override {}
+ virtual bool render_target_get_transparent(RID p_render_target) const override { return false; }
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override {}
- virtual bool render_target_was_used(RID p_render_target) override { return false; }
+ virtual bool render_target_get_direct_to_screen(RID p_render_target) const override { return false; }
+ virtual bool render_target_was_used(RID p_render_target) const override { return false; }
virtual void render_target_set_as_unused(RID p_render_target) override {}
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override {}
+ virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override { return RS::VIEWPORT_MSAA_DISABLED; }
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override {}
virtual bool render_target_is_clear_requested(RID p_render_target) override { return false; }
@@ -170,8 +179,19 @@ public:
virtual Rect2i render_target_get_sdf_rect(RID p_render_target) const override { return Rect2i(); }
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override {}
- virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override{};
- virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override{};
+ virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override {}
+ virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override { return RS::VIEWPORT_VRS_DISABLED; }
+ virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_vrs_texture(RID p_render_target) const override { return RID(); }
+
+ virtual void render_target_set_override_color(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_color(RID p_render_target) const override { return RID(); }
+ virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_depth(RID p_render_target) const override { return RID(); }
+ virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) override {}
+ virtual RID render_target_get_override_velocity(RID p_render_target) const override { return RID(); }
+
+ virtual RID render_target_get_texture(RID p_render_target) override { return RID(); }
};
} // namespace RendererDummy
diff --git a/servers/rendering/dummy/storage/utilities.h b/servers/rendering/dummy/storage/utilities.h
index cb7b2a2b63..a42ab0d814 100644
--- a/servers/rendering/dummy/storage/utilities.h
+++ b/servers/rendering/dummy/storage/utilities.h
@@ -109,6 +109,8 @@ public:
virtual String get_video_adapter_vendor() const override { return String(); }
virtual RenderingDevice::DeviceType get_video_adapter_type() const override { return RenderingDevice::DeviceType::DEVICE_TYPE_OTHER; }
virtual String get_video_adapter_api_version() const override { return String(); }
+
+ virtual Size2i get_maximum_viewport_size() const override { return Size2i(); };
};
} // namespace RendererDummy
diff --git a/servers/rendering/environment/renderer_fog.h b/servers/rendering/environment/renderer_fog.h
index c55021e1a1..8f38d5745e 100644
--- a/servers/rendering/environment/renderer_fog.h
+++ b/servers/rendering/environment/renderer_fog.h
@@ -41,7 +41,7 @@ public:
virtual RID fog_volume_allocate() = 0;
virtual void fog_volume_initialize(RID p_rid) = 0;
- virtual void fog_free(RID p_rid) = 0;
+ virtual void fog_volume_free(RID p_rid) = 0;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0;
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0;
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index c5818d9290..41d4ca8d5e 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -38,17 +38,17 @@
static const int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1;
-void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel) {
+void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask) {
RENDER_TIMESTAMP("Cull CanvasItem Tree");
memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *));
for (int i = 0; i < p_child_item_count; i++) {
- _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true);
+ _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask);
}
if (p_canvas_item) {
- _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true);
+ _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, canvas_cull_mask);
}
RendererCanvasRender::Item *list = nullptr;
@@ -114,16 +114,16 @@ void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<Renderer
} while (ysort_owner && ysort_owner->sort_y);
}
-void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
+void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) {
if (ci->copy_back_buffer) {
ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect);
}
- if (use_canvas_group) {
+ if (p_use_canvas_group) {
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
if (canvas_group_from == nullptr) {
// no list before processing this item, means must put stuff in group from the beginning of list.
- canvas_group_from = z_list[zidx];
+ canvas_group_from = r_z_list[zidx];
} else {
// there was a list before processing, so begin group from this one.
canvas_group_from = canvas_group_from->next;
@@ -198,13 +198,13 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- if (z_last_list[zidx]) {
- z_last_list[zidx]->next = ci;
- z_last_list[zidx] = ci;
+ if (r_z_last_list[zidx]) {
+ r_z_last_list[zidx]->next = ci;
+ r_z_last_list[zidx] = ci;
} else {
- z_list[zidx] = ci;
- z_last_list[zidx] = ci;
+ r_z_list[zidx] = ci;
+ r_z_last_list[zidx] = ci;
}
ci->z_final = p_z;
@@ -223,13 +223,17 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
}
}
-void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) {
+void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask) {
Item *ci = p_canvas_item;
if (!ci->visible) {
return;
}
+ if (!(ci->visibility_layer & canvas_cull_mask)) {
+ return;
+ }
+
if (ci->children_order_dirty) {
ci->child_items.sort_custom<ItemIndexSort>();
ci->children_order_dirty = false;
@@ -313,43 +317,43 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
sorter.sort(child_items, child_item_count);
for (i = 0; i < child_item_count; i++) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, child_items[i]->ysort_parent_abs_z_index, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false);
+ _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, canvas_cull_mask);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
if (use_canvas_group) {
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- canvas_group_from = z_last_list[zidx];
+ canvas_group_from = r_z_last_list[zidx];
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr);
if (use_canvas_group) {
int zidx = p_z - RS::CANVAS_ITEM_Z_MIN;
- canvas_group_from = z_last_list[zidx];
+ canvas_group_from = r_z_last_list[zidx];
}
for (int i = 0; i < child_item_count; i++) {
if (!child_items[i]->behind && !use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask);
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform);
for (int i = 0; i < child_item_count; i++) {
if (child_items[i]->behind || use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true);
+ _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, canvas_cull_mask);
}
}
}
-void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel) {
+void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask) {
RENDER_TIMESTAMP("> Render Canvas");
sdf_used = false;
@@ -372,26 +376,26 @@ void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, co
}
if (!has_mirror) {
- _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
} else {
//used for parallaxlayer mirroring
for (int i = 0; i < l; i++) {
const Canvas::ChildItem &ci2 = p_canvas->child_items[i];
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
//mirroring (useful for scrolling backgrounds)
if (ci2.mirror.x != 0) {
Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0));
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
}
if (ci2.mirror.y != 0) {
Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y));
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
}
if (ci2.mirror.y != 0 && ci2.mirror.x != 0) {
Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror);
- _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel);
+ _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask);
}
}
}
@@ -513,6 +517,20 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D
canvas_item->xform = p_transform;
}
+void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ canvas_item->visibility_layer = p_visibility_layer;
+}
+
+uint32_t RendererCanvasCull::canvas_item_get_visibility_layer(RID p_item) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ if (!canvas_item)
+ return 0;
+ return canvas_item->visibility_layer;
+}
+
void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 0d6a4006f8..198e1020f0 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -54,6 +54,7 @@ public:
Vector2 ysort_pos;
int ysort_index;
int ysort_parent_abs_z_index; // Absolute Z index of parent. Only populated and used when y-sorting.
+ uint32_t visibility_layer = 0xffffffff;
Vector<Item *> child_items;
@@ -176,17 +177,17 @@ public:
PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator;
SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list;
- _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
+ _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform);
private:
- void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel);
- void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort);
+ void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask);
+ void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort, uint32_t canvas_cull_mask);
RendererCanvasRender::Item **z_list;
RendererCanvasRender::Item **z_last_list;
public:
- void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel);
+ void render_canvas(RID p_render_target, Canvas *p_canvas, const Transform2D &p_transform, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, const Rect2 &p_clip_rect, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_transforms_to_pixel, bool p_snap_2d_vertices_to_pixel, uint32_t canvas_cull_mask);
bool was_sdf_used();
@@ -206,6 +207,9 @@ public:
void canvas_item_set_visible(RID p_item, bool p_visible);
void canvas_item_set_light_mask(RID p_item, int p_mask);
+ void canvas_item_set_visibility_layer(RID p_item, uint32_t p_layer);
+ uint32_t canvas_item_get_visibility_layer(RID p_item);
+
void canvas_item_set_transform(RID p_item, const Transform2D &p_transform);
void canvas_item_set_clip(RID p_item, bool p_clip);
void canvas_item_set_distance_field_mode(RID p_item, bool p_enable);
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index 6791ed9626..375358a5e8 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -476,7 +476,6 @@ public:
};
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) = 0;
- virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) = 0;
struct LightOccluderInstance {
bool enabled;
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 8e04191e35..169988f72c 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -102,6 +102,7 @@ public:
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
+ virtual double get_total_time() const = 0;
static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index 53237c1dfb..a14228eb3d 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -357,8 +357,8 @@ void CopyEffects::copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, cons
copy.push_constant.flags |= COPY_FLAG_ALPHA_TO_ONE;
}
- copy.push_constant.section[0] = 0;
- copy.push_constant.section[1] = 0;
+ copy.push_constant.section[0] = p_rect.position.x;
+ copy.push_constant.section[1] = p_rect.position.y;
copy.push_constant.section[2] = p_rect.size.width;
copy.push_constant.section[3] = p_rect.size.height;
copy.push_constant.target[0] = p_rect.position.x;
diff --git a/servers/rendering/renderer_rd/effects/fsr.cpp b/servers/rendering/renderer_rd/effects/fsr.cpp
index 5fde24a926..92b34ede0e 100644
--- a/servers/rendering/renderer_rd/effects/fsr.cpp
+++ b/servers/rendering/renderer_rd/effects/fsr.cpp
@@ -29,7 +29,8 @@
/*************************************************************************/
#include "fsr.h"
-#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+#include "../storage_rd/material_storage.h"
+#include "../uniform_set_cache_rd.h"
using namespace RendererRD;
diff --git a/servers/rendering/renderer_rd/effects/fsr.h b/servers/rendering/renderer_rd/effects/fsr.h
index 1adfba527a..69088e526a 100644
--- a/servers/rendering/renderer_rd/effects/fsr.h
+++ b/servers/rendering/renderer_rd/effects/fsr.h
@@ -31,11 +31,10 @@
#ifndef FSR_RD_H
#define FSR_RD_H
-#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
-#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
-#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "../pipeline_cache_rd.h"
+#include "../shaders/effects/fsr_upscale.glsl.gen.h"
+#include "../storage_rd/render_scene_buffers_rd.h"
#include "servers/rendering/renderer_scene_render.h"
-
#include "servers/rendering_server.h"
namespace RendererRD {
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 582c5abbdd..9653382e96 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -30,6 +30,7 @@
#include "ss_effects.h"
+#include "core/config/project_settings.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
@@ -42,7 +43,7 @@ SSEffects *SSEffects::singleton = nullptr;
static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ p_array[i * 4 + j] = p_mtx.columns[i][j];
}
}
}
@@ -50,8 +51,8 @@ static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array)
SSEffects::SSEffects() {
singleton = this;
+ // Initialize depth buffer for screen space effects
{
- // Initialize depth buffer for screen space effects
Vector<String> downsampler_modes;
downsampler_modes.push_back("\n");
downsampler_modes.push_back("\n#define USE_HALF_SIZE\n");
@@ -100,6 +101,7 @@ SSEffects::SSEffects() {
}
// Initialize Screen Space Indirect Lighting (SSIL)
+ ssil_set_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to"));
{
Vector<String> ssil_modes;
@@ -175,9 +177,10 @@ SSEffects::SSEffects() {
}
}
- {
- // Initialize Screen Space Ambient Occlusion (SSAO)
+ // Initialize Screen Space Ambient Occlusion (SSAO)
+ ssao_set_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
+ {
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
@@ -276,9 +279,10 @@ SSEffects::SSEffects() {
ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler);
}
- {
- // Screen Space Reflections
+ // Screen Space Reflections
+ ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
+ {
Vector<RD::PipelineSpecializationConstant> specialization_constants;
{
@@ -336,6 +340,10 @@ SSEffects::SSEffects() {
}
// Subsurface scattering
+ sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
+ sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+ sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
+
{
Vector<String> sss_modes;
sss_modes.push_back("\n#define USE_11_SAMPLES\n");
@@ -403,7 +411,7 @@ SSEffects::~SSEffects() {
/* SS Downsampler */
-void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const Projection &p_projection) {
+void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -413,9 +421,9 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
int downsample_mode = SS_EFFECTS_DOWNSAMPLE;
- bool use_mips = p_ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || p_ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM;
+ bool use_mips = ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM;
- if (p_ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && p_ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF;
} else if (use_mips) {
downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP;
@@ -424,10 +432,10 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
bool use_half_size = false;
bool use_full_mips = false;
- if (p_ssao_half_size && p_ssil_half_size) {
+ if (ssao_half_size && ssil_half_size) {
downsample_mode++;
use_half_size = true;
- } else if (p_ssao_half_size != p_ssil_half_size) {
+ } else if (ssao_half_size != ssil_half_size) {
if (use_mips) {
downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS;
use_full_mips = true;
@@ -480,8 +488,8 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
ss_effects.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, use_full_mips ? 6 : 2), 2);
}
- float depth_linearize_mul = -p_projection.matrix[3][2];
- float depth_linearize_add = p_projection.matrix[2][2];
+ float depth_linearize_mul = -p_projection.columns[3][2];
+ float depth_linearize_add = p_projection.columns[2][2];
if (depth_linearize_mul * depth_linearize_add < 0) {
depth_linearize_add = -depth_linearize_add;
}
@@ -526,12 +534,21 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
/* SSIL */
+void SSEffects::ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ssil_quality = p_quality;
+ ssil_half_size = p_half_size;
+ ssil_adaptive_target = p_adaptive_target;
+ ssil_blur_passes = p_blur_passes;
+ ssil_fadeout_from = p_fadeout_from;
+ ssil_fadeout_to = p_fadeout_to;
+}
+
void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
- if ((p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) {
+ if ((ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) {
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1);
}
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3);
@@ -539,7 +556,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0);
for (int i = 0; i < 4; i++) {
- if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+ if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
continue;
}
@@ -554,7 +571,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ssil_slice, u_edges_slice), 2);
RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant));
- Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+ Size2i size = Size2i(p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssil_half_size ? 2 : 1));
RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
}
@@ -562,11 +579,11 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
}
void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings, RID p_linear_depth) {
- if (p_ssil_buffers.half_size != p_settings.half_size) {
+ if (p_ssil_buffers.half_size != ssil_half_size) {
ssil_free(p_ssil_buffers);
}
- if (p_settings.half_size) {
+ if (ssil_half_size) {
p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4;
p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4;
p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8;
@@ -580,7 +597,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S
if (p_ssil_buffers.ssil_final.is_null()) {
{
- p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
+ p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
}
{
RD::TextureFormat tf;
@@ -665,7 +682,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S
p_ssil_buffers.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(p_ssil_buffers.importance_map[1], "SSIL Importance Map Pong");
}
- p_ssil_buffers.half_size = p_settings.half_size;
+ p_ssil_buffers.half_size = ssil_half_size;
}
}
@@ -696,8 +713,8 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
ssil.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
ssil.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
- float tan_half_fov_x = 1.0 / p_projection.matrix[0][0];
- float tan_half_fov_y = 1.0 / p_projection.matrix[1][1];
+ float tan_half_fov_x = 1.0 / p_projection.columns[0][0];
+ float tan_half_fov_y = 1.0 / p_projection.columns[1][1];
ssil.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0;
ssil.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0;
ssil.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0;
@@ -711,26 +728,26 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
ssil.gather_push_constant.radius = p_settings.radius;
float radius_near_limit = (p_settings.radius * 1.2f);
- if (p_settings.quality <= RS::ENV_SSIL_QUALITY_LOW) {
+ if (ssil_quality <= RS::ENV_SSIL_QUALITY_LOW) {
radius_near_limit *= 1.50f;
- if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
ssil.gather_push_constant.radius *= 0.8f;
}
}
radius_near_limit /= tan_half_fov_y;
ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI;
- ssil.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from);
- ssil.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0;
+ ssil.gather_push_constant.fade_out_mul = -1.0 / (ssil_fadeout_to - ssil_fadeout_from);
+ ssil.gather_push_constant.fade_out_add = ssil_fadeout_from / (ssil_fadeout_to - ssil_fadeout_from) + 1.0;
ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit;
ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius;
ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection;
ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssil_buffers.half_buffer_width) * (p_ssil_buffers.half_buffer_height) * 255);
- ssil.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target;
+ ssil.gather_push_constant.adaptive_sample_limit = ssil_adaptive_target;
- ssil.gather_push_constant.quality = MAX(0, p_settings.quality - 1);
- ssil.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1;
+ ssil.gather_push_constant.quality = MAX(0, ssil_quality - 1);
+ ssil.gather_push_constant.size_multiplier = ssil_half_size ? 2 : 1;
if (p_ssil_buffers.projection_uniform_set.is_null()) {
Vector<RD::Uniform> uniforms;
@@ -806,7 +823,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
p_ssil_buffers.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 2), 1);
}
- if (p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) {
+ if (ssil_quality == RS::ENV_SSIL_QUALITY_ULTRA) {
RD::get_singleton()->draw_command_begin_label("Generate Importance Map");
ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
@@ -865,13 +882,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
- int blur_passes = p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? p_settings.blur_passes : 1;
+ int blur_passes = ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? ssil_blur_passes : 1;
shader = ssil.blur_shader.version_get_shader(ssil.blur_shader_version, 0);
for (int pass = 0; pass < blur_passes; pass++) {
int blur_pipeline = SSIL_BLUR_PASS;
- if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
blur_pipeline = SSIL_BLUR_PASS_SMART;
if (pass < blur_passes - 2) {
blur_pipeline = SSIL_BLUR_PASS_WIDE;
@@ -879,13 +896,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
}
for (int i = 0; i < 4; i++) {
- if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+ if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
continue;
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]);
if (pass % 2 == 0) {
- if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_slice), 0);
} else {
@@ -896,7 +913,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.pong_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_pong_slice), 1);
} else {
- if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.pong_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_pong_slice), 0);
} else {
@@ -913,11 +930,11 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant));
- int x_groups = (p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1));
- int y_groups = (p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+ int x_groups = (p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1));
+ int y_groups = (p_settings.full_screen_size.y >> (ssil_half_size ? 2 : 1));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1);
- if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
+ if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
RD::get_singleton()->compute_list_add_barrier(compute_list);
}
}
@@ -931,12 +948,12 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness;
ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x;
ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y;
- ssil.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2);
+ ssil.interleave_push_constant.size_modifier = uint32_t(ssil_half_size ? 4 : 2);
int interleave_pipeline = SSIL_INTERLEAVE_HALF;
- if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) {
+ if (ssil_quality == RS::ENV_SSIL_QUALITY_LOW) {
interleave_pipeline = SSIL_INTERLEAVE;
- } else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) {
+ } else if (ssil_quality >= RS::ENV_SSIL_QUALITY_MEDIUM) {
interleave_pipeline = SSIL_INTERLEAVE_SMART;
}
@@ -947,7 +964,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
RD::Uniform u_destination(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.ssil_final }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_destination), 0);
- if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) {
+ if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW && ssil_blur_passes % 2 == 0) {
RD::Uniform u_ssil(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil), 1);
} else {
@@ -1003,19 +1020,28 @@ void SSEffects::ssil_free(SSILRenderBuffers &p_ssil_buffers) {
/* SSAO */
+void SSEffects::ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ssao_quality = p_quality;
+ ssao_half_size = p_half_size;
+ ssao_adaptive_target = p_adaptive_target;
+ ssao_blur_passes = p_blur_passes;
+ ssao_fadeout_from = p_fadeout_from;
+ ssao_fadeout_to = p_fadeout_to;
+}
+
void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
- if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
+ if ((ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 0);
}
RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 1); //
for (int i = 0; i < 4; i++) {
- if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+ if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
continue;
}
@@ -1029,7 +1055,7 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ao_slice), 2);
RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant));
- Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+ Size2i size = Size2i(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_half_size ? 2 : 1));
RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
}
@@ -1037,11 +1063,11 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
}
void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings, RID p_linear_depth) {
- if (p_ssao_buffers.half_size != p_settings.half_size) {
+ if (p_ssao_buffers.half_size != ssao_half_size) {
ssao_free(p_ssao_buffers);
}
- if (p_settings.half_size) {
+ if (ssao_half_size) {
p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4;
p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4;
p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8;
@@ -1055,7 +1081,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S
if (p_ssao_buffers.ao_deinterleaved.is_null()) {
{
- p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
+ p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
}
{
RD::TextureFormat tf;
@@ -1111,7 +1137,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S
p_ssao_buffers.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(p_ssao_buffers.ao_final, "SSAO Final");
}
- p_ssao_buffers.half_size = p_settings.half_size;
+ p_ssao_buffers.half_size = ssao_half_size;
}
}
@@ -1138,8 +1164,8 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
ssao.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
ssao.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
- float tan_half_fov_x = 1.0 / p_projection.matrix[0][0];
- float tan_half_fov_y = 1.0 / p_projection.matrix[1][1];
+ float tan_half_fov_x = 1.0 / p_projection.columns[0][0];
+ float tan_half_fov_y = 1.0 / p_projection.columns[1][1];
ssao.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0;
ssao.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0;
ssao.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0;
@@ -1151,10 +1177,10 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
ssao.gather_push_constant.radius = p_settings.radius;
float radius_near_limit = (p_settings.radius * 1.2f);
- if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) {
+ if (ssao_quality <= RS::ENV_SSAO_QUALITY_LOW) {
radius_near_limit *= 1.50f;
- if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
ssao.gather_push_constant.radius *= 0.8f;
}
}
@@ -1162,18 +1188,18 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
ssao.gather_push_constant.intensity = p_settings.intensity;
ssao.gather_push_constant.shadow_power = p_settings.power;
ssao.gather_push_constant.shadow_clamp = 0.98;
- ssao.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from);
- ssao.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0;
+ ssao.gather_push_constant.fade_out_mul = -1.0 / (ssao_fadeout_to - ssao_fadeout_from);
+ ssao.gather_push_constant.fade_out_add = ssao_fadeout_from / (ssao_fadeout_to - ssao_fadeout_from) + 1.0;
ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon;
ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit;
ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius;
ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssao_buffers.half_buffer_width) * (p_ssao_buffers.half_buffer_height) * 255);
- ssao.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target;
+ ssao.gather_push_constant.adaptive_sample_limit = ssao_adaptive_target;
ssao.gather_push_constant.detail_intensity = p_settings.detail;
- ssao.gather_push_constant.quality = MAX(0, p_settings.quality - 1);
- ssao.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1;
+ ssao.gather_push_constant.quality = MAX(0, ssao_quality - 1);
+ ssao.gather_push_constant.size_multiplier = ssao_half_size ? 2 : 1;
if (p_ssao_buffers.gather_uniform_set.is_null()) {
Vector<RD::Uniform> uniforms;
@@ -1231,7 +1257,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
RD::get_singleton()->set_resource_name(p_ssao_buffers.importance_map_uniform_set, "SSAO Importance Map Uniform Set");
}
- if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) {
RD::get_singleton()->draw_command_begin_label("Generate Importance Map");
ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
@@ -1299,13 +1325,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
- int blur_passes = p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? p_settings.blur_passes : 1;
+ int blur_passes = ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? ssao_blur_passes : 1;
shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0);
for (int pass = 0; pass < blur_passes; pass++) {
int blur_pipeline = SSAO_BLUR_PASS;
- if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
+ if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
blur_pipeline = SSAO_BLUR_PASS_SMART;
if (pass < blur_passes - 2) {
blur_pipeline = SSAO_BLUR_PASS_WIDE;
@@ -1315,13 +1341,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
}
for (int i = 0; i < 4; i++) {
- if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+ if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
continue;
}
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]);
if (pass % 2 == 0) {
- if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_slices_with_sampler), 0);
} else {
@@ -1332,7 +1358,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
RD::Uniform u_ao_pong_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_pong_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao_pong_slices), 1);
} else {
- if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_pong_slices[i] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_pong_slices_with_sampler), 0);
} else {
@@ -1345,11 +1371,11 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
}
RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
- Size2i size(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+ Size2i size(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_half_size ? 2 : 1));
RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1);
}
- if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
+ if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
RD::get_singleton()->compute_list_add_barrier(compute_list);
}
}
@@ -1364,14 +1390,14 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness;
ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x;
ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y;
- ssao.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2);
+ ssao.interleave_push_constant.size_modifier = uint32_t(ssao_half_size ? 4 : 2);
shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, 0);
int interleave_pipeline = SSAO_INTERLEAVE_HALF;
- if (p_settings.quality == RS::ENV_SSAO_QUALITY_LOW) {
+ if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) {
interleave_pipeline = SSAO_INTERLEAVE;
- } else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) {
+ } else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) {
interleave_pipeline = SSAO_INTERLEAVE_SMART;
}
@@ -1380,7 +1406,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
RD::Uniform u_upscale_buffer(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_final }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_buffer), 0);
- if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) {
+ if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW && ssao_blur_passes % 2 == 0) {
RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao), 1);
} else {
@@ -1425,8 +1451,23 @@ void SSEffects::ssao_free(SSAORenderBuffers &p_ssao_buffers) {
/* Screen Space Reflection */
-void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count) {
+void SSEffects::ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
+ ssr_roughness_quality = p_quality;
+}
+
+void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, const Size2i &p_screen_size, const uint32_t p_view_count) {
// As we are processing one view at a time, we can reuse buffers, only our output needs to have layers for each view.
+ if (p_ssr_buffers.size != p_screen_size || p_ssr_buffers.roughness_quality != ssr_roughness_quality) {
+ ssr_free(p_ssr_buffers);
+ }
+
+ if (p_ssr_buffers.output.is_valid()) {
+ // already allocated
+ return;
+ }
+
+ p_ssr_buffers.size = p_screen_size;
+ p_ssr_buffers.roughness_quality = ssr_roughness_quality;
if (p_ssr_buffers.depth_scaled.is_null()) {
RD::TextureFormat tf;
@@ -1446,7 +1487,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend
RD::get_singleton()->set_resource_name(p_ssr_buffers.normal_scaled, "SSR Normal Scaled");
}
- if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_ssr_buffers.blur_radius[0].is_valid()) {
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_ssr_buffers.blur_radius[0].is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
tf.width = p_screen_size.x;
@@ -1490,7 +1531,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend
}
}
-void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) {
+void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -1551,8 +1592,13 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
RD::Uniform u_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_normal_roughness_slices[v] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth, u_normal_roughness), 1);
- RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output_blur), 2);
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+ RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output), 2);
+ } else {
+ RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_intermediate), 2);
+ }
RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.depth_scaled }));
RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.normal_scaled }));
@@ -1581,12 +1627,12 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
push_constant.num_steps = p_max_steps;
push_constant.depth_tolerance = p_tolerance;
push_constant.use_half_res = true;
- push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
- push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
- push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
+ push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].columns[0][0]);
+ push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].columns[1][1]);
+ push_constant.proj_info[2] = (1.0f - p_projections[v].columns[0][2]) / p_projections[v].columns[0][0];
+ push_constant.proj_info[3] = (1.0f + p_projections[v].columns[1][2]) / p_projections[v].columns[1][1];
- ScreenSpaceReflectionMode mode = (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
+ ScreenSpaceReflectionMode mode = (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode);
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode]);
@@ -1594,17 +1640,25 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
- RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
- RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output_blur, u_scale_depth), 0);
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+ // read from output slices (our scale wrote into these)
+ RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+ RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output, u_scale_depth), 0);
- if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+ // write to intermediate (our roughness pass will output into output slices)
RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[0] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate, u_blur_radius), 1);
} else {
+ // read from intermediate (our scale wrote into these)
RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate), 1);
+ RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate, u_scale_depth), 0);
+
+ // We are not performing our blur so go directly to output.
+ RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_output), 1);
}
RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.normal_scaled }));
@@ -1619,7 +1673,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
RD::get_singleton()->draw_command_end_label();
}
- if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+ if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
RD::get_singleton()->draw_command_begin_label("SSR filter");
//blur
@@ -1629,15 +1683,15 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
push_constant.view_index = v;
push_constant.orthogonal = p_projections[v].is_orthogonal();
push_constant.edge_tolerance = Math::sin(Math::deg_to_rad(15.0));
- push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
- push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
- push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
+ push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].columns[0][0]);
+ push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].columns[1][1]);
+ push_constant.proj_info[2] = (1.0f - p_projections[v].columns[0][2]) / p_projections[v].columns[0][0];
+ push_constant.proj_info[3] = (1.0f + p_projections[v].columns[1][2]) / p_projections[v].columns[1][1];
push_constant.vertical = 0;
- if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) {
+ if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) {
push_constant.steps = p_max_steps / 3;
push_constant.increment = 3;
- } else if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {
+ } else if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {
push_constant.steps = p_max_steps / 2;
push_constant.increment = 2;
} else {
@@ -1740,7 +1794,20 @@ void SSEffects::ssr_free(SSRRenderBuffers &p_ssr_buffers) {
/* Subsurface scattering */
-void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
+void SSEffects::sss_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
+ sss_quality = p_quality;
+}
+
+RS::SubSurfaceScatteringQuality SSEffects::sss_get_quality() const {
+ return sss_quality;
+}
+
+void SSEffects::sss_set_scale(float p_scale, float p_depth_scale) {
+ sss_scale = p_scale;
+ sss_depth_scale = p_depth_scale;
+}
+
+void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -1769,11 +1836,11 @@ void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffer
sss.push_constant.screen_size[0] = p_screen_size.x;
sss.push_constant.screen_size[1] = p_screen_size.y;
sss.push_constant.vertical = false;
- sss.push_constant.scale = p_scale;
- sss.push_constant.depth_scale = p_depth_scale;
+ sss.push_constant.scale = sss_scale;
+ sss.push_constant.depth_scale = sss_depth_scale;
- RID shader = sss.shader.version_get_shader(sss.shader_version, p_quality - 1);
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
+ RID shader = sss.shader.version_get_shader(sss.shader_version, sss_quality - 1);
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1]);
RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse }));
RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse }));
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.h b/servers/rendering/renderer_rd/effects/ss_effects.h
index d50319c46f..dfaf3881bb 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.h
+++ b/servers/rendering/renderer_rd/effects/ss_effects.h
@@ -64,9 +64,10 @@ public:
/* SS Downsampler */
- void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const Projection &p_projection);
+ void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection);
/* SSIL */
+ void ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
struct SSILRenderBuffers {
bool half_size = false;
@@ -99,13 +100,6 @@ public:
float sharpness = 0.98;
float normal_rejection = 1.0;
- RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM;
- bool half_size = true;
- float adaptive_target = 0.5;
- int blur_passes = 4;
- float fadeout_from = 50.0;
- float fadeout_to = 300.0;
-
Size2i full_screen_size = Size2i();
};
@@ -114,6 +108,7 @@ public:
void ssil_free(SSILRenderBuffers &p_ssil_buffers);
/* SSAO */
+ void ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
struct SSAORenderBuffers {
bool half_size = false;
@@ -142,13 +137,6 @@ public:
float horizon = 0.06;
float sharpness = 0.98;
- RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM;
- bool half_size = false;
- float adaptive_target = 0.5;
- int blur_passes = 2;
- float fadeout_from = 50.0;
- float fadeout_to = 300.0;
-
Size2i full_screen_size = Size2i();
};
@@ -157,8 +145,12 @@ public:
void ssao_free(SSAORenderBuffers &p_ssao_buffers);
/* Screen Space Reflection */
+ void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
struct SSRRenderBuffers {
+ Size2i size;
+ RenderingServer::EnvironmentSSRRoughnessQuality roughness_quality = RenderingServer::ENV_SSR_ROUGHNESS_QUALITY_DISABLED;
+
RID normal_scaled;
RID depth_scaled;
RID blur_radius[2];
@@ -167,14 +159,40 @@ public:
RID output_slices[RendererSceneRender::MAX_RENDER_VIEWS];
};
- void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count);
- void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets);
+ void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, const Size2i &p_screen_size, const uint32_t p_view_count);
+ void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets);
void ssr_free(SSRRenderBuffers &p_ssr_buffers);
/* subsurface scattering */
- void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
+ void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality);
+ RS::SubSurfaceScatteringQuality sss_get_quality() const;
+ void sss_set_scale(float p_scale, float p_depth_scale);
+
+ void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size);
private:
+ /* Settings */
+
+ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
+ bool ssao_half_size = false;
+ float ssao_adaptive_target = 0.5;
+ int ssao_blur_passes = 2;
+ float ssao_fadeout_from = 50.0;
+ float ssao_fadeout_to = 300.0;
+
+ RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
+ bool ssil_half_size = false;
+ float ssil_adaptive_target = 0.5;
+ int ssil_blur_passes = 4;
+ float ssil_fadeout_from = 50.0;
+ float ssil_fadeout_to = 300.0;
+
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
+
+ RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
+ float sss_scale = 0.05;
+ float sss_depth_scale = 0.01;
+
/* SS Downsampler */
struct SSEffectsDownsamplePushConstant {
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 3390e9cf64..74082906c4 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -57,12 +57,19 @@ void Fog::fog_volume_initialize(RID p_rid) {
fog_volume_owner.initialize_rid(p_rid, FogVolume());
}
-void Fog::fog_free(RID p_rid) {
+void Fog::fog_volume_free(RID p_rid) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid);
fog_volume->dependency.deleted_notify(p_rid);
fog_volume_owner.free(p_rid);
}
+Dependency *Fog::fog_volume_get_dependency(RID p_fog_volume) const {
+ FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+ ERR_FAIL_NULL_V(fog_volume, nullptr);
+
+ return &fog_volume->dependency;
+}
+
void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
ERR_FAIL_COND(!fog_volume);
@@ -136,7 +143,7 @@ Vector3 Fog::fog_volume_get_extents(RID p_fog_volume) const {
bool Fog::FogMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
uniform_set_updated = true;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, Fog::get_singleton()->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL, true);
}
Fog::FogMaterialData::~FogMaterialData() {
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 9ecd5699dc..0ade995758 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -46,7 +46,9 @@
namespace RendererRD {
class Fog : public RendererFog {
-public:
+private:
+ static Fog *singleton;
+
/* FOG VOLUMES */
struct FogVolume {
@@ -58,16 +60,14 @@ public:
Dependency dependency;
};
+ mutable RID_Owner<FogVolume, true> fog_volume_owner;
+
struct FogVolumeInstance {
RID volume;
Transform3D transform;
bool active = false;
};
-private:
- static Fog *singleton;
-
- mutable RID_Owner<FogVolume, true> fog_volume_owner;
mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
/* Volumetric Fog */
@@ -240,12 +240,12 @@ public:
/* FOG VOLUMES */
- FogVolume *get_fog_volume(RID p_rid) { return fog_volume_owner.get_or_null(p_rid); };
bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); };
virtual RID fog_volume_allocate() override;
virtual void fog_volume_initialize(RID p_rid) override;
- virtual void fog_free(RID p_rid) override;
+ virtual void fog_volume_free(RID p_rid) override;
+ Dependency *fog_volume_get_dependency(RID p_fog_volume) const;
virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;
@@ -257,12 +257,35 @@ public:
/* FOG VOLUMES INSTANCE */
- FogVolumeInstance *get_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.get_or_null(p_rid); };
bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); };
RID fog_volume_instance_create(RID p_fog_volume);
void fog_instance_free(RID p_rid);
+ void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
+ Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND(!fvi);
+ fvi->transform = p_transform;
+ }
+
+ void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
+ Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND(!fvi);
+ fvi->active = p_active;
+ }
+
+ RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
+ Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND_V(!fvi, RID());
+ return fvi->volume;
+ }
+
+ Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const {
+ Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+ ERR_FAIL_COND_V(!fvi, Vector3());
+ return fvi->transform.get_origin();
+ }
+
/* Volumetric FOG */
class VolumetricFog : public RenderBufferCustomDataRD {
GDCLASS(VolumetricFog, RenderBufferCustomDataRD)
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index ced0f6380f..550fe27e4c 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -1634,7 +1634,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
Projection inv_projection = p_projections[v].inverse();
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3; j++) {
- push_constant.inv_projection[j][i] = inv_projection.matrix[i][j];
+ push_constant.inv_projection[j][i] = inv_projection.columns[i][j];
}
}
@@ -1644,8 +1644,8 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
RD::get_singleton()->compute_list_end();
}
- Size2 rtsize = texture_storage->render_target_get_size(p_render_target);
- copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2(Vector2(), rtsize), true, false, false, false, RID(), p_view_count > 1);
+ Size2i rtsize = texture_storage->render_target_get_size(p_render_target);
+ copy_effects->copy_to_fb_rect(p_texture, texture_storage->render_target_get_rd_framebuffer(p_render_target), Rect2i(Point2i(), rtsize), true, false, false, false, RID(), p_view_count > 1);
}
void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
@@ -1798,7 +1798,8 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con
RD::get_singleton()->draw_list_end();
}
-void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) {
+void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
/* Update general SDFGI Buffer */
SDFGIData sdfgi_data;
@@ -1881,40 +1882,43 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
SDFGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
uint32_t idx = 0;
- for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) {
+ for (uint32_t j = 0; j < (uint32_t)p_render_data->sdfgi_update_data->directional_lights->size(); j++) {
if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
- ERR_CONTINUE(!li);
+ RID light_instance = p_render_data->sdfgi_update_data->directional_lights->get(j);
+ ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
- if (RSG::light_storage->light_directional_get_sky_mode(li->light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
+ RID light = light_storage->light_instance_get_base_light(light_instance);
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
+
+ if (RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
continue;
}
- Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+ Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
dir.y *= y_mult;
dir.normalize();
lights[idx].direction[0] = dir.x;
lights[idx].direction[1] = dir.y;
lights[idx].direction[2] = dir.z;
- Color color = RSG::light_storage->light_get_color(li->light);
+ Color color = RSG::light_storage->light_get_color(light);
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
lights[idx].type = RS::LIGHT_DIRECTIONAL;
- lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- if (p_scene_render->is_using_physical_light_units()) {
- lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+ lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
}
if (p_render_data->camera_attributes.is_valid()) {
lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
}
- lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
+ lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
idx++;
}
@@ -1923,45 +1927,49 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size;
cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size;
- for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) {
+ for (uint32_t j = 0; j < p_render_data->sdfgi_update_data->positional_light_count; j++) {
if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
- ERR_CONTINUE(!li);
+ RID light_instance = p_render_data->sdfgi_update_data->positional_light_instances[j];
+ ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
+
+ RID light = light_storage->light_instance_get_base_light(light_instance);
+ AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance);
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
- uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light);
+ uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light);
if (i > max_sdfgi_cascade) {
continue;
}
- if (!cascade_aabb.intersects(li->aabb)) {
+ if (!cascade_aabb.intersects(light_aabb)) {
continue;
}
- Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+ Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
//faster to not do this here
//dir.y *= y_mult;
//dir.normalize();
lights[idx].direction[0] = dir.x;
lights[idx].direction[1] = dir.y;
lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
+ Vector3 pos = light_transform.origin;
pos.y *= y_mult;
lights[idx].position[0] = pos.x;
lights[idx].position[1] = pos.y;
lights[idx].position[2] = pos.z;
- Color color = RSG::light_storage->light_get_color(li->light);
+ Color color = RSG::light_storage->light_get_color(light);
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
- lights[idx].type = RSG::light_storage->light_get_type(li->light);
+ lights[idx].type = RSG::light_storage->light_get_type(light);
- lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- if (p_scene_render->is_using_physical_light_units()) {
- lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+ lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
// Convert from Luminous Power to Luminous Intensity
if (lights[idx].type == RS::LIGHT_OMNI) {
@@ -1977,11 +1985,11 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
}
- lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
- lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+ lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
+ lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
idx++;
}
@@ -1994,7 +2002,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
}
}
-void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization) {
+void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization) {
//print_line("rendering region " + itos(p_region));
ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
AABB bounds;
@@ -2015,7 +2023,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
}
//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size));
- p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization);
+ RendererSceneRenderRD::get_singleton()->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization);
if (cascade_next != cascade) {
RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
@@ -2327,7 +2335,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
img.instantiate();
for (uint32_t i = 0; i < cascade_size; i++) {
Vector<uint8_t> subarr = data.slice(128 * 128 * i, 128 * 128 * (i + 1));
- img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr);
+ img->set_data(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr);
img->save_png("res://cascade_sdf_" + itos(cascade) + "_" + itos(i) + ".png");
}
@@ -2353,9 +2361,11 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
}
}
-void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
+void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) {
ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lights");
update_cascades();
@@ -2381,21 +2391,25 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
break;
}
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_positional_light_cull_result[i][j]);
- ERR_CONTINUE(!li);
+ RID light_instance = p_positional_light_cull_result[i][j];
+ ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
- uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light);
+ RID light = light_storage->light_instance_get_base_light(light_instance);
+ AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance);
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
+
+ uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light);
if (p_cascade_indices[i] > max_sdfgi_cascade) {
continue;
}
- if (!cascade_aabb.intersects(li->aabb)) {
+ if (!cascade_aabb.intersects(light_aabb)) {
continue;
}
- lights[idx].type = RSG::light_storage->light_get_type(li->light);
+ lights[idx].type = RSG::light_storage->light_get_type(light);
- Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+ Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
dir.y *= y_mult; //only makes sense for directional
dir.normalize();
@@ -2403,20 +2417,20 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
lights[idx].direction[0] = dir.x;
lights[idx].direction[1] = dir.y;
lights[idx].direction[2] = dir.z;
- Vector3 pos = li->transform.origin;
+ Vector3 pos = light_transform.origin;
pos.y *= y_mult;
lights[idx].position[0] = pos.x;
lights[idx].position[1] = pos.y;
lights[idx].position[2] = pos.z;
- Color color = RSG::light_storage->light_get_color(li->light);
+ Color color = RSG::light_storage->light_get_color(light);
color = color.srgb_to_linear();
lights[idx].color[0] = color.r;
lights[idx].color[1] = color.g;
lights[idx].color[2] = color.b;
- lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- if (p_scene_render->is_using_physical_light_units()) {
- lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+ lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+ lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
// Convert from Luminous Power to Luminous Intensity
if (lights[idx].type == RS::LIGHT_OMNI) {
@@ -2432,11 +2446,11 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
}
- lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
- lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
- lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
- lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+ lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
+ lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+ lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE);
+ lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
idx++;
}
@@ -2492,7 +2506,8 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
////////////////////////////////////////////////////////////////////////////////
// VoxelGIInstance
-void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
uint32_t data_version = gi->voxel_gi_get_data_version(probe);
@@ -2834,7 +2849,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
last_probe_data_version = data_version;
p_update_light_instances = true; //just in case
- p_scene_render->_base_uniforms_changed();
+ RendererSceneRenderRD::get_singleton()->base_uniforms_changed();
}
// UDPDATE TIME
@@ -2851,13 +2866,14 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
{
Transform3D to_cell = gi->voxel_gi_get_to_cell_xform(probe);
- Transform3D to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse();
+ Transform3D to_probe_xform = to_cell * transform.affine_inverse();
+
//update lights
for (uint32_t i = 0; i < light_count; i++) {
VoxelGILight &l = gi->voxel_gi_lights[i];
RID light_instance = p_light_instances[i];
- RID light = p_scene_render->light_instance_get_base_light(light_instance);
+ RID light = light_storage->light_instance_get_base_light(light_instance);
l.type = RSG::light_storage->light_get_type(light);
if (l.type == RS::LIGHT_DIRECTIONAL && RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
@@ -2868,7 +2884,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
l.attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
l.energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
- if (p_scene_render->is_using_physical_light_units()) {
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
l.energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
l.energy *= gi->voxel_gi_get_baked_exposure_normalization(probe);
@@ -2892,7 +2908,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
l.cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
l.inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
- Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance);
+ Transform3D xform = light_storage->light_instance_get_base_transform(light_instance);
Vector3 pos = to_probe_xform.xform(xform.origin);
Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_column(2)).normalized();
@@ -3087,17 +3103,17 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
Projection cm;
cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
- if (p_scene_render->cull_argument.size() == 0) {
- p_scene_render->cull_argument.push_back(nullptr);
+ if (RendererSceneRenderRD::get_singleton()->cull_argument.size() == 0) {
+ RendererSceneRenderRD::get_singleton()->cull_argument.push_back(nullptr);
}
- p_scene_render->cull_argument[0] = instance;
+ RendererSceneRenderRD::get_singleton()->cull_argument[0] = instance;
float exposure_normalization = 1.0;
- if (p_scene_render->is_using_physical_light_units()) {
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
exposure_normalization = gi->voxel_gi_get_baked_exposure_normalization(probe);
}
- p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization);
+ RendererSceneRenderRD::get_singleton()->_render_material(to_world_xform * xform, cm, true, RendererSceneRenderRD::get_singleton()->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization);
VoxelGIDynamicPushConstant push_constant;
memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant));
@@ -3270,7 +3286,7 @@ void GI::VoxelGIInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, c
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- push_constant.projection[i * 4 + j] = cam_transform.matrix[i][j];
+ push_constant.projection[i * 4 + j] = cam_transform.columns[i][j];
}
}
@@ -3591,7 +3607,7 @@ Ref<GI::SDFGI> GI::create_sdfgi(RID p_env, const Vector3 &p_world_position, uint
return sdfgi;
}
-void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used) {
ERR_FAIL_COND(p_render_buffers.is_null());
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -3805,10 +3821,10 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
push_constant.z_far = p_projections[0].get_z_far();
// these are only used if we have 1 view, else we use the projections in our scene data
- push_constant.proj_info[0] = -2.0f / (internal_size.x * p_projections[0].matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (internal_size.y * p_projections[0].matrix[1][1]);
- push_constant.proj_info[2] = (1.0f - p_projections[0].matrix[0][2]) / p_projections[0].matrix[0][0];
- push_constant.proj_info[3] = (1.0f + p_projections[0].matrix[1][2]) / p_projections[0].matrix[1][1];
+ push_constant.proj_info[0] = -2.0f / (internal_size.x * p_projections[0].columns[0][0]);
+ push_constant.proj_info[1] = -2.0f / (internal_size.y * p_projections[0].columns[1][1]);
+ push_constant.proj_info[2] = (1.0f - p_projections[0].columns[0][2]) / p_projections[0].columns[0][0];
+ push_constant.proj_info[3] = (1.0f + p_projections[0].columns[1][2]) / p_projections[0].columns[1][1];
bool use_sdfgi = p_render_buffers->has_custom_data(RB_SCOPE_SDFGI);
bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0;
@@ -4051,11 +4067,11 @@ bool GI::voxel_gi_needs_update(RID p_probe) const {
return voxel_gi->last_probe_version != voxel_gi_get_version(voxel_gi->probe);
}
-void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
ERR_FAIL_COND(!voxel_gi);
- voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+ voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects);
}
void GI::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index e567c67a3b..2182ca6a20 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -145,7 +145,7 @@ public:
Transform3D transform;
- void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects);
void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
void free_resources();
};
@@ -687,9 +687,9 @@ public:
void debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views);
void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
- void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
- void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization);
- void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
+ void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data);
+ void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization);
+ void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result);
};
RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
@@ -812,13 +812,13 @@ public:
Ref<SDFGI> create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
- void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
+ void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used);
void process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances);
RID voxel_gi_instance_create(RID p_base);
void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
bool voxel_gi_needs_update(RID p_probe) const;
- void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+ void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects);
void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
};
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 307af99e91..6940276040 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -268,7 +268,7 @@ bool SkyRD::SkyMaterialData::update_parameters(const HashMap<StringName, Variant
uniform_set_updated = true;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL, true);
}
SkyRD::SkyMaterialData::~SkyMaterialData() {
@@ -300,10 +300,10 @@ void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineC
for (uint32_t v = 0; v < p_view_count; v++) {
// We only need key components of our projection matrix
- sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0];
- sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0];
- sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1];
- sky_push_constant.projections[v][3] = p_projections[v].matrix[1][1];
+ sky_push_constant.projections[v][0] = p_projections[v].columns[2][0];
+ sky_push_constant.projections[v][1] = p_projections[v].columns[0][0];
+ sky_push_constant.projections[v][2] = p_projections[v].columns[2][1];
+ sky_push_constant.projections[v][3] = p_projections[v].columns[1][1];
}
sky_push_constant.position[0] = p_position.x;
sky_push_constant.position[1] = p_position.y;
@@ -772,9 +772,7 @@ Ref<Image> SkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, con
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(rad_tex, 0);
RD::get_singleton()->free(rad_tex);
- Ref<Image> img;
- img.instantiate();
- img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
+ Ref<Image> img = Image::create_from_data(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data);
for (int i = 0; i < p_size.width; i++) {
for (int j = 0; j < p_size.height; j++) {
Color c = img->get_pixel(i, j);
@@ -1200,18 +1198,17 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
// This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
// after the depth prepass, but this runs before the depth prepass
for (int i = 0; i < (int)p_lights.size(); i++) {
- RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]);
- if (!li) {
+ if (!light_storage->owns_light_instance(p_lights[i])) {
continue;
}
- RID base = li->light;
+ RID base = light_storage->light_instance_get_base_light(p_lights[i]);
ERR_CONTINUE(base.is_null());
RS::LightType type = light_storage->light_get_type(base);
if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count];
- Transform3D light_transform = li->transform;
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]);
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
sky_light_data.direction[0] = world_direction.x;
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 3a9c695653..ceed287184 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -110,9 +110,29 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::free_data() {
render_buffers->clear_context(RB_SCOPE_FORWARD_CLUSTERED);
}
+ if (cluster_builder) {
+ memdelete(cluster_builder);
+ cluster_builder = nullptr;
+ }
+
if (!render_sdfgi_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_sdfgi_uniform_set)) {
RD::get_singleton()->free(render_sdfgi_uniform_set);
}
+
+ if (ss_effects_data.linear_depth.is_valid()) {
+ RD::get_singleton()->free(ss_effects_data.linear_depth);
+ ss_effects_data.linear_depth = RID();
+ ss_effects_data.linear_depth_slices.clear();
+ }
+
+ if (ss_effects_data.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects_data.downsample_uniform_set)) {
+ RD::get_singleton()->free(ss_effects_data.downsample_uniform_set);
+ ss_effects_data.downsample_uniform_set = RID();
+ }
+
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssao_free(ss_effects_data.ssao);
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssil_free(ss_effects_data.ssil);
+ RenderForwardClustered::get_singleton()->get_ss_effects()->ssr_free(ss_effects_data.ssr);
}
void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderSceneBuffersRD *p_render_buffers) {
@@ -146,6 +166,14 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RenderS
p_render_buffers->create_texture(RB_SCOPE_FORWARD_CLUSTERED, RB_TEX_DEPTH_MSAA, format, usage_bits, texture_samples);
}
+
+ if (cluster_builder == nullptr) {
+ cluster_builder = memnew(ClusterBuilderRD);
+ }
+ cluster_builder->set_shared(RenderForwardClustered::get_singleton()->get_cluster_builder_shared());
+
+ RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ cluster_builder->setup(p_render_buffers->get_internal_size(), p_render_buffers->get_max_cluster_elements(), p_render_buffers->get_depth_texture(), sampler, p_render_buffers->get_internal_texture());
}
RID RenderForwardClustered::RenderBufferDataForwardClustered::get_color_only_fb() {
@@ -580,9 +608,11 @@ 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) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
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();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? light_storage->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()) {
@@ -724,7 +754,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
- if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && repeats < RenderElementInfo::MAX_REPEATS) {
+ if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && inst->mirror == prev_surface->owner->mirror && repeats < RenderElementInfo::MAX_REPEATS) {
//this element is the same as the previous one, count repeats to draw it using instancing
repeats++;
} else {
@@ -910,12 +940,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
// LOD
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->scene_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
+ // Get the LOD support points on the mesh AABB.
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
- 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);
+ // Get the distances to those points on the AABB from the camera origin.
+ float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min);
+ float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max);
float distance = 0.0;
@@ -932,8 +963,8 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
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->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
+ uint32_t indices = 0;
+ 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
@@ -1030,26 +1061,28 @@ void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis)
}
void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
if (i >= (int)scene_state.max_lightmaps) {
break;
}
- RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+ RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
- Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+ Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
scene_state.lightmaps[i].exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
- float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+ float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
}
scene_state.lightmap_ids[i] = p_lightmaps[i];
- scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
+ scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap);
scene_state.lightmaps_used++;
}
@@ -1058,7 +1091,451 @@ void RenderForwardClustered::_setup_lightmaps(const RenderDataRD *p_render_data,
}
}
+/* SDFGI */
+
+void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) {
+ Ref<RenderSceneBuffersRD> rb;
+ if (p_render_data && p_render_data->render_buffers.is_valid()) {
+ rb = p_render_data->render_buffers;
+ }
+
+ 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;
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+ for (int i = 0; i < p_render_data->render_sdfgi_region_count; i++) {
+ sdfgi->render_region(rb, p_render_data->render_sdfgi_regions[i].region, p_render_data->render_sdfgi_regions[i].instances, exposure_normalization);
+ }
+ if (p_render_data->sdfgi_update_data->update_static) {
+ sdfgi->render_static_lights(p_render_data, rb, p_render_data->sdfgi_update_data->static_cascade_count, p_render_data->sdfgi_update_data->static_cascade_indices, p_render_data->sdfgi_update_data->static_positional_lights);
+ }
+ }
+}
+
+/* Debug */
+
+void RenderForwardClustered::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
+ RS::ViewportDebugDraw dd = get_debug_draw_mode();
+
+ if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
+ ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
+ switch (dd) {
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL;
+ break;
+ case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES:
+ elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE;
+ break;
+ default: {
+ }
+ }
+ current_cluster_builder->debug(elem_type);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FOG SHADER
+
+void RenderForwardClustered::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+
+ ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI));
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
+
+ Ref<RendererRD::GI::SDFGI> sdfgi;
+ if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
+ sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
+ }
+
+ Size2i size = p_render_buffers->get_internal_size();
+ float ratio = float(size.x) / float((size.x + size.y) / 2);
+ uint32_t target_width = uint32_t(float(get_volumetric_fog_size()) * ratio);
+ uint32_t target_height = uint32_t(float(get_volumetric_fog_size()) / ratio);
+
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+ //validate
+ if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != get_volumetric_fog_depth()) {
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>());
+ }
+ }
+
+ if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment)) {
+ //no reason to enable or update, bye
+ return;
+ }
+
+ if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ //required volumetric fog but not existing, create
+ Ref<RendererRD::Fog::VolumetricFog> fog;
+
+ fog.instantiate();
+ fog->init(Vector3i(target_width, target_height, get_volumetric_fog_depth()), sky.sky_shader.default_shader_rd);
+
+ p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog);
+ }
+
+ if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
+
+ RendererRD::Fog::VolumetricFogSettings settings;
+ settings.rb_size = size;
+ settings.time = time;
+ settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array();
+ settings.max_cluster_elements = RendererRD::LightStorage::get_singleton()->get_max_cluster_elements();
+ settings.volumetric_fog_filter_active = get_volumetric_fog_filter_active();
+
+ settings.shadow_sampler = shadow_sampler;
+ settings.shadow_atlas_depth = RendererRD::LightStorage::get_singleton()->owns_shadow_atlas(p_shadow_atlas) ? RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas) : RID();
+ settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer();
+ settings.omni_light_buffer = RendererRD::LightStorage::get_singleton()->get_omni_light_buffer();
+ settings.spot_light_buffer = RendererRD::LightStorage::get_singleton()->get_spot_light_buffer();
+ settings.directional_shadow_depth = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture();
+ settings.directional_light_buffer = RendererRD::LightStorage::get_singleton()->get_directional_light_buffer();
+
+ settings.vfog = fog;
+ settings.cluster_builder = rb_data->cluster_builder;
+ settings.rbgi = rbgi;
+ settings.sdfgi = sdfgi;
+ settings.env = p_environment;
+ settings.sky = &sky;
+ settings.gi = &gi;
+
+ RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes);
+ }
+}
+
+/* Lighting */
+
+void RenderForwardClustered::setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, p_transform, p_half_extents);
+ }
+}
+
+void RenderForwardClustered::setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_light(p_type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, p_transform, p_radius, p_spot_aperture);
+ }
+}
+
+void RenderForwardClustered::setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) {
+ if (current_cluster_builder != nullptr) {
+ current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, p_transform, p_half_extents);
+ }
+}
+
+/* Render scene */
+
+void RenderForwardClustered::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+ ERR_FAIL_COND(p_environment.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ RENDER_TIMESTAMP("Process SSAO");
+
+ RendererRD::SSEffects::SSAOSettings settings;
+ settings.radius = environment_get_ssao_radius(p_environment);
+ settings.intensity = environment_get_ssao_intensity(p_environment);
+ settings.power = environment_get_ssao_power(p_environment);
+ settings.detail = environment_get_ssao_detail(p_environment);
+ settings.horizon = environment_get_ssao_horizon(p_environment);
+ settings.sharpness = environment_get_ssao_sharpness(p_environment);
+ settings.full_screen_size = p_render_buffers->get_internal_size();
+
+ ss_effects->ssao_allocate_buffers(rb_data->ss_effects_data.ssao, settings, rb_data->ss_effects_data.linear_depth);
+ ss_effects->generate_ssao(rb_data->ss_effects_data.ssao, p_normal_buffer, p_projection, settings);
+}
+
+void RenderForwardClustered::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+ ERR_FAIL_COND(p_environment.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ RENDER_TIMESTAMP("Process SSIL");
+
+ RendererRD::SSEffects::SSILSettings settings;
+ settings.radius = environment_get_ssil_radius(p_environment);
+ settings.intensity = environment_get_ssil_intensity(p_environment);
+ settings.sharpness = environment_get_ssil_sharpness(p_environment);
+ settings.normal_rejection = environment_get_ssil_normal_rejection(p_environment);
+ settings.full_screen_size = p_render_buffers->get_internal_size();
+
+ Projection correction;
+ correction.set_depth_correction(true);
+ Projection projection = correction * p_projection;
+ Transform3D transform = p_transform;
+ transform.set_origin(Vector3(0.0, 0.0, 0.0));
+ Projection last_frame_projection = rb_data->ss_effects_data.last_frame_projection * Projection(rb_data->ss_effects_data.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
+
+ ss_effects->ssil_allocate_buffers(rb_data->ss_effects_data.ssil, settings, rb_data->ss_effects_data.linear_depth);
+ ss_effects->screen_space_indirect_lighting(rb_data->ss_effects_data.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
+ rb_data->ss_effects_data.last_frame_projection = projection;
+ rb_data->ss_effects_data.last_frame_transform = transform;
+}
+
+void RenderForwardClustered::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ if (rb_data->ss_effects_data.ssil.last_frame.is_valid()) {
+ Size2i size = p_render_buffers->get_internal_size();
+ RID texture = p_render_buffers->get_internal_texture();
+ copy_effects->copy_to_rect(texture, rb_data->ss_effects_data.ssil.last_frame, Rect2i(0, 0, size.x, size.y));
+
+ int width = size.x;
+ int height = size.y;
+ for (int i = 0; i < rb_data->ss_effects_data.ssil.last_frame_slices.size() - 1; i++) {
+ width = MAX(1, width >> 1);
+ height = MAX(1, height >> 1);
+ copy_effects->make_mipmap(rb_data->ss_effects_data.ssil.last_frame_slices[i], rb_data->ss_effects_data.ssil.last_frame_slices[i + 1], Size2i(width, height));
+ }
+ }
+}
+
+void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
+ // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+
+ Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
+ Ref<RenderBufferDataForwardClustered> rb_data;
+ if (rb.is_valid()) {
+ rb_data = rb->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ }
+
+ if (rb.is_valid() && p_use_gi && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ sdfgi->store_probes();
+ }
+
+ p_render_data->cube_shadows.clear();
+ p_render_data->shadows.clear();
+ p_render_data->directional_shadows.clear();
+
+ 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 < p_render_data->render_shadow_count; i++) {
+ RID li = p_render_data->render_shadows[i].light;
+ RID base = light_storage->light_instance_get_base_light(li);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ p_render_data->directional_shadows.push_back(i);
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ p_render_data->cube_shadows.push_back(i);
+ } else {
+ p_render_data->shadows.push_back(i);
+ }
+ }
+
+ //cube shadows are rendered in their own way
+ for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+ }
+
+ if (p_render_data->directional_shadows.size()) {
+ //open the pass for directional shadows
+ light_storage->update_directional_shadow_atlas();
+ RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ // Render GI
+
+ bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size();
+ bool render_gi = rb.is_valid() && p_use_gi;
+
+ if (render_shadows && render_gi) {
+ RENDER_TIMESTAMP("Render GI + Render Shadows (Parallel)");
+ } else if (render_shadows) {
+ RENDER_TIMESTAMP("Render Shadows");
+ } else if (render_gi) {
+ RENDER_TIMESTAMP("Render GI");
+ }
+
+ //prepare shadow rendering
+ if (render_shadows) {
+ _render_shadow_begin();
+
+ //render directional shadows
+ for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info);
+ }
+ //render positional shadows
+ for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info);
+ }
+
+ _render_shadow_process();
+ }
+
+ //start GI
+ if (render_gi) {
+ gi.process_gi(rb, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
+ }
+
+ //Do shadow rendering (in parallel with GI)
+ if (render_shadows) {
+ _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
+ }
+
+ if (render_gi) {
+ RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
+ }
+
+ if (rb_data.is_valid() && ss_effects) {
+ if (p_use_ssao || p_use_ssil) {
+ Size2i size = rb->get_internal_size();
+
+ bool invalidate_uniform_set = false;
+ if (rb_data->ss_effects_data.linear_depth.is_null()) {
+ RD::TextureFormat tf;
+ tf.format = RD::DATA_FORMAT_R16_SFLOAT;
+ tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+ tf.width = (size.x + 1) / 2;
+ tf.height = (size.y + 1) / 2;
+ tf.mipmaps = 5;
+ tf.array_layers = 4;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ rb_data->ss_effects_data.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ RD::get_singleton()->set_resource_name(rb_data->ss_effects_data.linear_depth, "SS Effects Depth");
+ for (uint32_t i = 0; i < tf.mipmaps; i++) {
+ RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb_data->ss_effects_data.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY);
+ rb_data->ss_effects_data.linear_depth_slices.push_back(slice);
+ RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " ");
+ }
+ invalidate_uniform_set = true;
+ }
+
+ RID depth_texture = rb->get_depth_texture();
+ ss_effects->downsample_depth(depth_texture, rb_data->ss_effects_data.linear_depth_slices, invalidate_uniform_set, size, p_render_data->scene_data->cam_projection);
+ }
+
+ if (p_use_ssao) {
+ // TODO make these proper stereo
+ _process_ssao(rb, 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(rb, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform);
+ }
+ }
+
+ //full barrier here, we need raster, transfer and compute and it depends from the previous work
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
+
+ if (current_cluster_builder) {
+ 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;
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ using_shadows = false;
+ }
+ } else {
+ //do not render reflections when rendering a reflection probe
+ light_storage->update_reflection_probe_buffer(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;
+ light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+
+ p_render_data->directional_light_count = directional_light_count;
+
+ if (current_cluster_builder) {
+ current_cluster_builder->bake_cluster();
+ }
+
+ if (rb.is_valid()) {
+ bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count);
+ _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes);
+ }
+}
+
+void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
+ ERR_FAIL_NULL(ss_effects);
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
+ uint32_t view_count = p_render_buffers->get_view_count();
+
+ if (!can_use_effects) {
+ //just copy
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count);
+ return;
+ }
+
+ ERR_FAIL_COND(p_environment.is_null());
+ ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
+
+ Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2);
+ ss_effects->ssr_allocate_buffers(rb_data->ss_effects_data.ssr, _render_buffers_get_color_format(), half_size, view_count);
+
+ RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+ RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+ for (uint32_t v = 0; v < view_count; v++) {
+ texture_slices[v] = p_render_buffers->get_internal_texture(v);
+ depth_slices[v] = p_render_buffers->get_depth_texture(v);
+ }
+ ss_effects->screen_space_reflection(rb_data->ss_effects_data.ssr, texture_slices, p_normal_slices, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
+ copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), rb_data->ss_effects_data.ssr.output, view_count);
+}
+
+void RenderForwardClustered::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) {
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Size2i internal_size = p_render_buffers->get_internal_size();
+ bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
+
+ if (!can_use_effects) {
+ //just copy
+ return;
+ }
+
+ p_render_buffers->allocate_blur_textures();
+
+ for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
+ RID internal_texture = p_render_buffers->get_internal_texture(v);
+ RID depth_texture = p_render_buffers->get_depth_texture(v);
+ ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size);
+ }
+}
+
void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
Ref<RenderSceneBuffersRD> rb;
Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
@@ -1070,6 +1547,54 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
//first of all, make a new render pass
//fill up ubo
+ RENDER_TIMESTAMP("Prepare 3D Scene");
+
+ // sdfgi first
+ _update_sdfgi(p_render_data);
+
+ // assign render indices to voxel_gi_instances
+ for (uint32_t i = 0; i < (uint32_t)p_render_data->voxel_gi_instances->size(); i++) {
+ RID voxel_gi_instance = (*p_render_data->voxel_gi_instances)[i];
+ gi.voxel_gi_instance_set_render_index(voxel_gi_instance, i);
+ }
+
+ // obtain cluster builder
+ if (rb_data.is_valid()) {
+ current_cluster_builder = rb_data->cluster_builder;
+ } else if (light_storage->owns_reflection_probe_instance(p_render_data->reflection_probe)) {
+ current_cluster_builder = light_storage->reflection_probe_instance_get_cluster_builder(p_render_data->reflection_probe, &cluster_builder_shared);
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ light_storage->reflection_probe_set_baked_exposure(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe), RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes));
+ }
+ } else {
+ ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
+ current_cluster_builder = nullptr;
+ }
+
+ p_render_data->voxel_gi_count = 0;
+
+ if (rb.is_valid()) {
+ if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ if (sdfgi.is_valid()) {
+ sdfgi->update_cascades();
+ sdfgi->pre_process_gi(p_render_data->scene_data->cam_transform, p_render_data);
+ sdfgi->update_light();
+ }
+ }
+
+ gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count);
+ }
+
+ if (current_cluster_builder != nullptr) {
+ p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer();
+ p_render_data->cluster_size = current_cluster_builder->get_cluster_size();
+ p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
+ }
+
+ _update_vrs(rb);
+
RENDER_TIMESTAMP("Setup 3D Scene");
// check if we need motion vectors
@@ -1153,15 +1678,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
color_only_framebuffer = rb_data->get_color_only_fb();
} else if (p_render_data->reflection_probe.is_valid()) {
- uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
- color_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
color_only_framebuffer = color_framebuffer;
- depth_framebuffer = reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
}
@@ -1188,7 +1713,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
- bool using_sss = rb_data.is_valid() && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
+ bool using_sss = rb_data.is_valid() && scene_state.used_sss && ss_effects->sss_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED;
if (using_sss && !using_separate_specular) {
using_separate_specular = true;
@@ -1306,7 +1831,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->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);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1376,7 +1901,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->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);
+ 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_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
@@ -1497,7 +2022,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->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);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1538,6 +2063,229 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_render_buffers_post_process_and_tonemap(p_render_data);
}
+
+ if (rb.is_valid()) {
+ _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ Vector<RID> view_rids;
+
+ // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled.
+ Size2i size = rb->get_internal_size();
+ RID source_texture = rb->get_internal_texture();
+ for (uint32_t v = 0; v < rb->get_view_count(); v++) {
+ view_rids.push_back(rb->get_internal_texture(v));
+ }
+
+ sdfgi->debug_draw(p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
+ }
+ }
+}
+
+void RenderForwardClustered::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ ERR_FAIL_COND(p_render_buffers.is_null());
+
+ Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
+ ERR_FAIL_COND(rb_data.is_null());
+
+ RendererSceneRenderRD::_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occlusion_buffer);
+
+ RID render_target = p_render_buffers->get_render_target();
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSAO && rb_data->ss_effects_data.ssao.ao_final.is_valid()) {
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true);
+ }
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SSIL && rb_data->ss_effects_data.ssil.ssil_final.is_valid()) {
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
+ copy_effects->copy_to_fb_rect(rb_data->ss_effects_data.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ }
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
+ RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT);
+ RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION);
+ copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1);
+ }
+}
+
+void RenderForwardClustered::_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) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+ ERR_FAIL_COND(!light_storage->owns_light_instance(p_light));
+
+ RID base = light_storage->light_instance_get_base_light(p_light);
+
+ Rect2i atlas_rect;
+ uint32_t atlas_size = 1;
+ RID atlas_fb;
+
+ bool using_dual_paraboloid = false;
+ bool using_dual_paraboloid_flip = false;
+ Vector2i dual_paraboloid_offset;
+ RID render_fb;
+ RID render_texture;
+ float zfar;
+
+ bool use_pancake = false;
+ bool render_cubemap = false;
+ bool finalize_cubemap = false;
+
+ bool flip_y = false;
+
+ Projection light_projection;
+ Transform3D light_transform;
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ //set pssm stuff
+ uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light);
+ if (last_scene_shadow_pass != get_scene_pass()) {
+ light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect());
+ light_storage->directional_shadow_increase_current_light();
+ light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass());
+ }
+
+ use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+
+ atlas_rect = light_storage->light_instance_get_directional_rect(p_light);
+
+ if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ atlas_rect.size.width /= 2;
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 1) {
+ atlas_rect.position.x += atlas_rect.size.width;
+ } else if (p_pass == 2) {
+ atlas_rect.position.y += atlas_rect.size.height;
+ } else if (p_pass == 3) {
+ atlas_rect.position += atlas_rect.size;
+ }
+ } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 0) {
+ } else {
+ atlas_rect.position.y += atlas_rect.size.height;
+ }
+ }
+
+ float directional_shadow_size = light_storage->directional_shadow_get_size();
+ Rect2 atlas_rect_norm = atlas_rect;
+ atlas_rect_norm.position /= directional_shadow_size;
+ atlas_rect_norm.size /= directional_shadow_size;
+ light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm);
+
+ zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ render_fb = light_storage->direction_shadow_get_fb();
+ render_texture = RID();
+ flip_y = true;
+
+ } else {
+ //set from shadow atlas
+
+ ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas));
+ ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light));
+
+ RSG::light_storage->shadow_atlas_update(p_shadow_atlas);
+
+ uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light);
+
+ uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK;
+ uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant);
+
+ ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant));
+
+ uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
+ uint32_t quadrant_size = shadow_atlas_size >> 1;
+
+ atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+ atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / subdivision);
+ atlas_rect.position.x += (shadow % subdivision) * shadow_size;
+ atlas_rect.position.y += (shadow / subdivision) * shadow_size;
+
+ atlas_rect.size.width = shadow_size;
+ atlas_rect.size.height = shadow_size;
+
+ zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) {
+ bool wrap = (shadow + 1) % subdivision == 0;
+ dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0);
+
+ if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ render_texture = light_storage->get_cubemap(shadow_size / 2);
+ render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass);
+
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+ render_cubemap = true;
+ finalize_cubemap = p_pass == 5;
+ atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ atlas_size = shadow_atlas_size;
+
+ if (p_pass == 0) {
+ _render_shadow_begin();
+ }
+
+ } else {
+ atlas_rect.position.x += 1;
+ atlas_rect.position.y += 1;
+ atlas_rect.size.x -= 2;
+ atlas_rect.size.y -= 2;
+
+ atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ using_dual_paraboloid = true;
+ using_dual_paraboloid_flip = p_pass == 1;
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+ flip_y = true;
+ }
+
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) {
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ flip_y = true;
+ }
+ }
+
+ if (render_cubemap) {
+ //rendering to cubemap
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
+ if (finalize_cubemap) {
+ _render_shadow_process();
+ _render_shadow_end();
+ //reblit
+ Rect2 atlas_rect_norm = atlas_rect;
+ atlas_rect_norm.position /= float(atlas_size);
+ atlas_rect_norm.size /= float(atlas_size);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+
+ //restore transform so it can be properly used
+ light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
+ }
+
+ } else {
+ //render shadow
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
+ }
}
void RenderForwardClustered::_render_shadow_begin() {
@@ -1560,7 +2308,6 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
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;
@@ -1631,7 +2378,7 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -1894,7 +2641,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardClustered::_base_uniforms_changed() {
+void RenderForwardClustered::base_uniforms_changed() {
if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -2010,14 +2757,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_omni_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_spot_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
uniforms.push_back(u);
}
@@ -2025,14 +2772,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_reflection_probe_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.append_id(get_directional_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
uniforms.push_back(u);
}
{
@@ -2069,7 +2816,7 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_decal_buffer());
+ u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
uniforms.push_back(u);
}
@@ -2147,7 +2894,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
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();
+ RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? light_storage->reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -2164,7 +2911,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
- texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
+ texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_render_data->shadow_atlas);
}
if (!texture.is_valid()) {
texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
@@ -2176,8 +2923,8 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
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());
+ if (p_use_directional_shadow_atlas && RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) {
+ u.append_id(RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture());
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
}
@@ -2191,7 +2938,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
if (p_render_data && i < p_render_data->lightmaps->size()) {
- RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
+ RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
RID texture = light_storage->lightmap_get_texture(base);
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
u.append_id(rd_texture);
@@ -2267,7 +3014,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
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 aot = rb_data.is_valid() ? rb_data->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);
@@ -2353,7 +3100,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
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 ssil = rb_data.is_valid() ? rb_data->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);
@@ -2512,6 +3259,26 @@ RID RenderForwardClustered::_render_buffers_get_velocity_texture(Ref<RenderScene
return p_render_buffers->get_velocity_buffer(p_render_buffers->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED);
}
+void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ss_effects->ssao_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to);
+}
+
+void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+ ss_effects->ssil_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to);
+}
+
+void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
+ ss_effects->ssr_set_roughness_quality(p_quality);
+}
+
+void RenderForwardClustered::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
+ ss_effects->sss_set_quality(p_quality);
+}
+
+void RenderForwardClustered::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
+ ss_effects->sss_set_scale(p_scale, p_depth_scale);
+}
+
RenderForwardClustered *RenderForwardClustered::singleton = nullptr;
void RenderForwardClustered::GeometryInstanceForwardClustered::_mark_dirty() {
@@ -2831,7 +3598,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->store_transform_cache = store_transform;
ginstance->can_sdfgi = false;
- if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) {
+ if (!RendererRD::LightStorage::get_singleton()->lightmap_instance_is_valid(ginstance->lightmap_instance)) {
if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) {
ginstance->can_sdfgi = true;
}
@@ -3013,7 +3780,7 @@ void RenderForwardClustered::_update_shader_quality_settings() {
scene_shader.set_default_specialization_constants(spec_constants);
- _base_uniforms_changed(); //also need this
+ base_uniforms_changed(); //also need this
}
RenderForwardClustered::RenderForwardClustered() {
@@ -3056,15 +3823,31 @@ RenderForwardClustered::RenderForwardClustered() {
scene_shader.init(defines);
}
+ /* shadow sampler */
+ {
+ RD::SamplerState sampler;
+ sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler.enable_compare = true;
+ sampler.compare_op = RD::COMPARE_OP_LESS;
+ shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ }
+
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
_update_shader_quality_settings();
resolve_effects = memnew(RendererRD::Resolve());
taa = memnew(RendererRD::TAA);
+ ss_effects = memnew(RendererRD::SSEffects);
}
RenderForwardClustered::~RenderForwardClustered() {
+ if (ss_effects != nullptr) {
+ memdelete(ss_effects);
+ ss_effects = nullptr;
+ }
+
if (taa != nullptr) {
memdelete(taa);
taa = nullptr;
@@ -3075,7 +3858,8 @@ RenderForwardClustered::~RenderForwardClustered() {
resolve_effects = nullptr;
}
- directional_shadow_atlas_set_size(0);
+ RD::get_singleton()->free(shadow_sampler);
+ RSG::light_storage->directional_shadow_atlas_set_size(0);
{
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); 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 1e70f6880c..670eb93e20 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -32,7 +32,9 @@
#define RENDER_FORWARD_CLUSTERED_H
#include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
#include "servers/rendering/renderer_rd/effects/resolve.h"
+#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/taa.h"
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
@@ -99,7 +101,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
public:
- //for rendering, may be MSAAd
+ ClusterBuilderRD *cluster_builder = nullptr;
+
+ struct SSEffectsData {
+ RID linear_depth;
+ Vector<RID> linear_depth_slices;
+
+ RID downsample_uniform_set;
+
+ Projection last_frame_projection;
+ Transform3D last_frame_transform;
+
+ RendererRD::SSEffects::SSAORenderBuffers ssao;
+ RendererRD::SSEffects::SSILRenderBuffers ssil;
+ RendererRD::SSEffects::SSRRenderBuffers ssr;
+ } ss_effects_data;
enum DepthFrameBufferType {
DEPTH_FB,
@@ -139,6 +155,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
RID get_specular_only_fb();
+ RID get_ao_texture() const { return ss_effects_data.ssao.ao_final; }
+ RID get_ssil_texture() const { return ss_effects_data.ssil.ssil_final; }
+
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
virtual void free_data() override;
};
@@ -149,10 +168,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- virtual void _base_uniforms_changed() override;
- virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
- virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
-
bool base_uniform_set_updated = false;
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
@@ -191,7 +206,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID render_pass_uniform_set;
bool force_wireframe = false;
Vector2 uv_offset;
- Plane lod_plane;
float lod_distance_multiplier = 0.0;
float screen_mesh_lod_threshold = 0.0;
RD::FramebufferFormatID framebuffer_format = 0;
@@ -199,7 +213,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
uint32_t barrier = RD::BARRIER_MASK_ALL;
bool use_directional_soft_shadow = false;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_no_gi, bool p_use_directional_soft_shadows, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -211,7 +225,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
render_pass_uniform_set = p_render_pass_uniform_set;
force_wireframe = p_force_wireframe;
uv_offset = p_uv_offset;
- lod_plane = p_lod_plane;
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
@@ -558,16 +571,61 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _update_shader_quality_settings() override;
+ /* Effects */
+
RendererRD::Resolve *resolve_effects = nullptr;
RendererRD::TAA *taa = nullptr;
+ RendererRD::SSEffects *ss_effects = nullptr;
+
+ /* Cluster builder */
+
+ ClusterBuilderSharedDataRD cluster_builder_shared;
+ ClusterBuilderRD *current_cluster_builder = nullptr;
+
+ /* SDFGI */
+ void _update_sdfgi(RenderDataRD *p_render_data);
+
+ /* Volumetric fog */
+ RID shadow_sampler;
+
+ void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
+
+ /* Render shadows */
+
+ 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);
+ void _render_shadow_begin();
+ void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+ void _render_shadow_process();
+ void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+
+ /* Render Scene */
+ void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
+ void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
+ void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
+ void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
+ void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
+ void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
+
+ /* Debug */
+ void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
protected:
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+ /* setup */
+
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+
+ virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
+ virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
+ virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) 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, 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;
+ virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
+
+ /* Rendering */
+
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+ virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) 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, float p_exposure_normalization) override;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
@@ -577,6 +635,15 @@ protected:
public:
static RenderForwardClustered *get_singleton() { return singleton; }
+ ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+ RendererRD::SSEffects *get_ss_effects() { return ss_effects; }
+
+ /* callback from updating our lighting UBOs, used to populate cluster builder */
+ virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+ virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) override;
+ virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+
+ virtual void base_uniforms_changed() override;
_FORCE_INLINE_ virtual void update_uniform_sets() override {
base_uniform_set_updated = true;
_update_render_base_uniform_set();
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 1987577464..c1b23af82f 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -509,7 +509,7 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardClustered::MaterialData::~MaterialData() {
@@ -697,10 +697,10 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
- actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
- actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(read_model_matrix * scene_data.view_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
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 f458063aea..f76d016ae7 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -39,7 +39,7 @@
using namespace RendererSceneRenderImplementation;
-RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(ForwardIDType p_type) {
+RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forward_id(RendererRD::ForwardIDType p_type) {
int32_t index = -1;
for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) {
if (forward_id_allocators[p_type].allocations[i] == false) {
@@ -58,15 +58,66 @@ RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(Forward
return index;
}
-void RenderForwardMobile::_free_forward_id(ForwardIDType p_type, ForwardID p_id) {
- ERR_FAIL_INDEX(p_id, (ForwardID)forward_id_allocators[p_type].allocations.size());
+void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {
+ ERR_FAIL_INDEX(p_id, (RendererRD::ForwardID)forward_id_allocators[p_type].allocations.size());
forward_id_allocators[p_type].allocations[p_id] = false;
}
-void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {
+void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {
forward_id_allocators[p_type].map[p_id] = p_index;
}
+void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
+ // first zero out our indices
+
+ p_push_constant->omni_lights[0] = 0xFFFF;
+ p_push_constant->omni_lights[1] = 0xFFFF;
+
+ p_push_constant->spot_lights[0] = 0xFFFF;
+ p_push_constant->spot_lights[1] = 0xFFFF;
+
+ p_push_constant->decals[0] = 0xFFFF;
+ p_push_constant->decals[1] = 0xFFFF;
+
+ p_push_constant->reflection_probes[0] = 0xFFFF;
+ p_push_constant->reflection_probes[1] = 0xFFFF;
+
+ if (p_instance->omni_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+ }
+ if (p_instance->spot_light_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+ }
+ if (p_instance->reflection_probe_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+ }
+ if (p_instance->decals_count == 0) {
+ spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+ }
+
+ for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
+ uint32_t ofs = i < 4 ? 0 : 1;
+ uint32_t shift = (i & 0x3) << 3;
+ uint32_t mask = ~(0xFF << shift);
+ if (i < p_instance->omni_light_count) {
+ p_push_constant->omni_lights[ofs] &= mask;
+ p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+ }
+ if (i < p_instance->spot_light_count) {
+ p_push_constant->spot_lights[ofs] &= mask;
+ p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+ }
+ if (i < p_instance->decals_count) {
+ p_push_constant->decals[ofs] &= mask;
+ p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+ }
+ if (i < p_instance->reflection_probe_count) {
+ p_push_constant->reflection_probes[ofs] &= mask;
+ p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+ }
+ }
+}
+
/* Render buffer */
void RenderForwardMobile::RenderBufferDataForwardMobile::free_data() {
@@ -300,6 +351,7 @@ bool RenderForwardMobile::_render_buffers_can_be_storage() {
}
RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
//there should always be enough uniform buffers for render passes, otherwise bugs
@@ -340,7 +392,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
}
{
- RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
+ RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? light_storage->reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -358,7 +410,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
- texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
+ texture = light_storage->shadow_atlas_get_texture(p_render_data->shadow_atlas);
}
if (!texture.is_valid()) {
texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
@@ -370,8 +422,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
u.binding = 5;
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());
+ if (p_use_directional_shadow_atlas && light_storage->directional_shadow_get_texture().is_valid()) {
+ u.append_id(light_storage->directional_shadow_get_texture());
} else {
u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
}
@@ -387,8 +439,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
if (p_render_data && i < p_render_data->lightmaps->size()) {
- RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
- RID texture = RendererRD::LightStorage::get_singleton()->lightmap_get_texture(base);
+ RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
+ RID texture = light_storage->lightmap_get_texture(base);
RID rd_texture = texture_storage->texture_get_rd_texture(texture);
u.append_id(rd_texture);
} else {
@@ -467,6 +519,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
}
void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
// This probably needs to change...
scene_state.lightmaps_used = 0;
for (int i = 0; i < (int)p_lightmaps.size(); i++) {
@@ -474,20 +528,20 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
break;
}
- RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+ RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
- Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+ Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
to_lm = to_lm.inverse().transposed(); //will transform normals
RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
scene_state.lightmaps[i].exposure_normalization = 1.0;
if (p_render_data->camera_attributes.is_valid()) {
- float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+ float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
}
scene_state.lightmap_ids[i] = p_lightmaps[i];
- scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
+ scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap);
scene_state.lightmaps_used++;
}
@@ -496,12 +550,103 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
}
}
+void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+
+ p_render_data->cube_shadows.clear();
+ p_render_data->shadows.clear();
+ p_render_data->directional_shadows.clear();
+
+ 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 < p_render_data->render_shadow_count; i++) {
+ RID li = p_render_data->render_shadows[i].light;
+ RID base = light_storage->light_instance_get_base_light(li);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ p_render_data->directional_shadows.push_back(i);
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ p_render_data->cube_shadows.push_back(i);
+ } else {
+ p_render_data->shadows.push_back(i);
+ }
+ }
+
+ //cube shadows are rendered in their own way
+ for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+ }
+
+ if (p_render_data->directional_shadows.size()) {
+ //open the pass for directional shadows
+ light_storage->update_directional_shadow_atlas();
+ RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+ RD::get_singleton()->draw_list_end();
+ }
+ }
+
+ bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size();
+
+ if (render_shadows) {
+ RENDER_TIMESTAMP("Render Shadows");
+ }
+
+ //prepare shadow rendering
+ if (render_shadows) {
+ _render_shadow_begin();
+
+ //render directional shadows
+ for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info);
+ }
+ //render positional shadows
+ for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) {
+ _render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info);
+ }
+
+ _render_shadow_process();
+
+ _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
+ }
+
+ //full barrier here, we need raster, transfer and compute and it depends from the previous work
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
+
+ bool using_shadows = true;
+
+ if (p_render_data->reflection_probe.is_valid()) {
+ if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ using_shadows = false;
+ }
+ } else {
+ //do not render reflections when rendering a reflection probe
+ light_storage->update_reflection_probe_buffer(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;
+ light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+
+ p_render_data->directional_light_count = directional_light_count;
+}
+
void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+ Ref<RenderSceneBuffersRD> rb;
Ref<RenderBufferDataForwardMobile> rb_data;
if (p_render_data->render_buffers.is_valid()) {
- rb_data = p_render_data->render_buffers->get_custom_data(RB_SCOPE_MOBILE);
+ rb = p_render_data->render_buffers;
+ rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
}
+ RENDER_TIMESTAMP("Prepare 3D Scene");
+
+ _update_vrs(rb);
+
RENDER_TIMESTAMP("Setup 3D Scene");
/* TODO
@@ -532,9 +677,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
bool using_subpass_transparent = true;
bool using_subpass_post_process = true;
- bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out
- bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out
-
// fill our render lists early so we can find out if we use various features
_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -559,7 +701,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
using_subpass_post_process = false;
}
- if (using_ssr || using_sss || scene_state.used_screen_texture || scene_state.used_depth_texture) {
+ if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
// can't use our last two subpasses
using_subpass_transparent = false;
using_subpass_post_process = false;
@@ -576,13 +718,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
}
} else if (p_render_data->reflection_probe.is_valid()) {
- uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+ uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
screen_size.x = resolution;
screen_size.y = resolution;
- framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+ framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
- if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+ if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
p_render_data->environment = RID(); //no environment on interiors
}
@@ -713,8 +855,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
}
- RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
- _pre_opaque_render(p_render_data, false, false, false, nullrids, RID());
+ _pre_opaque_render(p_render_data);
uint32_t spec_constant_base_flags = 0;
@@ -758,8 +899,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
- bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture && !using_ssr && !using_sss;
- bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture && !using_ssr && !using_sss;
+ bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture;
+ bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture;
{
// regular forward for now
@@ -775,7 +916,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->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);
+ 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_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
@@ -842,7 +983,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->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);
+ 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_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
@@ -881,7 +1022,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->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);
+ 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_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
@@ -917,10 +1058,190 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (rb_data.is_valid()) {
_disable_clear_request(p_render_data);
}
+
+ if (rb.is_valid()) {
+ _render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+ }
}
/* these are being called from RendererSceneRenderRD::_pre_opaque_render */
+void RenderForwardMobile::_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) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+ ERR_FAIL_COND(!light_storage->owns_light_instance(p_light));
+
+ RID base = light_storage->light_instance_get_base_light(p_light);
+
+ Rect2i atlas_rect;
+ uint32_t atlas_size = 1;
+ RID atlas_fb;
+
+ bool using_dual_paraboloid = false;
+ bool using_dual_paraboloid_flip = false;
+ Vector2i dual_paraboloid_offset;
+ RID render_fb;
+ RID render_texture;
+ float zfar;
+
+ bool use_pancake = false;
+ bool render_cubemap = false;
+ bool finalize_cubemap = false;
+
+ bool flip_y = false;
+
+ Projection light_projection;
+ Transform3D light_transform;
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+ //set pssm stuff
+ uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light);
+ if (last_scene_shadow_pass != get_scene_pass()) {
+ light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect());
+ light_storage->directional_shadow_increase_current_light();
+ light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass());
+ }
+
+ use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+
+ atlas_rect = light_storage->light_instance_get_directional_rect(p_light);
+
+ if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ atlas_rect.size.width /= 2;
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 1) {
+ atlas_rect.position.x += atlas_rect.size.width;
+ } else if (p_pass == 2) {
+ atlas_rect.position.y += atlas_rect.size.height;
+ } else if (p_pass == 3) {
+ atlas_rect.position += atlas_rect.size;
+ }
+ } else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+ atlas_rect.size.height /= 2;
+
+ if (p_pass == 0) {
+ } else {
+ atlas_rect.position.y += atlas_rect.size.height;
+ }
+ }
+
+ float directional_shadow_size = light_storage->directional_shadow_get_size();
+ Rect2 atlas_rect_norm = atlas_rect;
+ atlas_rect_norm.position /= directional_shadow_size;
+ atlas_rect_norm.size /= directional_shadow_size;
+ light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect_norm);
+
+ zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ render_fb = light_storage->direction_shadow_get_fb();
+ render_texture = RID();
+ flip_y = true;
+
+ } else {
+ //set from shadow atlas
+
+ ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas));
+ ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light));
+
+ RSG::light_storage->shadow_atlas_update(p_shadow_atlas);
+
+ uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light);
+
+ uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK;
+ uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant);
+
+ ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant));
+
+ uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
+ uint32_t quadrant_size = shadow_atlas_size >> 1;
+
+ atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+ atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / subdivision);
+ atlas_rect.position.x += (shadow % subdivision) * shadow_size;
+ atlas_rect.position.y += (shadow / subdivision) * shadow_size;
+
+ atlas_rect.size.width = shadow_size;
+ atlas_rect.size.height = shadow_size;
+
+ zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+ if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) {
+ bool wrap = (shadow + 1) % subdivision == 0;
+ dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0);
+
+ if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+ render_texture = light_storage->get_cubemap(shadow_size / 2);
+ render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass);
+
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+ render_cubemap = true;
+ finalize_cubemap = p_pass == 5;
+ atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ atlas_size = shadow_atlas_size;
+
+ if (p_pass == 0) {
+ _render_shadow_begin();
+ }
+
+ } else {
+ atlas_rect.position.x += 1;
+ atlas_rect.position.y += 1;
+ atlas_rect.size.x -= 2;
+ atlas_rect.size.y -= 2;
+
+ atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ using_dual_paraboloid = true;
+ using_dual_paraboloid_flip = p_pass == 1;
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+ flip_y = true;
+ }
+
+ } else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) {
+ light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+ light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+ render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+ flip_y = true;
+ }
+ }
+
+ if (render_cubemap) {
+ //rendering to cubemap
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
+ if (finalize_cubemap) {
+ _render_shadow_process();
+ _render_shadow_end();
+ //reblit
+ Rect2 atlas_rect_norm = atlas_rect;
+ atlas_rect_norm.position /= float(atlas_size);
+ atlas_rect_norm.size /= float(atlas_size);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+
+ //restore transform so it can be properly used
+ light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
+ }
+
+ } else {
+ //render shadow
+ _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
+ }
+}
+
void RenderForwardMobile::_render_shadow_begin() {
scene_state.shadow_passes.clear();
RD::get_singleton()->draw_command_begin_label("Shadow Setup");
@@ -945,7 +1266,6 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
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;
@@ -1014,7 +1334,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) {
for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) {
SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i];
- RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
+ RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER);
_render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect);
}
@@ -1146,7 +1466,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
}
void RenderForwardMobile::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) {
- // we don't do GI in low end..
+ // we don't do SDFGI in low end..
}
void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) {
@@ -1189,7 +1509,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
RD::get_singleton()->draw_command_end_label();
}
-void RenderForwardMobile::_base_uniforms_changed() {
+void RenderForwardMobile::base_uniforms_changed() {
if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -1305,14 +1625,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_omni_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_spot_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
uniforms.push_back(u);
}
@@ -1320,14 +1640,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_reflection_probe_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- u.append_id(get_directional_light_buffer());
+ u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
uniforms.push_back(u);
}
{
@@ -1364,7 +1684,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
RD::Uniform u;
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(get_decal_buffer());
+ u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
uniforms.push_back(u);
}
@@ -1487,12 +1807,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
// LOD
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->scene_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
+ // Get the LOD support points on the mesh AABB.
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z));
- 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);
+ // Get the distances to those points on the AABB from the camera origin.
+ float distance_min = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_min);
+ float distance_max = (float)p_render_data->scene_data->cam_transform.origin.distance_to(lod_support_max);
float distance = 0.0;
@@ -1509,8 +1830,8 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
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->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
+ uint32_t indices = 0;
+ 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
@@ -1584,7 +1905,7 @@ 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) {
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();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? RendererRD::LightStorage::get_singleton()->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()) {
@@ -1665,57 +1986,6 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para
}
}
-void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
- // first zero out our indices
-
- p_push_constant->omni_lights[0] = 0xFFFF;
- p_push_constant->omni_lights[1] = 0xFFFF;
-
- p_push_constant->spot_lights[0] = 0xFFFF;
- p_push_constant->spot_lights[1] = 0xFFFF;
-
- p_push_constant->decals[0] = 0xFFFF;
- p_push_constant->decals[1] = 0xFFFF;
-
- p_push_constant->reflection_probes[0] = 0xFFFF;
- p_push_constant->reflection_probes[1] = 0xFFFF;
-
- if (p_instance->omni_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
- }
- if (p_instance->spot_light_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
- }
- if (p_instance->reflection_probe_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
- }
- if (p_instance->decals_count == 0) {
- spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
- }
-
- for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
- uint32_t ofs = i < 4 ? 0 : 1;
- uint32_t shift = (i & 0x3) << 3;
- uint32_t mask = ~(0xFF << shift);
- if (i < p_instance->omni_light_count) {
- p_push_constant->omni_lights[ofs] &= mask;
- p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
- }
- if (i < p_instance->spot_light_count) {
- p_push_constant->spot_lights[ofs] &= mask;
- p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
- }
- if (i < p_instance->decals_count) {
- p_push_constant->decals[ofs] &= mask;
- p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
- }
- if (i < p_instance->reflection_probe_count) {
- p_push_constant->reflection_probes[ofs] &= mask;
- p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
- }
- }
-}
-
template <RenderForwardMobile::PassMode p_pass_mode>
void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
@@ -1797,7 +2067,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
if (inst->use_soft_shadow) {
base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
}
- _fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
+ forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
#ifdef DEBUG_ENABLED
if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@@ -1989,17 +2259,17 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co
spot_light_count = 0;
for (uint32_t i = 0; i < p_light_instance_count; i++) {
- RS::LightType type = RenderForwardMobile::get_singleton()->light_instance_get_type(p_light_instances[i]);
+ RS::LightType type = RendererRD::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]);
switch (type) {
case RS::LIGHT_OMNI: {
if (omni_light_count < (uint32_t)MAX_RDL_CULL) {
- omni_lights[omni_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
+ omni_lights[omni_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
omni_light_count++;
}
} break;
case RS::LIGHT_SPOT: {
if (spot_light_count < (uint32_t)MAX_RDL_CULL) {
- spot_lights[spot_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
+ spot_lights[spot_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
spot_light_count++;
}
} break;
@@ -2012,14 +2282,14 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co
void RenderForwardMobile::GeometryInstanceForwardMobile::pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < reflection_probe_count; i++) {
- reflection_probes[i] = RenderForwardMobile::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
+ reflection_probes[i] = RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
}
}
void RenderForwardMobile::GeometryInstanceForwardMobile::pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) {
decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
for (uint32_t i = 0; i < decals_count; i++) {
- decals[i] = RenderForwardMobile::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]);
+ decals[i] = RendererRD::TextureStorage::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]);
}
}
@@ -2387,10 +2657,6 @@ bool RenderForwardMobile::is_dynamic_gi_supported() const {
return false;
}
-bool RenderForwardMobile::is_clustered_enabled() const {
- return false;
-}
-
bool RenderForwardMobile::is_volumetric_supported() const {
return false;
}
@@ -2446,7 +2712,7 @@ void RenderForwardMobile::_update_shader_quality_settings() {
scene_shader.set_default_specialization_constants(spec_constants);
- _base_uniforms_changed(); //also need this
+ base_uniforms_changed(); //also need this
}
RenderForwardMobile::RenderForwardMobile() {
@@ -2495,7 +2761,7 @@ RenderForwardMobile::RenderForwardMobile() {
}
RenderForwardMobile::~RenderForwardMobile() {
- directional_shadow_atlas_set_size(0);
+ RSG::light_storage->directional_shadow_atlas_set_size(0);
//clear base uniform set if still valid
for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) {
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 a53872fc88..ce64d805b7 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -44,19 +44,12 @@ namespace RendererSceneRenderImplementation {
class RenderForwardMobile : public RendererSceneRenderRD {
friend SceneShaderForwardMobile;
- struct ForwardIDAllocator {
- LocalVector<bool> allocations;
- LocalVector<uint8_t> map;
- };
-
- ForwardIDAllocator forward_id_allocators[FORWARD_ID_MAX];
+protected:
+ struct GeometryInstanceSurfaceDataCache;
- virtual ForwardID _allocate_forward_id(ForwardIDType p_type) override;
- virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) override;
- virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) override;
- virtual bool _uses_forward_ids() const override { return true; }
+private:
+ static RenderForwardMobile *singleton;
-protected:
/* Scene Shader */
enum {
@@ -157,8 +150,6 @@ protected:
// PASS_MODE_SDF,
};
- class GeometryInstanceForwardMobile;
- struct GeometryInstanceSurfaceDataCache;
struct RenderElementInfo;
struct RenderListParameters {
@@ -172,7 +163,6 @@ protected:
RID render_pass_uniform_set;
bool force_wireframe = false;
Vector2 uv_offset;
- Plane lod_plane;
uint32_t spec_constant_base_flags = 0;
float lod_distance_multiplier = 0.0;
float screen_mesh_lod_threshold = 0.0;
@@ -181,7 +171,7 @@ protected:
uint32_t barrier = RD::BARRIER_MASK_ALL;
uint32_t subpass = 0;
- RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
+ RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, uint32_t p_spec_constant_base_flags = 0, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) {
elements = p_elements;
element_info = p_element_info;
element_count = p_element_count;
@@ -192,7 +182,6 @@ protected:
render_pass_uniform_set = p_render_pass_uniform_set;
force_wireframe = p_force_wireframe;
uv_offset = p_uv_offset;
- lod_plane = p_lod_plane;
lod_distance_multiplier = p_lod_distance_multiplier;
screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
element_offset = p_element_offset;
@@ -201,36 +190,27 @@ protected:
}
};
- virtual float _render_buffers_get_luminance_multiplier() override;
- virtual RD::DataFormat _render_buffers_get_color_format() override;
- virtual bool _render_buffers_can_be_storage() override;
+ /* Render shadows */
- RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+ 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);
+ void _render_shadow_begin();
+ void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+ void _render_shadow_process();
+ void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
- 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, 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;
+ /* Render Scene */
- 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, float p_exposure_normalization) override;
- virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
- virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
- virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
+ RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ void _pre_opaque_render(RenderDataRD *p_render_data);
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
- virtual void _base_uniforms_changed() override;
void _update_render_base_uniform_set();
- virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
- virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
// void _update_instance_data_buffer(RenderListType p_render_list);
- static RenderForwardMobile *singleton;
-
void _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 = false, bool p_pancake_shadows = false, int p_index = 0);
void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
@@ -369,8 +349,28 @@ protected:
RenderList render_list[RENDER_LIST_MAX];
+protected:
+ /* setup */
+ virtual void _update_shader_quality_settings() override;
+
+ virtual float _render_buffers_get_luminance_multiplier() override;
+ virtual RD::DataFormat _render_buffers_get_color_format() override;
+ virtual bool _render_buffers_can_be_storage() override;
+
+ virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+ virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+
+ virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{};
+ virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{};
+ virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override{};
+
+ virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override{};
+ virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override{};
+
/* Geometry instance */
+ class GeometryInstanceForwardMobile;
+
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
@@ -484,13 +484,13 @@ protected:
// culled light info
uint32_t reflection_probe_count = 0;
- ForwardID reflection_probes[MAX_RDL_CULL];
+ RendererRD::ForwardID reflection_probes[MAX_RDL_CULL];
uint32_t omni_light_count = 0;
- ForwardID omni_lights[MAX_RDL_CULL];
+ RendererRD::ForwardID omni_lights[MAX_RDL_CULL];
uint32_t spot_light_count = 0;
- ForwardID spot_lights[MAX_RDL_CULL];
+ RendererRD::ForwardID spot_lights[MAX_RDL_CULL];
uint32_t decals_count = 0;
- ForwardID decals[MAX_RDL_CULL];
+ RendererRD::ForwardID decals[MAX_RDL_CULL];
GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
@@ -513,9 +513,41 @@ protected:
virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override;
};
- _FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
+ /* Rendering */
- void _update_shader_quality_settings() override;
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) 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, float p_exposure_normalization) override;
+ virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+ virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
+ virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
+
+ /* Forward ID */
+
+ class ForwardIDStorageMobile : public RendererRD::ForwardIDStorage {
+ public:
+ struct ForwardIDAllocator {
+ LocalVector<bool> allocations;
+ LocalVector<uint8_t> map;
+ };
+
+ ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX];
+
+ public:
+ virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override;
+ virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override;
+ virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override;
+ virtual bool uses_forward_ids() const override { return true; }
+
+ void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
+ };
+
+ ForwardIDStorageMobile *forward_id_storage_mobile = nullptr;
+
+ virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override {
+ forward_id_storage_mobile = memnew(ForwardIDStorageMobile);
+ return forward_id_storage_mobile;
+ }
public:
static RenderForwardMobile *get_singleton() { return singleton; }
@@ -544,8 +576,9 @@ public:
virtual bool free(RID p_rid) override;
+ virtual void base_uniforms_changed() override;
+
virtual bool is_dynamic_gi_supported() const override;
- virtual bool is_clustered_enabled() const override;
virtual bool is_volumetric_supported() const override;
virtual uint32_t get_max_elements() const override;
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 691d431b82..02bd30d32d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -464,7 +464,7 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) {
bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton;
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, RD::BARRIER_MASK_RASTER);
}
SceneShaderForwardMobile::MaterialData::~MaterialData() {
@@ -597,10 +597,10 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
- actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz";
actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
- actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(read_model_matrix * scene_data.view_matrix)[3].xyz";
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
index 9151c53823..7a2336970b 100644
--- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
+++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "pipeline_cache_rd.h"
+
#include "core/os/memory.h"
RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass, uint32_t p_bool_specializations) {
@@ -70,9 +71,7 @@ RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD
}
void PipelineCacheRD::_clear() {
-#ifndef _MSC_VER
-#warning Clear should probably recompile all the variants already compiled instead to avoid stalls? needs discussion
-#endif
+ // TODO: Clear should probably recompile all the variants already compiled instead to avoid stalls? Needs discussion.
if (versions) {
for (uint32_t i = 0; i < version_count; i++) {
//shader may be gone, so this may not be valid
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index bbb53f7b97..cbc5cc337c 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1075,10 +1075,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
clear_colors.push_back(texture_storage->render_target_get_clear_request_color(p_to_render_target));
texture_storage->render_target_disable_clear_request(p_to_render_target);
}
-#ifndef _MSC_VER
-#warning TODO obtain from framebuffer format eventually when this is implemented
-#endif
-
+ // TODO: Obtain from framebuffer format eventually when this is implemented.
fb_uniform_set = texture_storage->render_target_get_framebuffer_uniform_set(p_to_render_target);
}
@@ -1114,8 +1111,20 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
- if (material.is_null() && ci->canvas_group != nullptr) {
- material = default_canvas_group_material;
+ if (ci->canvas_group != nullptr) {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ if (!p_to_backbuffer) {
+ material = default_clip_children_material;
+ }
+ } else {
+ if (material.is_null()) {
+ if (ci->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_ONLY) {
+ material = default_clip_children_material;
+ } else {
+ material = default_canvas_group_material;
+ }
+ }
+ }
}
if (material != prev_material) {
@@ -1440,10 +1449,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
- Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
-
- if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_OPAQUE) {
+ if (ci->canvas_group_owner->canvas_group->mode != RS::CANVAS_GROUP_MODE_TRANSPARENT) {
+ Rect2i group_rect = ci->canvas_group_owner->global_rect_cache;
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, group_rect, false);
+ if (ci->canvas_group_owner->canvas_group->mode == RS::CANVAS_GROUP_MODE_CLIP_AND_DRAW) {
+ items[item_count++] = ci->canvas_group_owner;
+ }
} else if (!backbuffer_cleared) {
texture_storage->render_target_clear_back_buffer(p_to_render_target, Rect2i(), Color(0, 0, 0, 0));
backbuffer_cleared = true;
@@ -1475,6 +1486,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
canvas_group_owner = nullptr;
+ // Backbuffer is dirty now and needs to be re-cleared if another CanvasGroup needs it.
+ backbuffer_cleared = false;
}
if (backbuffer_copy) {
@@ -1621,13 +1634,13 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp);
}
- Vector3 cam_target = Basis(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
+ Vector3 cam_target = Basis::from_euler(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0));
projection = projection * Projection(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse());
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
- push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ push_constant.projection[y * 4 + x] = projection.columns[y][x];
}
}
static const Vector2 directions[4] = { Vector2(1, 0), Vector2(0, 1), Vector2(-1, 0), Vector2(0, -1) };
@@ -1702,7 +1715,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
- push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ push_constant.projection[y * 4 + x] = projection.columns[y][x];
}
}
@@ -1770,7 +1783,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan
ShadowRenderPushConstant push_constant;
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
- push_constant.projection[y * 4 + x] = projection.matrix[y][x];
+ push_constant.projection[y * 4 + x] = projection.columns[y][x];
}
}
@@ -1901,11 +1914,12 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve
}
}
- //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush
+ //if same buffer len is being set, just use buffer_update to avoid a pipeline flush
if (oc->vertex_array.is_null()) {
//create from scratch
//vertices
+ // TODO: geometry is always of length lc * 6 * sizeof(float), so in doubles builds this will receive half the data it needs
oc->vertex_buffer = RD::get_singleton()->vertex_buffer_create(lc * 6 * sizeof(real_t), geometry);
Vector<RID> buffer;
@@ -2324,7 +2338,7 @@ RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_
bool RendererCanvasRenderRD::CanvasMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
RendererCanvasRenderRD *canvas_singleton = static_cast<RendererCanvasRenderRD *>(RendererCanvasRender::singleton);
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET, false);
}
RendererCanvasRenderRD::CanvasMaterialData::~CanvasMaterialData() {
@@ -2739,6 +2753,26 @@ void fragment() {
material_storage->material_set_shader(default_canvas_group_material, default_canvas_group_shader);
}
+ {
+ default_clip_children_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(default_clip_children_shader);
+
+ material_storage->shader_set_code(default_clip_children_shader, R"(
+// Default clip children shader.
+
+shader_type canvas_item;
+
+void fragment() {
+ vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ COLOR.rgb = c.rgb;
+}
+)");
+ default_clip_children_material = material_storage->material_allocate();
+ material_storage->material_initialize(default_clip_children_material);
+
+ material_storage->material_set_shader(default_clip_children_material, default_clip_children_shader);
+ }
+
static_assert(sizeof(PushConstant) == 128);
}
@@ -2790,6 +2824,9 @@ RendererCanvasRenderRD::~RendererCanvasRenderRD() {
material_storage->material_free(default_canvas_group_material);
material_storage->shader_free(default_canvas_group_shader);
+ material_storage->material_free(default_clip_children_material);
+ material_storage->shader_free(default_clip_children_shader);
+
{
if (state.canvas_state_buffer.is_valid()) {
RD::get_singleton()->free(state.canvas_state_buffer);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 67db56d913..d1f3c9ec6a 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -421,6 +421,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
RID default_canvas_group_shader;
RID default_canvas_group_material;
+ RID default_clip_children_material;
+ RID default_clip_children_shader;
RS::CanvasItemTextureFilter default_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
RS::CanvasItemTextureRepeat default_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
@@ -457,8 +459,6 @@ public:
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_light_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used);
- void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {}
-
virtual void set_shadow_texture_size(int p_size);
void set_time(double p_time);
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index a50742f91a..3289bfb0ea 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -44,13 +44,9 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID
}
for (int i = 0; i < p_amount; i++) {
- RID texture = texture_storage->render_target_get_texture(p_render_targets[i].render_target);
- ERR_CONTINUE(texture.is_null());
- RID rd_texture = texture_storage->texture_get_rd_texture(texture);
+ RID rd_texture = texture_storage->render_target_get_rd_texture(p_render_targets[i].render_target);
ERR_CONTINUE(rd_texture.is_null());
- // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in.
-
if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) {
Vector<RD::Uniform> uniforms;
RD::Uniform u;
@@ -106,10 +102,8 @@ void RendererCompositorRD::begin_frame(double frame_step) {
}
void RendererCompositorRD::end_frame(bool p_swap_buffers) {
-#ifndef _MSC_VER
-#warning TODO: likely pass a bool to swap buffers to avoid display?
-#endif
- RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
+ // TODO: Likely pass a bool to swap buffers to avoid display?
+ RD::get_singleton()->swap_buffers();
}
void RendererCompositorRD::initialize() {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 74b8f0890f..75fe84f46b 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -195,32 +195,6 @@ void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::Env
gi.sdfgi_frames_to_update_light = p_update;
}
-void RendererSceneRenderRD::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
- ssr_roughness_quality = p_quality;
-}
-
-RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_roughness_quality() const {
- return ssr_roughness_quality;
-}
-
-void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
- ssao_quality = p_quality;
- ssao_half_size = p_half_size;
- ssao_adaptive_target = p_adaptive_target;
- ssao_blur_passes = p_blur_passes;
- ssao_fadeout_from = p_fadeout_from;
- ssao_fadeout_to = p_fadeout_to;
-}
-
-void RendererSceneRenderRD::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
- ssil_quality = p_quality;
- ssil_half_size = p_half_size;
- ssil_adaptive_target = p_adaptive_target;
- ssil_blur_passes = p_blur_passes;
- ssil_fadeout_from = p_fadeout_from;
- ssil_fadeout_to = p_fadeout_to;
-}
-
Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) {
ERR_FAIL_COND_V(p_env.is_null(), Ref<Image>());
@@ -276,265 +250,13 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba
panorama_color = ambient_color.lerp(panorama_color, ambient_color_sky_mix);
}
- Ref<Image> panorama;
- panorama.instantiate();
- panorama->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF);
+ Ref<Image> panorama = Image::create_empty(p_size.width, p_size.height, false, Image::FORMAT_RGBAF);
panorama->fill(panorama_color);
return panorama;
}
}
-////////////////////////////////////////////////////////////
-
-RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) {
- return RendererRD::Fog::get_singleton()->fog_volume_instance_create(p_fog_volume);
-}
-
-void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
- RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance);
- ERR_FAIL_COND(!fvi);
- fvi->transform = p_transform;
-}
-void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
- RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance);
- ERR_FAIL_COND(!fvi);
- fvi->active = p_active;
-}
-
-RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
- RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance);
- ERR_FAIL_COND_V(!fvi, RID());
- return fvi->volume;
-}
-
-Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const {
- RendererRD::Fog::FogVolumeInstance *fvi = RendererRD::Fog::get_singleton()->get_fog_volume_instance(p_fog_volume_instance);
- ERR_FAIL_COND_V(!fvi, Vector3());
-
- return fvi->transform.get_origin();
-}
-
-////////////////////////////////////////////////////////////
-
-RID RendererSceneRenderRD::reflection_atlas_create() {
- ReflectionAtlas ra;
- ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
- ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
-
- if (is_clustered_enabled()) {
- ra.cluster_builder = memnew(ClusterBuilderRD);
- ra.cluster_builder->set_shared(&cluster_builder_shared);
- ra.cluster_builder->setup(Size2i(ra.size, ra.size), max_cluster_elements, RID(), RID(), RID());
- } else {
- ra.cluster_builder = nullptr;
- }
-
- return reflection_atlas_owner.make_rid(ra);
-}
-
-void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
- ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND(!ra);
-
- if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
- return; //no changes
- }
-
- if (ra->cluster_builder) {
- // only if we're using our cluster
- ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
- }
-
- ra->size = p_reflection_size;
- ra->count = p_reflection_count;
-
- if (ra->reflection.is_valid()) {
- //clear and invalidate everything
- RD::get_singleton()->free(ra->reflection);
- ra->reflection = RID();
- RD::get_singleton()->free(ra->depth_buffer);
- ra->depth_buffer = RID();
- for (int i = 0; i < ra->reflections.size(); i++) {
- ra->reflections.write[i].data.clear_reflection_data();
- if (ra->reflections[i].owner.is_null()) {
- continue;
- }
- reflection_probe_release_atlas_index(ra->reflections[i].owner);
- //rp->atlasindex clear
- }
-
- ra->reflections.clear();
- }
-}
-
-int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const {
- ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND_V(!ra, 0);
-
- return ra->size;
-}
-
-////////////////////////
-RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) {
- ReflectionProbeInstance rpi;
- rpi.probe = p_probe;
- rpi.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE);
-
- return reflection_probe_instance_owner.make_rid(rpi);
-}
-
-void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
-
- rpi->transform = p_transform;
- rpi->dirty = true;
-}
-
-void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
-
- if (rpi->atlas.is_null()) {
- return; //nothing to release
- }
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND(!atlas);
- ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
- atlas->reflections.write[rpi->atlas_index].owner = RID();
- rpi->atlas_index = -1;
- rpi->atlas = RID();
-}
-
-bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- if (rpi->rendering) {
- return false;
- }
-
- if (rpi->dirty) {
- return true;
- }
-
- if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
- return true;
- }
-
- return rpi->atlas_index == -1;
-}
-
-bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- return rpi->atlas.is_valid();
-}
-
-bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
-
- ERR_FAIL_COND_V(!atlas, false);
-
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
-
- RD::get_singleton()->draw_command_begin_label("Reflection probe render");
-
- if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
- WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
- reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
- }
-
- if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 8) {
- // Invalidate reflection atlas, need to regenerate
- RD::get_singleton()->free(atlas->reflection);
- atlas->reflection = RID();
-
- for (int i = 0; i < atlas->reflections.size(); i++) {
- if (atlas->reflections[i].owner.is_null()) {
- continue;
- }
- reflection_probe_release_atlas_index(atlas->reflections[i].owner);
- }
-
- atlas->reflections.clear();
- }
-
- if (atlas->reflection.is_null()) {
- int mipmaps = MIN(sky.roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
- mipmaps = RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering
- {
- //reflection atlas was unused, create:
- RD::TextureFormat tf;
- tf.array_layers = 6 * atlas->count;
- tf.format = _render_buffers_get_color_format();
- tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
- tf.mipmaps = mipmaps;
- tf.width = atlas->size;
- tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
-
- atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
- {
- RD::TextureFormat tf;
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
- tf.width = atlas->size;
- tf.height = atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
- atlas->reflections.resize(atlas->count);
- for (int i = 0; i < atlas->count; i++) {
- atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format());
- for (int j = 0; j < 6; j++) {
- atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer);
- }
- }
-
- Vector<RID> fb;
- fb.push_back(atlas->depth_buffer);
- atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
- }
-
- if (rpi->atlas_index == -1) {
- for (int i = 0; i < atlas->reflections.size(); i++) {
- if (atlas->reflections[i].owner.is_null()) {
- rpi->atlas_index = i;
- break;
- }
- }
- //find the one used last
- if (rpi->atlas_index == -1) {
- //everything is in use, find the one least used via LRU
- uint64_t pass_min = 0;
-
- for (int i = 0; i < atlas->reflections.size(); i++) {
- ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner);
- if (rpi2->last_pass < pass_min) {
- pass_min = rpi2->last_pass;
- rpi->atlas_index = i;
- }
- }
- }
- }
-
- if (rpi->atlas_index != -1) { // should we fail if this is still -1 ?
- atlas->reflections.write[rpi->atlas_index].owner = p_instance;
- }
-
- rpi->atlas = p_reflection_atlas;
- rpi->rendering = true;
- rpi->dirty = false;
- rpi->processing_layer = 1;
- rpi->processing_side = 0;
-
- RD::get_singleton()->draw_command_end_label();
-
- return true;
-}
+/* REFLECTION PROBE */
RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) {
Vector<RID> fb;
@@ -543,667 +265,39 @@ RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID
return RD::get_singleton()->framebuffer_create(fb);
}
-bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, false);
- ERR_FAIL_COND_V(!rpi->rendering, false);
- ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
-
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- if (!atlas || rpi->atlas_index == -1) {
- //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
- rpi->rendering = false;
- return false;
- }
-
- if (RSG::light_storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
- // Using real time reflections, all roughness is done in one step
- atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(false);
- rpi->rendering = false;
- rpi->processing_side = 0;
- rpi->processing_layer = 1;
- return true;
- }
-
- if (rpi->processing_layer > 1) {
- atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, 10, rpi->processing_layer, sky.sky_ggx_samples_quality);
- rpi->processing_layer++;
- if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
- rpi->rendering = false;
- rpi->processing_side = 0;
- rpi->processing_layer = 1;
- return true;
- }
- return false;
-
- } else {
- atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_side, rpi->processing_layer, sky.sky_ggx_samples_quality);
- }
-
- rpi->processing_side++;
- if (rpi->processing_side == 6) {
- rpi->processing_side = 0;
- rpi->processing_layer++;
- }
-
- return false;
-}
-
-uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, 0);
- return atlas->size;
-}
-
-RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
- ERR_FAIL_INDEX_V(p_index, 6, RID());
-
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->reflections[rpi->atlas_index].fbs[p_index];
-}
-
-RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
- ERR_FAIL_INDEX_V(p_index, 6, RID());
-
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->depth_fb;
-}
-
-///////////////////////////////////////////////////////////
-
-RID RendererSceneRenderRD::shadow_atlas_create() {
- return shadow_atlas_owner.make_rid(ShadowAtlas());
-}
-
-void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
- if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) {
- RD::TextureFormat tf;
- tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
- tf.width = shadow_atlas->size;
- tf.height = shadow_atlas->size;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
- shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- Vector<RID> fb_tex;
- fb_tex.push_back(shadow_atlas->depth);
- shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex);
- }
-}
-
-void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_COND(p_size < 0);
- p_size = next_power_of_2(p_size);
-
- if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) {
- return;
- }
-
- // erasing atlas
- if (shadow_atlas->depth.is_valid()) {
- RD::get_singleton()->free(shadow_atlas->depth);
- shadow_atlas->depth = RID();
- }
- for (int i = 0; i < 4; i++) {
- //clear subdivisions
- shadow_atlas->quadrants[i].shadows.clear();
- shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision);
- }
-
- //erase shadow atlas reference from lights
- for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) {
- LightInstance *li = light_instance_owner.get_or_null(E.key);
- ERR_CONTINUE(!li);
- li->shadow_atlases.erase(p_atlas);
- }
-
- //clear owners
- shadow_atlas->shadow_owners.clear();
-
- shadow_atlas->size = p_size;
- shadow_atlas->use_16_bits = p_16_bits;
-}
-
-void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_INDEX(p_quadrant, 4);
- ERR_FAIL_INDEX(p_subdivision, 16384);
-
- uint32_t subdiv = next_power_of_2(p_subdivision);
- if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer
- subdiv <<= 1;
- }
-
- subdiv = int(Math::sqrt((float)subdiv));
-
- //obtain the number that will be x*x
-
- if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) {
- return;
- }
-
- //erase all data from quadrant
- for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
- if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
- shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
- LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
- ERR_CONTINUE(!li);
- li->shadow_atlases.erase(p_atlas);
- }
- }
-
- shadow_atlas->quadrants[p_quadrant].shadows.clear();
- shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv);
- shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
-
- //cache the smallest subdiv (for faster allocation in light update)
-
- shadow_atlas->smallest_subdiv = 1 << 30;
-
- for (int i = 0; i < 4; i++) {
- if (shadow_atlas->quadrants[i].subdivision) {
- shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
- }
- }
-
- if (shadow_atlas->smallest_subdiv == 1 << 30) {
- shadow_atlas->smallest_subdiv = 0;
- }
-
- //resort the size orders, simple bublesort for 4 elements..
-
- int swaps = 0;
- do {
- swaps = 0;
-
- for (int i = 0; i < 3; i++) {
- if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
- SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
- swaps++;
- }
- }
- } while (swaps > 0);
-}
-
-bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
- for (int i = p_quadrant_count - 1; i >= 0; i--) {
- int qidx = p_in_quadrants[i];
-
- if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
- return false;
- }
-
- //look for an empty space
- int sc = shadow_atlas->quadrants[qidx].shadows.size();
- const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
-
- int found_free_idx = -1; //found a free one
- int found_used_idx = -1; //found existing one, must steal it
- uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion)
-
- for (int j = 0; j < sc; j++) {
- if (!sarr[j].owner.is_valid()) {
- found_free_idx = j;
- break;
- }
-
- LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
- ERR_CONTINUE(!sli);
-
- if (sli->last_scene_pass != scene_pass) {
- //was just allocated, don't kill it so soon, wait a bit..
- if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
- continue;
- }
-
- if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
- found_used_idx = j;
- min_pass = sli->last_scene_pass;
- }
- }
- }
-
- if (found_free_idx == -1 && found_used_idx == -1) {
- continue; //nothing found
- }
-
- if (found_free_idx == -1 && found_used_idx != -1) {
- found_free_idx = found_used_idx;
- }
-
- r_quadrant = qidx;
- r_shadow = found_free_idx;
-
- return true;
- }
-
- return false;
-}
-
-bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
- for (int i = p_quadrant_count - 1; i >= 0; i--) {
- int qidx = p_in_quadrants[i];
-
- if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
- return false;
- }
-
- //look for an empty space
- int sc = shadow_atlas->quadrants[qidx].shadows.size();
- const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
-
- int found_idx = -1;
- uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair
-
- for (int j = 0; j < sc - 1; j++) {
- uint64_t pass = 0;
-
- if (sarr[j].owner.is_valid()) {
- LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
- ERR_CONTINUE(!sli);
-
- if (sli->last_scene_pass == scene_pass) {
- continue;
- }
-
- //was just allocated, don't kill it so soon, wait a bit..
- if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
- continue;
- }
- pass += sli->last_scene_pass;
- }
-
- if (sarr[j + 1].owner.is_valid()) {
- LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner);
- ERR_CONTINUE(!sli);
-
- if (sli->last_scene_pass == scene_pass) {
- continue;
- }
-
- //was just allocated, don't kill it so soon, wait a bit..
- if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
- continue;
- }
- pass += sli->last_scene_pass;
- }
-
- if (found_idx == -1 || pass < min_pass) {
- found_idx = j;
- min_pass = pass;
-
- // we found two empty spots, no need to check the rest
- if (pass == 0) {
- break;
- }
- }
- }
-
- if (found_idx == -1) {
- continue; //nothing found
- }
-
- r_quadrant = qidx;
- r_shadow = found_idx;
-
- return true;
- }
-
- return false;
-}
-
-bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!shadow_atlas, false);
-
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND_V(!li, false);
-
- if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
- return false;
- }
-
- uint32_t quad_size = shadow_atlas->size >> 1;
- int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
-
- int valid_quadrants[4];
- int valid_quadrant_count = 0;
- int best_size = -1; //best size found
- int best_subdiv = -1; //subdiv for the best size
-
- //find the quadrants this fits into, and the best possible size it can fit into
- for (int i = 0; i < 4; i++) {
- int q = shadow_atlas->size_order[i];
- int sd = shadow_atlas->quadrants[q].subdivision;
- if (sd == 0) {
- continue; //unused
- }
-
- int max_fit = quad_size / sd;
-
- if (best_size != -1 && max_fit > best_size) {
- break; //too large
- }
-
- valid_quadrants[valid_quadrant_count++] = q;
- best_subdiv = sd;
-
- if (max_fit >= desired_fit) {
- best_size = max_fit;
- }
- }
-
- ERR_FAIL_COND_V(valid_quadrant_count == 0, false);
-
- uint64_t tick = OS::get_singleton()->get_ticks_msec();
-
- uint32_t old_key = ShadowAtlas::SHADOW_INVALID;
- uint32_t old_quadrant = ShadowAtlas::SHADOW_INVALID;
- uint32_t old_shadow = ShadowAtlas::SHADOW_INVALID;
- int old_subdivision = -1;
-
- bool should_realloc = false;
- bool should_redraw = false;
-
- if (shadow_atlas->shadow_owners.has(p_light_instance)) {
- old_key = shadow_atlas->shadow_owners[p_light_instance];
- old_quadrant = (old_key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- old_shadow = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
- should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version;
-
- if (!should_realloc) {
- shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version;
- //already existing, see if it should redraw or it's just OK
- return should_redraw;
- }
-
- old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision;
- }
-
- bool is_omni = li->light_type == RS::LIGHT_OMNI;
- bool found_shadow = false;
- int new_quadrant = -1;
- int new_shadow = -1;
-
- if (is_omni) {
- found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
- } else {
- found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
- }
-
- if (found_shadow) {
- if (old_quadrant != ShadowAtlas::SHADOW_INVALID) {
- shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0;
- shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID();
-
- if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
- shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0;
- shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID();
- }
- }
-
- uint32_t new_key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
- new_key |= new_shadow;
-
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
- _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow);
-
- sh->owner = p_light_instance;
- sh->alloc_tick = tick;
- sh->version = p_light_version;
-
- if (is_omni) {
- new_key |= ShadowAtlas::OMNI_LIGHT_FLAG;
-
- int new_omni_shadow = new_shadow + 1;
- ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow];
- _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow);
-
- extra_sh->owner = p_light_instance;
- extra_sh->alloc_tick = tick;
- extra_sh->version = p_light_version;
- }
-
- li->shadow_atlases.insert(p_atlas);
-
- //update it in map
- shadow_atlas->shadow_owners[p_light_instance] = new_key;
- //make it dirty, as it should redraw anyway
- return true;
- }
-
- return should_redraw;
-}
-
-void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) {
- if (p_shadow->owner.is_valid()) {
- LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner);
- uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner];
-
- if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) {
- uint32_t s = old_key & ShadowAtlas::SHADOW_INDEX_MASK;
- uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1);
- RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx];
- omni_shadow->version = 0;
- omni_shadow->owner = RID();
- }
-
- p_shadow_atlas->shadow_owners.erase(p_shadow->owner);
- p_shadow->version = 0;
- p_shadow->owner = RID();
- sli->shadow_atlases.erase(p_atlas);
- }
-}
-
-void RendererSceneRenderRD::_update_directional_shadow_atlas() {
- if (directional_shadow.depth.is_null() && directional_shadow.size > 0) {
- RD::TextureFormat tf;
- tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
- tf.width = directional_shadow.size;
- tf.height = directional_shadow.size;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
-
- directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- Vector<RID> fb_tex;
- fb_tex.push_back(directional_shadow.depth);
- directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex);
- }
-}
-void RendererSceneRenderRD::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
- p_size = nearest_power_of_2_templated(p_size);
-
- if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) {
- return;
- }
-
- directional_shadow.size = p_size;
- directional_shadow.use_16_bits = p_16_bits;
-
- if (directional_shadow.depth.is_valid()) {
- RD::get_singleton()->free(directional_shadow.depth);
- directional_shadow.depth = RID();
- _base_uniforms_changed();
- }
-}
-
-void RendererSceneRenderRD::set_directional_shadow_count(int p_count) {
- directional_shadow.light_count = p_count;
- directional_shadow.current_light = 0;
-}
-
-static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
- int split_h = 1;
- int split_v = 1;
-
- while (split_h * split_v < p_shadow_count) {
- if (split_h == split_v) {
- split_h <<= 1;
- } else {
- split_v <<= 1;
- }
- }
-
- Rect2i rect(0, 0, p_size, p_size);
- rect.size.width /= split_h;
- rect.size.height /= split_v;
-
- rect.position.x = rect.size.width * (p_shadow_index % split_h);
- rect.position.y = rect.size.height * (p_shadow_index / split_h);
-
- return rect;
-}
-
-int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance) {
- ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
-
- Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
-
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance);
- ERR_FAIL_COND_V(!light_instance, 0);
-
- switch (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light)) {
- case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
- break; //none
- case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
- r.size.height /= 2;
- break;
- case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
- r.size /= 2;
- break;
- }
-
- return MAX(r.size.width, r.size.height);
-}
-
-//////////////////////////////////////////////////
-
-RID RendererSceneRenderRD::light_instance_create(RID p_light) {
- RID li = light_instance_owner.make_rid(LightInstance());
-
- LightInstance *light_instance = light_instance_owner.get_or_null(li);
-
- light_instance->self = li;
- light_instance->light = p_light;
- light_instance->light_type = RSG::light_storage->light_get_type(p_light);
- if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
- light_instance->forward_id = _allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT);
- }
-
- return li;
-}
-
-void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->transform = p_transform;
-}
-
-void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->aabb = p_aabb;
-}
-
-void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- ERR_FAIL_INDEX(p_pass, 6);
+/* FOG VOLUME INSTANCE */
- light_instance->shadow_transform[p_pass].camera = p_projection;
- light_instance->shadow_transform[p_pass].transform = p_transform;
- light_instance->shadow_transform[p_pass].farplane = p_far;
- light_instance->shadow_transform[p_pass].split = p_split;
- light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
- light_instance->shadow_transform[p_pass].range_begin = p_range_begin;
- light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size;
- light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale;
-}
-
-void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
-
- light_instance->last_scene_pass = scene_pass;
+RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) {
+ return RendererRD::Fog::get_singleton()->fog_volume_instance_create(p_fog_volume);
}
-RendererSceneRenderRD::ShadowCubemap *RendererSceneRenderRD::_get_shadow_cubemap(int p_size) {
- if (!shadow_cubemaps.has(p_size)) {
- ShadowCubemap sc;
- {
- RD::TextureFormat tf;
- tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
- tf.width = p_size;
- tf.height = p_size;
- tf.texture_type = RD::TEXTURE_TYPE_CUBE;
- tf.array_layers = 6;
- tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
- sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
- }
-
- for (int i = 0; i < 6; i++) {
- RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0);
- Vector<RID> fbtex;
- fbtex.push_back(side_texture);
- sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex);
- }
-
- shadow_cubemaps[p_size] = sc;
- }
-
- return &shadow_cubemaps[p_size];
+void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
+ RendererRD::Fog::get_singleton()->fog_volume_instance_set_transform(p_fog_volume_instance, p_transform);
}
-//////////////////////////
-
-RID RendererSceneRenderRD::decal_instance_create(RID p_decal) {
- DecalInstance di;
- di.decal = p_decal;
- di.forward_id = _allocate_forward_id(FORWARD_ID_TYPE_DECAL);
- return decal_instance_owner.make_rid(di);
+void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
+ RendererRD::Fog::get_singleton()->fog_volume_instance_set_active(p_fog_volume_instance, p_active);
}
-void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
- DecalInstance *di = decal_instance_owner.get_or_null(p_decal);
- ERR_FAIL_COND(!di);
- di->transform = p_transform;
+RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
+ return RendererRD::Fog::get_singleton()->fog_volume_instance_get_volume(p_fog_volume_instance);
}
-/////////////////////////////////
-
-RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) {
- LightmapInstance li;
- li.lightmap = p_lightmap;
- return lightmap_instance_owner.make_rid(li);
-}
-void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
- LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap);
- ERR_FAIL_COND(!li);
- li->transform = p_transform;
+Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const {
+ return RendererRD::Fog::get_singleton()->fog_volume_instance_get_position(p_fog_volume_instance);
}
-/////////////////////////////////
+/* VOXEL GI */
RID RendererSceneRenderRD::voxel_gi_instance_create(RID p_base) {
return gi.voxel_gi_instance_create(p_base);
}
void RendererSceneRenderRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
+ if (!is_dynamic_gi_supported()) {
+ return;
+ }
+
gi.voxel_gi_instance_set_transform_to_data(p_probe, p_xform);
}
@@ -1220,7 +314,7 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins
return;
}
- gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this);
+ gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects);
}
void RendererSceneRenderRD::_debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth) {
@@ -1243,9 +337,6 @@ Ref<RenderSceneBuffers> RendererSceneRenderRD::render_buffers_create() {
rb->set_can_be_storage(_render_buffers_can_be_storage());
rb->set_max_cluster_elements(max_cluster_elements);
rb->set_base_data_format(_render_buffers_get_color_format());
- if (ss_effects) {
- rb->set_sseffects(ss_effects);
- }
if (vrs) {
rb->set_vrs(vrs);
}
@@ -1306,136 +397,6 @@ void RendererSceneRenderRD::_allocate_luminance_textures(Ref<RenderSceneBuffersR
}
}
-void RendererSceneRenderRD::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) {
- ERR_FAIL_COND(p_render_buffers.is_null());
-
- Size2i internal_size = p_render_buffers->get_internal_size();
- bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
-
- if (!can_use_effects) {
- //just copy
- return;
- }
-
- p_render_buffers->allocate_blur_textures();
-
- for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
- RID internal_texture = p_render_buffers->get_internal_texture(v);
- RID depth_texture = p_render_buffers->get_depth_texture(v);
- ss_effects->sub_surface_scattering(p_render_buffers, internal_texture, depth_texture, p_camera, internal_size, sss_scale, sss_depth_scale, sss_quality);
- }
-}
-
-void RendererSceneRenderRD::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
- ERR_FAIL_NULL(ss_effects);
- ERR_FAIL_COND(p_render_buffers.is_null());
-
- Size2i internal_size = p_render_buffers->get_internal_size();
- bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
- uint32_t view_count = p_render_buffers->get_view_count();
-
- if (!can_use_effects) {
- //just copy
- copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count);
- return;
- }
-
- ERR_FAIL_COND(p_environment.is_null());
- ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
-
- Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2);
- if (p_render_buffers->ssr.output.is_null()) {
- ss_effects->ssr_allocate_buffers(p_render_buffers->ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, view_count);
- }
- RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
- RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < view_count; v++) {
- texture_slices[v] = p_render_buffers->get_internal_texture(v);
- depth_slices[v] = p_render_buffers->get_depth_texture(v);
- }
- ss_effects->screen_space_reflection(p_render_buffers->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, depth_slices, half_size, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), view_count, p_projections, p_eye_offsets);
- copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), p_render_buffers->ssr.output, view_count);
-}
-
-void RendererSceneRenderRD::_process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection) {
- ERR_FAIL_NULL(ss_effects);
- ERR_FAIL_COND(p_render_buffers.is_null());
- ERR_FAIL_COND(p_environment.is_null());
-
- RENDER_TIMESTAMP("Process SSAO");
-
- RendererRD::SSEffects::SSAOSettings settings;
- settings.radius = environment_get_ssao_radius(p_environment);
- settings.intensity = environment_get_ssao_intensity(p_environment);
- settings.power = environment_get_ssao_power(p_environment);
- settings.detail = environment_get_ssao_detail(p_environment);
- settings.horizon = environment_get_ssao_horizon(p_environment);
- settings.sharpness = environment_get_ssao_sharpness(p_environment);
-
- settings.quality = ssao_quality;
- settings.half_size = ssao_half_size;
- settings.adaptive_target = ssao_adaptive_target;
- settings.blur_passes = ssao_blur_passes;
- settings.fadeout_from = ssao_fadeout_from;
- settings.fadeout_to = ssao_fadeout_to;
- settings.full_screen_size = p_render_buffers->get_internal_size();
-
- ss_effects->ssao_allocate_buffers(p_render_buffers->ss_effects.ssao, settings, p_render_buffers->ss_effects.linear_depth);
- ss_effects->generate_ssao(p_render_buffers->ss_effects.ssao, p_normal_buffer, p_projection, settings);
-}
-
-void RendererSceneRenderRD::_process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform) {
- ERR_FAIL_NULL(ss_effects);
- ERR_FAIL_COND(p_render_buffers.is_null());
- ERR_FAIL_COND(p_environment.is_null());
-
- RENDER_TIMESTAMP("Process SSIL");
-
- RendererRD::SSEffects::SSILSettings settings;
- settings.radius = environment_get_ssil_radius(p_environment);
- settings.intensity = environment_get_ssil_intensity(p_environment);
- settings.sharpness = environment_get_ssil_sharpness(p_environment);
- settings.normal_rejection = environment_get_ssil_normal_rejection(p_environment);
-
- settings.quality = ssil_quality;
- settings.half_size = ssil_half_size;
- settings.adaptive_target = ssil_adaptive_target;
- settings.blur_passes = ssil_blur_passes;
- settings.fadeout_from = ssil_fadeout_from;
- settings.fadeout_to = ssil_fadeout_to;
- settings.full_screen_size = p_render_buffers->get_internal_size();
-
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_projection;
- Transform3D transform = p_transform;
- transform.set_origin(Vector3(0.0, 0.0, 0.0));
- Projection last_frame_projection = p_render_buffers->ss_effects.last_frame_projection * Projection(p_render_buffers->ss_effects.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
-
- ss_effects->ssil_allocate_buffers(p_render_buffers->ss_effects.ssil, settings, p_render_buffers->ss_effects.linear_depth);
- ss_effects->screen_space_indirect_lighting(p_render_buffers->ss_effects.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
- p_render_buffers->ss_effects.last_frame_projection = projection;
- p_render_buffers->ss_effects.last_frame_transform = transform;
-}
-
-void RendererSceneRenderRD::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) {
- ERR_FAIL_COND(p_render_buffers.is_null());
-
- if (p_render_buffers->ss_effects.ssil.last_frame.is_valid()) {
- Size2i size = p_render_buffers->get_internal_size();
- RID texture = p_render_buffers->get_internal_texture();
- copy_effects->copy_to_rect(texture, p_render_buffers->ss_effects.ssil.last_frame, Rect2i(0, 0, size.x, size.y));
-
- int width = size.x;
- int height = size.y;
- for (int i = 0; i < p_render_buffers->ss_effects.ssil.last_frame_slices.size() - 1; i++) {
- width = MAX(1, width >> 1);
- height = MAX(1, height >> 1);
- copy_effects->make_mipmap(p_render_buffers->ss_effects.ssil.last_frame_slices[i], p_render_buffers->ss_effects.ssil.last_frame_slices[i + 1], Size2i(width, height));
- }
- }
-}
-
void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) {
Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
ERR_FAIL_COND(rb.is_null());
@@ -1851,7 +812,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) {
if (p_shadow_atlas.is_valid()) {
- RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
+ RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->shadow_atlas_get_texture(p_shadow_atlas);
if (shadow_atlas_texture.is_null()) {
shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -1863,9 +824,9 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS) {
- if (directional_shadow_get_texture().is_valid()) {
- RID shadow_atlas_texture = directional_shadow_get_texture();
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ if (RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture().is_valid()) {
+ RID shadow_atlas_texture = RendererRD::LightStorage::get_singleton()->directional_shadow_get_texture();
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(shadow_atlas_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, true);
}
@@ -1875,7 +836,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
RID decal_atlas = RendererRD::TextureStorage::get_singleton()->decal_atlas_get_texture();
if (decal_atlas.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(decal_atlas, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize / 2), false, false, true);
}
@@ -1883,43 +844,26 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(Ref<RenderSceneBuffersRD>
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE) {
if (p_render_buffers->luminance.current.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(p_render_buffers->luminance.current, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize / 8), false, true);
}
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSAO && p_render_buffers->ss_effects.ssao.ao_final.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssao.ao_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, true);
- }
-
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SSIL && p_render_buffers->ss_effects.ssil.ssil_final.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(p_render_buffers->ss_effects.ssil.ssil_final, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
- }
-
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(p_render_buffers).is_valid()) {
Size2 rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_GI_BUFFER && p_render_buffers->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT)) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
- RID ambient_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT);
- RID reflection_texture = p_render_buffers->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION);
- copy_effects->copy_to_fb_rect(ambient_texture, texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, true, reflection_texture, p_render_buffers->get_view_count() > 1);
- }
-
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
if (p_occlusion_buffer.is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(texture_storage->texture_get_rd_texture(p_occlusion_buffer), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2i(Vector2(), rtsize), true, false);
}
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS && _render_buffers_get_velocity_texture(p_render_buffers).is_valid()) {
- Size2 rtsize = texture_storage->render_target_get_size(render_target);
+ Size2i rtsize = texture_storage->render_target_get_size(render_target);
copy_effects->copy_to_fb_rect(_render_buffers_get_velocity_texture(p_render_buffers), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
}
}
@@ -1944,19 +888,6 @@ void RendererSceneRenderRD::gi_set_use_half_resolution(bool p_enable) {
gi.half_resolution = p_enable;
}
-void RendererSceneRenderRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
- sss_quality = p_quality;
-}
-
-RS::SubSurfaceScatteringQuality RendererSceneRenderRD::sub_surface_scattering_get_quality() const {
- return sss_quality;
-}
-
-void RendererSceneRenderRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) {
- sss_scale = p_scale;
- sss_depth_scale = p_depth_scale;
-}
-
void RendererSceneRenderRD::positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
ERR_FAIL_INDEX_MSG(p_quality, RS::SHADOW_QUALITY_MAX, "Shadow quality too high, please see RenderingServer's ShadowQuality enum");
@@ -2074,788 +1005,31 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
return sky.sky_use_cubemap_array;
}
-void RendererSceneRenderRD::_setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
- RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
- cluster.reflection_count = 0;
-
- for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) {
- if (cluster.reflection_count == cluster.max_reflections) {
- break;
- }
+void RendererSceneRenderRD::_update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers) {
+ if (p_render_buffers.is_valid() && vrs) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]);
- if (!rpi) {
- continue;
- }
-
- cluster.reflection_sort[cluster.reflection_count].instance = rpi;
- cluster.reflection_sort[cluster.reflection_count].depth = -p_camera_inverse_transform.xform(rpi->transform.origin).z;
- cluster.reflection_count++;
- }
-
- if (cluster.reflection_count > 0) {
- SortArray<Cluster::InstanceSort<ReflectionProbeInstance>> sort_array;
- sort_array.sort(cluster.reflection_sort, cluster.reflection_count);
- }
-
- bool using_forward_ids = _uses_forward_ids();
- for (uint32_t i = 0; i < cluster.reflection_count; i++) {
- ReflectionProbeInstance *rpi = cluster.reflection_sort[i].instance;
-
- if (using_forward_ids) {
- _map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i);
- }
-
- RID base_probe = rpi->probe;
-
- Cluster::ReflectionData &reflection_ubo = cluster.reflections[i];
-
- Vector3 extents = light_storage->reflection_probe_get_extents(base_probe);
-
- rpi->cull_mask = light_storage->reflection_probe_get_cull_mask(base_probe);
-
- reflection_ubo.box_extents[0] = extents.x;
- reflection_ubo.box_extents[1] = extents.y;
- reflection_ubo.box_extents[2] = extents.z;
- reflection_ubo.index = rpi->atlas_index;
-
- Vector3 origin_offset = light_storage->reflection_probe_get_origin_offset(base_probe);
-
- reflection_ubo.box_offset[0] = origin_offset.x;
- reflection_ubo.box_offset[1] = origin_offset.y;
- reflection_ubo.box_offset[2] = origin_offset.z;
- reflection_ubo.mask = light_storage->reflection_probe_get_cull_mask(base_probe);
-
- reflection_ubo.intensity = light_storage->reflection_probe_get_intensity(base_probe);
- reflection_ubo.ambient_mode = light_storage->reflection_probe_get_ambient_mode(base_probe);
-
- reflection_ubo.exterior = !light_storage->reflection_probe_is_interior(base_probe);
- reflection_ubo.box_project = light_storage->reflection_probe_is_box_projection(base_probe);
- reflection_ubo.exposure_normalization = 1.0;
-
- if (p_render_data->camera_attributes.is_valid()) {
- float exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- reflection_ubo.exposure_normalization = exposure / light_storage->reflection_probe_get_baked_exposure(base_probe);
- }
-
- Color ambient_linear = light_storage->reflection_probe_get_ambient_color(base_probe).srgb_to_linear();
- float interior_ambient_energy = light_storage->reflection_probe_get_ambient_color_energy(base_probe);
- reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
- reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
- reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
-
- Transform3D transform = rpi->transform;
- Transform3D proj = (p_camera_inverse_transform * transform).inverse();
- RendererRD::MaterialStorage::store_transform(proj, reflection_ubo.local_matrix);
-
- if (current_cluster_builder != nullptr) {
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_REFLECTION_PROBE, transform, extents);
- }
-
- rpi->last_pass = RSG::rasterizer->get_frame_number();
- }
-
- if (cluster.reflection_count) {
- RD::get_singleton()->buffer_update(cluster.reflection_buffer, 0, cluster.reflection_count * sizeof(Cluster::ReflectionData), cluster.reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
- }
-}
-
-void RendererSceneRenderRD::_setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
- RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
- RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
-
- Transform3D inverse_transform = p_camera_transform.affine_inverse();
-
- r_directional_light_count = 0;
- r_positional_light_count = 0;
-
- Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin);
-
- cluster.omni_light_count = 0;
- cluster.spot_light_count = 0;
-
- r_directional_light_soft_shadows = false;
-
- for (int i = 0; i < (int)p_lights.size(); i++) {
- LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
- if (!li) {
- continue;
- }
- RID base = li->light;
-
- ERR_CONTINUE(base.is_null());
-
- RS::LightType type = light_storage->light_get_type(base);
- switch (type) {
- case RS::LIGHT_DIRECTIONAL: {
- if (r_directional_light_count >= cluster.max_directional_lights || light_storage->light_directional_get_sky_mode(base) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
- continue;
- }
-
- Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count];
-
- Transform3D light_transform = li->transform;
-
- Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- float sign = light_storage->light_is_negative(base) ? -1 : 1;
-
- light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
-
- if (is_using_physical_light_units()) {
- light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
- } else {
- light_data.energy *= Math_PI;
- }
-
- if (p_render_data->camera_attributes.is_valid()) {
- light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- }
-
- Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
- light_data.color[0] = linear_col.r;
- light_data.color[1] = linear_col.g;
- light_data.color[2] = linear_col.b;
-
- light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
- light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY);
- light_data.mask = light_storage->light_get_cull_mask(base);
-
- float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
-
- light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
- WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet.");
- }
-
- light_data.shadow_opacity = (p_using_shadows && light_storage->light_has_shadow(base))
- ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY)
- : 0.0;
-
- float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- if (angular_diameter > 0.0) {
- // I know tan(0) is 0, but let's not risk it with numerical precision.
- // technically this will keep expanding until reaching the sun, but all we care
- // is expand until we reach the radius of the near plane (there can't be more occluders than that)
- angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
- if (light_storage->light_has_shadow(base) && light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR) > 0.0) {
- // Only enable PCSS-like soft shadows if blurring is enabled.
- // Otherwise, performance would decrease with no visual difference.
- r_directional_light_soft_shadows = true;
- }
- } else {
- angular_diameter = 0.0;
- }
-
- if (light_data.shadow_opacity > 0.001) {
- RS::LightDirectionalShadowMode smode = light_storage->light_directional_get_shadow_mode(base);
-
- int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
- light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light_storage->light_directional_get_blend_splits(base);
- for (int j = 0; j < 4; j++) {
- Rect2 atlas_rect = li->shadow_transform[j].atlas_rect;
- Projection matrix = li->shadow_transform[j].camera;
- float split = li->shadow_transform[MIN(limit, j)].split;
-
- Projection bias;
- bias.set_light_bias();
- Projection rectm;
- rectm.set_light_atlas_rect(atlas_rect);
-
- Transform3D modelview = (inverse_transform * li->shadow_transform[j].transform).inverse();
-
- Projection shadow_mtx = rectm * bias * matrix * modelview;
- light_data.shadow_split_offsets[j] = split;
- float bias_scale = li->shadow_transform[j].bias_scale;
- light_data.shadow_bias[j] = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0 * bias_scale;
- light_data.shadow_normal_bias[j] = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * li->shadow_transform[j].shadow_texel_size;
- light_data.shadow_transmittance_bias[j] = light_storage->light_get_transmittance_bias(base) * bias_scale;
- light_data.shadow_z_range[j] = li->shadow_transform[j].farplane;
- light_data.shadow_range_begin[j] = li->shadow_transform[j].range_begin;
- RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrices[j]);
-
- Vector2 uv_scale = li->shadow_transform[j].uv_scale;
- uv_scale *= atlas_rect.size; //adapt to atlas size
- switch (j) {
- case 0: {
- light_data.uv_scale1[0] = uv_scale.x;
- light_data.uv_scale1[1] = uv_scale.y;
- } break;
- case 1: {
- light_data.uv_scale2[0] = uv_scale.x;
- light_data.uv_scale2[1] = uv_scale.y;
- } break;
- case 2: {
- light_data.uv_scale3[0] = uv_scale.x;
- light_data.uv_scale3[1] = uv_scale.y;
- } break;
- case 3: {
- light_data.uv_scale4[0] = uv_scale.x;
- light_data.uv_scale4[1] = uv_scale.y;
- } break;
- }
- }
-
- float fade_start = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_FADE_START);
- light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
- light_data.fade_to = -light_data.shadow_split_offsets[3];
-
- light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
- light_data.softshadow_angle = angular_diameter;
- light_data.bake_mode = light_storage->light_get_bake_mode(base);
-
- if (angular_diameter <= 0.0) {
- light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
- }
- }
-
- r_directional_light_count++;
- } break;
- case RS::LIGHT_OMNI: {
- if (cluster.omni_light_count >= cluster.max_lights) {
- continue;
- }
-
- const real_t distance = camera_plane.distance_to(li->transform.origin);
-
- if (light_storage->light_is_distance_fade_enabled(li->light)) {
- const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
- const float fade_length = light_storage->light_get_distance_fade_length(li->light);
-
- if (distance > fade_begin) {
- if (distance > fade_begin + fade_length) {
- // Out of range, don't draw this light to improve performance.
- continue;
- }
- }
- }
-
- cluster.omni_light_sort[cluster.omni_light_count].instance = li;
- cluster.omni_light_sort[cluster.omni_light_count].depth = distance;
- cluster.omni_light_count++;
- } break;
- case RS::LIGHT_SPOT: {
- if (cluster.spot_light_count >= cluster.max_lights) {
- continue;
- }
-
- const real_t distance = camera_plane.distance_to(li->transform.origin);
-
- if (light_storage->light_is_distance_fade_enabled(li->light)) {
- const float fade_begin = light_storage->light_get_distance_fade_begin(li->light);
- const float fade_length = light_storage->light_get_distance_fade_length(li->light);
-
- if (distance > fade_begin) {
- if (distance > fade_begin + fade_length) {
- // Out of range, don't draw this light to improve performance.
- continue;
- }
- }
- }
-
- cluster.spot_light_sort[cluster.spot_light_count].instance = li;
- cluster.spot_light_sort[cluster.spot_light_count].depth = distance;
- cluster.spot_light_count++;
- } break;
- }
-
- li->last_pass = RSG::rasterizer->get_frame_number();
- }
-
- if (cluster.omni_light_count) {
- SortArray<Cluster::InstanceSort<LightInstance>> sorter;
- sorter.sort(cluster.omni_light_sort, cluster.omni_light_count);
- }
-
- if (cluster.spot_light_count) {
- SortArray<Cluster::InstanceSort<LightInstance>> sorter;
- sorter.sort(cluster.spot_light_sort, cluster.spot_light_count);
- }
-
- ShadowAtlas *shadow_atlas = nullptr;
-
- if (p_shadow_atlas.is_valid() && p_using_shadows) {
- shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- }
-
- bool using_forward_ids = _uses_forward_ids();
-
- for (uint32_t i = 0; i < (cluster.omni_light_count + cluster.spot_light_count); i++) {
- uint32_t index = (i < cluster.omni_light_count) ? i : i - (cluster.omni_light_count);
- Cluster::LightData &light_data = (i < cluster.omni_light_count) ? cluster.omni_lights[index] : cluster.spot_lights[index];
- RS::LightType type = (i < cluster.omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
- LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance;
- RID base = li->light;
-
- if (using_forward_ids) {
- _map_forward_id(type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, li->forward_id, index);
- }
-
- Transform3D light_transform = li->transform;
-
- float sign = light_storage->light_is_negative(base) ? -1 : 1;
- Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
-
- light_data.attenuation = light_storage->light_get_param(base, RS::LIGHT_PARAM_ATTENUATION);
-
- // Reuse fade begin, fade length and distance for shadow LOD determination later.
- float fade_begin = 0.0;
- float fade_shadow = 0.0;
- float fade_length = 0.0;
- real_t distance = 0.0;
-
- float fade = 1.0;
- float shadow_opacity_fade = 1.0;
- if (light_storage->light_is_distance_fade_enabled(li->light)) {
- fade_begin = light_storage->light_get_distance_fade_begin(li->light);
- fade_shadow = light_storage->light_get_distance_fade_shadow(li->light);
- fade_length = light_storage->light_get_distance_fade_length(li->light);
- distance = camera_plane.distance_to(li->transform.origin);
-
- // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
- if (distance > fade_begin) {
- fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
- }
-
- if (distance > fade_shadow) {
- shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length);
- }
- }
-
- float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * fade;
-
- if (is_using_physical_light_units()) {
- energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
-
- // Convert from Luminous Power to Luminous Intensity
- if (type == RS::LIGHT_OMNI) {
- energy *= 1.0 / (Math_PI * 4.0);
- } else {
- // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
- // We make this assumption to keep them easy to control.
- energy *= 1.0 / Math_PI;
- }
- } else {
- energy *= Math_PI;
- }
-
- if (p_render_data->camera_attributes.is_valid()) {
- energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- }
-
- light_data.color[0] = linear_col.r * energy;
- light_data.color[1] = linear_col.g * energy;
- light_data.color[2] = linear_col.b * energy;
- light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
- light_data.volumetric_fog_energy = light_storage->light_get_param(base, RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY);
- light_data.bake_mode = light_storage->light_get_bake_mode(base);
-
- float radius = MAX(0.001, light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
- light_data.inv_radius = 1.0 / radius;
-
- Vector3 pos = inverse_transform.xform(light_transform.origin);
-
- light_data.position[0] = pos.x;
- light_data.position[1] = pos.y;
- light_data.position[2] = pos.z;
-
- Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
-
- light_data.direction[0] = direction.x;
- light_data.direction[1] = direction.y;
- light_data.direction[2] = direction.z;
-
- float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
-
- light_data.size = size;
-
- light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
- float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
- light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle));
-
- light_data.mask = light_storage->light_get_cull_mask(base);
-
- light_data.atlas_rect[0] = 0;
- light_data.atlas_rect[1] = 0;
- light_data.atlas_rect[2] = 0;
- light_data.atlas_rect[3] = 0;
-
- RID projector = light_storage->light_get_projector(base);
-
- if (projector.is_valid()) {
- Rect2 rect = texture_storage->decal_atlas_get_texture_rect(projector);
-
- if (type == RS::LIGHT_SPOT) {
- light_data.projector_rect[0] = rect.position.x;
- light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
- light_data.projector_rect[2] = rect.size.width;
- light_data.projector_rect[3] = -rect.size.height;
- } else {
- light_data.projector_rect[0] = rect.position.x;
- light_data.projector_rect[1] = rect.position.y;
- light_data.projector_rect[2] = rect.size.width;
- light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
- }
- } else {
- light_data.projector_rect[0] = 0;
- light_data.projector_rect[1] = 0;
- light_data.projector_rect[2] = 0;
- light_data.projector_rect[3] = 0;
- }
-
- const bool needs_shadow =
- shadow_atlas &&
- shadow_atlas->shadow_owners.has(li->self) &&
- p_using_shadows &&
- light_storage->light_has_shadow(base);
-
- bool in_shadow_range = true;
- if (needs_shadow && light_storage->light_is_distance_fade_enabled(li->light)) {
- if (distance > light_storage->light_get_distance_fade_shadow(li->light) + light_storage->light_get_distance_fade_length(li->light)) {
- // Out of range, don't draw shadows to improve performance.
- in_shadow_range = false;
- }
- }
-
- if (needs_shadow && in_shadow_range) {
- // fill in the shadow information
-
- light_data.shadow_opacity = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) * shadow_opacity_fade;
-
- float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
- light_data.shadow_normal_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0;
-
- if (type == RS::LIGHT_SPOT) {
- light_data.shadow_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS) / 100.0;
- } else { //omni
- light_data.shadow_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BIAS);
- }
-
- light_data.transmittance_bias = light_storage->light_get_transmittance_bias(base);
-
- Vector2i omni_offset;
- Rect2 rect = light_instance_get_shadow_atlas_rect(li->self, p_shadow_atlas, omni_offset);
-
- light_data.atlas_rect[0] = rect.position.x;
- light_data.atlas_rect[1] = rect.position.y;
- light_data.atlas_rect[2] = rect.size.width;
- light_data.atlas_rect[3] = rect.size.height;
-
- light_data.soft_shadow_scale = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
-
- if (type == RS::LIGHT_OMNI) {
- Transform3D proj = (inverse_transform * light_transform).inverse();
-
- RendererRD::MaterialStorage::store_transform(proj, light_data.shadow_matrix);
-
- if (size > 0.0 && light_data.soft_shadow_scale > 0.0) {
- // Only enable PCSS-like soft shadows if blurring is enabled.
- // Otherwise, performance would decrease with no visual difference.
- light_data.soft_shadow_size = size;
- } else {
- light_data.soft_shadow_size = 0.0;
- light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
- }
-
- light_data.direction[0] = omni_offset.x * float(rect.size.width);
- light_data.direction[1] = omni_offset.y * float(rect.size.height);
- } else if (type == RS::LIGHT_SPOT) {
- Transform3D modelview = (inverse_transform * light_transform).inverse();
- Projection bias;
- bias.set_light_bias();
-
- Projection shadow_mtx = bias * li->shadow_transform[0].camera * modelview;
- RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix);
-
- if (size > 0.0 && light_data.soft_shadow_scale > 0.0) {
- // Only enable PCSS-like soft shadows if blurring is enabled.
- // Otherwise, performance would decrease with no visual difference.
- Projection cm = li->shadow_transform[0].camera;
- float half_np = cm.get_z_near() * Math::tan(Math::deg_to_rad(spot_angle));
- light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
- } else {
- light_data.soft_shadow_size = 0.0;
- light_data.soft_shadow_scale *= shadows_quality_radius_get(); // Only use quality radius for PCF
- }
- }
- } else {
- light_data.shadow_opacity = 0.0;
- }
-
- li->cull_mask = light_storage->light_get_cull_mask(base);
-
- if (current_cluster_builder != nullptr) {
- current_cluster_builder->add_light(type == RS::LIGHT_SPOT ? ClusterBuilderRD::LIGHT_TYPE_SPOT : ClusterBuilderRD::LIGHT_TYPE_OMNI, light_transform, radius, spot_angle);
- }
-
- r_positional_light_count++;
- }
-
- //update without barriers
- if (cluster.omni_light_count) {
- RD::get_singleton()->buffer_update(cluster.omni_light_buffer, 0, sizeof(Cluster::LightData) * cluster.omni_light_count, cluster.omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
- }
-
- if (cluster.spot_light_count) {
- RD::get_singleton()->buffer_update(cluster.spot_light_buffer, 0, sizeof(Cluster::LightData) * cluster.spot_light_count, cluster.spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
- }
-
- if (r_directional_light_count) {
- RD::get_singleton()->buffer_update(cluster.directional_light_buffer, 0, sizeof(Cluster::DirectionalLightData) * r_directional_light_count, cluster.directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
- }
-}
-
-void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
- RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
-
- Transform3D uv_xform;
- uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
- uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
-
- uint32_t decal_count = p_decals.size();
-
- cluster.decal_count = 0;
-
- for (uint32_t i = 0; i < decal_count; i++) {
- if (cluster.decal_count == cluster.max_decals) {
- break;
- }
-
- DecalInstance *di = decal_instance_owner.get_or_null(p_decals[i]);
- if (!di) {
- continue;
- }
- RID decal = di->decal;
-
- Transform3D xform = di->transform;
-
- real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
-
- if (texture_storage->decal_is_distance_fade_enabled(decal)) {
- float fade_begin = texture_storage->decal_get_distance_fade_begin(decal);
- float fade_length = texture_storage->decal_get_distance_fade_length(decal);
-
- if (distance > fade_begin) {
- if (distance > fade_begin + fade_length) {
- continue; // do not use this decal, its invisible
- }
- }
- }
-
- cluster.decal_sort[cluster.decal_count].instance = di;
- cluster.decal_sort[cluster.decal_count].depth = distance;
- cluster.decal_count++;
- }
-
- if (cluster.decal_count > 0) {
- SortArray<Cluster::InstanceSort<DecalInstance>> sort_array;
- sort_array.sort(cluster.decal_sort, cluster.decal_count);
- }
-
- bool using_forward_ids = _uses_forward_ids();
- for (uint32_t i = 0; i < cluster.decal_count; i++) {
- DecalInstance *di = cluster.decal_sort[i].instance;
- RID decal = di->decal;
-
- if (using_forward_ids) {
- _map_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id, i);
- }
-
- di->cull_mask = texture_storage->decal_get_cull_mask(decal);
-
- Transform3D xform = di->transform;
- float fade = 1.0;
-
- if (texture_storage->decal_is_distance_fade_enabled(decal)) {
- const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
- const float fade_begin = texture_storage->decal_get_distance_fade_begin(decal);
- const float fade_length = texture_storage->decal_get_distance_fade_length(decal);
-
- if (distance > fade_begin) {
- // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
- fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
- }
- }
-
- Cluster::DecalData &dd = cluster.decals[i];
-
- Vector3 decal_extents = texture_storage->decal_get_extents(decal);
-
- Transform3D scale_xform;
- scale_xform.basis.scale(decal_extents);
- Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse();
- RendererRD::MaterialStorage::store_transform(to_decal_xform, dd.xform);
-
- Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized();
- normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
-
- dd.normal[0] = normal.x;
- dd.normal[1] = normal.y;
- dd.normal[2] = normal.z;
- dd.normal_fade = texture_storage->decal_get_normal_fade(decal);
-
- RID albedo_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ALBEDO);
- RID emission_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_EMISSION);
- if (albedo_tex.is_valid()) {
- Rect2 rect = texture_storage->decal_atlas_get_texture_rect(albedo_tex);
- dd.albedo_rect[0] = rect.position.x;
- dd.albedo_rect[1] = rect.position.y;
- dd.albedo_rect[2] = rect.size.x;
- dd.albedo_rect[3] = rect.size.y;
- } else {
- if (!emission_tex.is_valid()) {
- continue; //no albedo, no emission, no decal.
- }
- dd.albedo_rect[0] = 0;
- dd.albedo_rect[1] = 0;
- dd.albedo_rect[2] = 0;
- dd.albedo_rect[3] = 0;
- }
-
- RID normal_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_NORMAL);
+ RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_buffers->get_render_target());
+ if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
+ RID vrs_texture = p_render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
- if (normal_tex.is_valid()) {
- Rect2 rect = texture_storage->decal_atlas_get_texture_rect(normal_tex);
- dd.normal_rect[0] = rect.position.x;
- dd.normal_rect[1] = rect.position.y;
- dd.normal_rect[2] = rect.size.x;
- dd.normal_rect[3] = rect.size.y;
+ // We use get_cache_multipass instead of get_cache_multiview because the default behavior is for
+ // our vrs_texture to be used as the VRS attachment. In this particular case we're writing to it
+ // so it needs to be set as our color attachment
- Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
- RendererRD::MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform);
- } else {
- dd.normal_rect[0] = 0;
- dd.normal_rect[1] = 0;
- dd.normal_rect[2] = 0;
- dd.normal_rect[3] = 0;
- }
+ Vector<RID> textures;
+ textures.push_back(vrs_texture);
- RID orm_tex = texture_storage->decal_get_texture(decal, RS::DECAL_TEXTURE_ORM);
- if (orm_tex.is_valid()) {
- Rect2 rect = texture_storage->decal_atlas_get_texture_rect(orm_tex);
- dd.orm_rect[0] = rect.position.x;
- dd.orm_rect[1] = rect.position.y;
- dd.orm_rect[2] = rect.size.x;
- dd.orm_rect[3] = rect.size.y;
- } else {
- dd.orm_rect[0] = 0;
- dd.orm_rect[1] = 0;
- dd.orm_rect[2] = 0;
- dd.orm_rect[3] = 0;
- }
+ Vector<RD::FramebufferPass> passes;
+ RD::FramebufferPass pass;
+ pass.color_attachments.push_back(0);
+ passes.push_back(pass);
- if (emission_tex.is_valid()) {
- Rect2 rect = texture_storage->decal_atlas_get_texture_rect(emission_tex);
- dd.emission_rect[0] = rect.position.x;
- dd.emission_rect[1] = rect.position.y;
- dd.emission_rect[2] = rect.size.x;
- dd.emission_rect[3] = rect.size.y;
- } else {
- dd.emission_rect[0] = 0;
- dd.emission_rect[1] = 0;
- dd.emission_rect[2] = 0;
- dd.emission_rect[3] = 0;
- }
+ RID vrs_fb = FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, p_render_buffers->get_view_count());
- Color modulate = texture_storage->decal_get_modulate(decal);
- dd.modulate[0] = modulate.r;
- dd.modulate[1] = modulate.g;
- dd.modulate[2] = modulate.b;
- dd.modulate[3] = modulate.a * fade;
- dd.emission_energy = texture_storage->decal_get_emission_energy(decal) * fade;
- dd.albedo_mix = texture_storage->decal_get_albedo_mix(decal);
- dd.mask = texture_storage->decal_get_cull_mask(decal);
- dd.upper_fade = texture_storage->decal_get_upper_fade(decal);
- dd.lower_fade = texture_storage->decal_get_lower_fade(decal);
-
- if (current_cluster_builder != nullptr) {
- current_cluster_builder->add_box(ClusterBuilderRD::BOX_TYPE_DECAL, xform, decal_extents);
+ vrs->update_vrs_texture(vrs_fb, p_render_buffers->get_render_target());
}
}
-
- if (cluster.decal_count > 0) {
- RD::get_singleton()->buffer_update(cluster.decal_buffer, 0, sizeof(Cluster::DecalData) * cluster.decal_count, cluster.decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// FOG SHADER
-
-void RendererSceneRenderRD::_update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) {
- ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered
- ERR_FAIL_COND(p_render_buffers.is_null());
-
- // These should be available for our clustered renderer, at some point _update_volumetric_fog should be called by the renderer implemetentation itself
- ERR_FAIL_COND(!p_render_buffers->has_custom_data(RB_SCOPE_GI));
- Ref<RendererRD::GI::RenderBuffersGI> rbgi = p_render_buffers->get_custom_data(RB_SCOPE_GI);
-
- Ref<RendererRD::GI::SDFGI> sdfgi;
- if (p_render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
- sdfgi = p_render_buffers->get_custom_data(RB_SCOPE_SDFGI);
- }
-
- Size2i size = p_render_buffers->get_internal_size();
- float ratio = float(size.x) / float((size.x + size.y) / 2);
- uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio);
- uint32_t target_height = uint32_t(float(volumetric_fog_size) / ratio);
-
- if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
- Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
- //validate
- if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment) || fog->width != target_width || fog->height != target_height || fog->depth != volumetric_fog_depth) {
- p_render_buffers->set_custom_data(RB_SCOPE_FOG, Ref<RenderBufferCustomDataRD>());
- }
- }
-
- if (p_environment.is_null() || !environment_get_volumetric_fog_enabled(p_environment)) {
- //no reason to enable or update, bye
- return;
- }
-
- if (p_environment.is_valid() && environment_get_volumetric_fog_enabled(p_environment) && !p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
- //required volumetric fog but not existing, create
- Ref<RendererRD::Fog::VolumetricFog> fog;
-
- fog.instantiate();
- fog->init(Vector3i(target_width, target_height, volumetric_fog_depth), sky.sky_shader.default_shader_rd);
-
- p_render_buffers->set_custom_data(RB_SCOPE_FOG, fog);
- }
-
- if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
- Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
-
- RendererRD::Fog::VolumetricFogSettings settings;
- settings.rb_size = size;
- settings.time = time;
- settings.is_using_radiance_cubemap_array = is_using_radiance_cubemap_array();
- settings.max_cluster_elements = max_cluster_elements;
- settings.volumetric_fog_filter_active = volumetric_fog_filter_active;
-
- settings.shadow_sampler = shadow_sampler;
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- settings.shadow_atlas_depth = shadow_atlas ? shadow_atlas->depth : RID();
- settings.voxel_gi_buffer = rbgi->get_voxel_gi_buffer();
- settings.omni_light_buffer = get_omni_light_buffer();
- settings.spot_light_buffer = get_spot_light_buffer();
- settings.directional_shadow_depth = directional_shadow.depth;
- settings.directional_light_buffer = get_directional_light_buffer();
-
- settings.vfog = fog;
- settings.cluster_builder = p_render_buffers->cluster_builder;
- settings.rbgi = rbgi;
- settings.sdfgi = sdfgi;
- settings.env = p_environment;
- settings.sky = &sky;
- settings.gi = &gi;
-
- RendererRD::Fog::get_singleton()->volumetric_fog_update(settings, p_cam_projection, p_cam_transform, p_prev_cam_inv_transform, p_shadow_atlas, p_directional_light_count, p_use_directional_shadows, p_positional_light_count, p_voxel_gi_count, p_fog_volumes);
- }
}
bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) {
@@ -2886,175 +1060,8 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo
}
}
-void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
- // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
- RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
-
- if (p_render_data->render_buffers.is_valid() && p_use_gi && p_render_data->render_buffers->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = p_render_data->render_buffers->get_custom_data(RB_SCOPE_SDFGI);
- sdfgi->store_probes();
- }
-
- render_state.cube_shadows.clear();
- render_state.shadows.clear();
- render_state.directional_shadows.clear();
-
- 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);
-
- if (light_storage->light_get_type(li->light) == RS::LIGHT_DIRECTIONAL) {
- render_state.directional_shadows.push_back(i);
- } else if (light_storage->light_get_type(li->light) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(li->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
- render_state.cube_shadows.push_back(i);
- } else {
- render_state.shadows.push_back(i);
- }
- }
-
- //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->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
- }
-
- if (render_state.directional_shadows.size()) {
- //open the pass for directional shadows
- _update_directional_shadow_atlas();
- RD::get_singleton()->draw_list_begin(directional_shadow.fb, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
- RD::get_singleton()->draw_list_end();
- }
- }
-
- // Render GI
-
- bool render_shadows = render_state.directional_shadows.size() || render_state.shadows.size();
- bool render_gi = p_render_data->render_buffers.is_valid() && p_use_gi;
-
- if (render_shadows && render_gi) {
- RENDER_TIMESTAMP("Render GI + Render Shadows (Parallel)");
- } else if (render_shadows) {
- RENDER_TIMESTAMP("Render Shadows");
- } else if (render_gi) {
- RENDER_TIMESTAMP("Render GI");
- }
-
- //prepare shadow rendering
- if (render_shadows) {
- _render_shadow_begin();
-
- //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->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->scene_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
- }
-
- _render_shadow_process();
- }
-
- //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->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
- }
-
- //Do shadow rendering (in parallel with GI)
- if (render_shadows) {
- _render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
- }
-
- if (render_gi) {
- RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
- }
-
- if (p_render_data->render_buffers.is_valid() && ss_effects) {
- if (p_use_ssao || p_use_ssil) {
- Ref<RenderSceneBuffersRD> rb = p_render_data->render_buffers;
- ERR_FAIL_COND(rb.is_null());
- Size2i size = rb->get_internal_size();
-
- bool invalidate_uniform_set = false;
- if (rb->ss_effects.linear_depth.is_null()) {
- RD::TextureFormat tf;
- tf.format = RD::DATA_FORMAT_R16_SFLOAT;
- tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
- tf.width = (size.x + 1) / 2;
- tf.height = (size.y + 1) / 2;
- tf.mipmaps = 5;
- tf.array_layers = 4;
- tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
- rb->ss_effects.linear_depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
- RD::get_singleton()->set_resource_name(rb->ss_effects.linear_depth, "SS Effects Depth");
- for (uint32_t i = 0; i < tf.mipmaps; i++) {
- RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, i, 1, RD::TEXTURE_SLICE_2D_ARRAY);
- rb->ss_effects.linear_depth_slices.push_back(slice);
- RD::get_singleton()->set_resource_name(slice, "SS Effects Depth Mip " + itos(i) + " ");
- }
- invalidate_uniform_set = true;
- }
-
- 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->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->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->scene_data->cam_projection, p_render_data->scene_data->cam_transform);
- }
- }
-
- //full barrier here, we need raster, transfer and compute and it depends from the previous work
- RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
-
- if (current_cluster_builder) {
- 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;
-
- if (p_render_data->reflection_probe.is_valid()) {
- if (!RSG::light_storage->reflection_probe_renders_shadows(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- using_shadows = false;
- }
- } else {
- //do not render reflections when rendering a reflection probe
- _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->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;
-
- if (current_cluster_builder) {
- current_cluster_builder->bake_cluster();
- }
-
- if (p_render_data->render_buffers.is_valid()) {
- bool directional_shadows = false;
- for (uint32_t i = 0; i < directional_light_count; i++) {
- if (cluster.directional_lights[i].shadow_opacity > 0.001) {
- directional_shadows = true;
- break;
- }
- }
- if (is_volumetric_supported()) {
- _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, RenderingMethod::RenderInfo *r_render_info) {
+ RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
// getting this here now so we can direct call a bunch of things more easily
@@ -3092,7 +1099,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
// 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;
@@ -3101,14 +1107,14 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
}
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;
+ int shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
+ scene_data.shadow_atlas_pixel_size.x = 1.0 / shadow_atlas_size;
+ scene_data.shadow_atlas_pixel_size.y = 1.0 / shadow_atlas_size;
}
{
- 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;
+ int directional_shadow_size = light_storage->directional_shadow_get_size();
+ scene_data.directional_shadow_pixel_size.x = 1.0 / directional_shadow_size;
+ scene_data.directional_shadow_pixel_size.y = 1.0 / directional_shadow_size;
}
scene_data.time = time;
@@ -3131,15 +1137,17 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.environment = p_environment;
render_data.camera_attributes = p_camera_attributes;
render_data.shadow_atlas = p_shadow_atlas;
+ render_data.occluder_debug_tex = p_occluder_debug_tex;
render_data.reflection_atlas = p_reflection_atlas;
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
- 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;
- render_state.render_sdfgi_region_count = p_render_sdfgi_region_count;
- render_state.sdfgi_update_data = p_sdfgi_update_data;
+ render_data.render_shadows = p_render_shadows;
+ render_data.render_shadow_count = p_render_shadow_count;
+ render_data.render_sdfgi_regions = p_render_sdfgi_regions;
+ render_data.render_sdfgi_region_count = p_render_sdfgi_region_count;
+ render_data.sdfgi_update_data = p_sdfgi_update_data;
+
render_data.render_info = r_render_info;
}
@@ -3151,22 +1159,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.voxel_gi_instances = &empty;
}
- // 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;
-
- if (p_camera_attributes.is_valid()) {
- exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
- }
- for (int i = 0; i < render_state.render_sdfgi_region_count; i++) {
- sdfgi->render_region(rb, render_state.render_sdfgi_regions[i].region, render_state.render_sdfgi_regions[i].instances, this, exposure_normalization);
- }
- if (render_state.sdfgi_update_data->update_static) {
- sdfgi->render_static_lights(&render_data, rb, render_state.sdfgi_update_data->static_cascade_count, p_sdfgi_update_data->static_cascade_indices, render_state.sdfgi_update_data->static_positional_lights, this);
- }
- }
-
Color clear_color;
if (p_render_buffers.is_valid()) {
clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target());
@@ -3174,297 +1166,8 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
clear_color = RSG::texture_storage->get_default_clear_color();
}
- //assign render indices to voxel_gi_instances
- if (is_dynamic_gi_supported()) {
- for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) {
- gi.voxel_gi_instance_set_render_index(p_voxel_gi_instances[i], i);
- }
- }
-
- if (rb.is_valid()) {
- // render_data.render_buffers == p_render_buffers so we can use our already retrieved rb
- current_cluster_builder = rb->cluster_builder;
- } else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(render_data.reflection_probe);
- ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas);
- if (!ra) {
- ERR_PRINT("reflection probe has no reflection atlas! Bug?");
- current_cluster_builder = nullptr;
- } else {
- current_cluster_builder = ra->cluster_builder;
- }
- if (p_camera_attributes.is_valid()) {
- RendererRD::LightStorage::get_singleton()->reflection_probe_set_baked_exposure(rpi->probe, RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes));
- }
- } else {
- ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash
- current_cluster_builder = nullptr;
- }
-
- render_state.voxel_gi_count = 0;
-
- if (rb.is_valid() && is_dynamic_gi_supported()) {
- if (rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- if (sdfgi.is_valid()) {
- sdfgi->update_cascades();
- sdfgi->pre_process_gi(scene_data.cam_transform, &render_data, this);
- sdfgi->update_light();
- }
- }
-
- 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;
//calls _pre_opaque_render between depth pre-pass and opaque pass
- if (current_cluster_builder != nullptr) {
- render_data.cluster_buffer = current_cluster_builder->get_cluster_buffer();
- render_data.cluster_size = current_cluster_builder->get_cluster_size();
- render_data.cluster_max_elements = current_cluster_builder->get_max_cluster_elements();
- }
-
- if (rb.is_valid() && vrs) {
- RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(rb->get_render_target());
- if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
- RID vrs_texture = rb->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
-
- // We use get_cache_multipass instead of get_cache_multiview because the default behavior is for
- // our vrs_texture to be used as the VRS attachment. In this particular case we're writing to it
- // so it needs to be set as our color attachment
-
- Vector<RID> textures;
- textures.push_back(vrs_texture);
-
- Vector<RD::FramebufferPass> passes;
- RD::FramebufferPass pass;
- pass.color_attachments.push_back(0);
- passes.push_back(pass);
-
- RID vrs_fb = FramebufferCacheRD::get_singleton()->get_cache_multipass(textures, passes, rb->get_view_count());
-
- vrs->update_vrs_texture(vrs_fb, rb->get_render_target());
- }
- }
-
_render_scene(&render_data, clear_color);
-
- if (rb.is_valid()) {
- _render_buffers_debug_draw(rb, p_shadow_atlas, p_occluder_debug_tex);
-
- if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- Vector<RID> view_rids;
-
- // SDFGI renders at internal resolution, need to check if our debug correctly supports outputting upscaled.
- Size2i size = rb->get_internal_size();
- RID source_texture = rb->get_internal_texture();
- for (uint32_t v = 0; v < rb->get_view_count(); v++) {
- view_rids.push_back(rb->get_internal_texture(v));
- }
-
- 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);
- }
- }
-}
-
-void RendererSceneRenderRD::_debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers) {
- if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) {
- RS::ViewportDebugDraw dd = get_debug_draw_mode();
-
- if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) {
- ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX;
- switch (dd) {
- case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS:
- elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT;
- break;
- case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS:
- elem_type = ClusterBuilderRD::ELEMENT_TYPE_SPOT_LIGHT;
- break;
- case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS:
- elem_type = ClusterBuilderRD::ELEMENT_TYPE_DECAL;
- break;
- case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES:
- elem_type = ClusterBuilderRD::ELEMENT_TYPE_REFLECTION_PROBE;
- break;
- default: {
- }
- }
- current_cluster_builder->debug(elem_type);
- }
- }
-}
-
-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 = 1;
- RID atlas_fb;
-
- bool using_dual_paraboloid = false;
- bool using_dual_paraboloid_flip = false;
- Vector2i dual_paraboloid_offset;
- RID render_fb;
- RID render_texture;
- float zfar;
-
- bool use_pancake = false;
- bool render_cubemap = false;
- bool finalize_cubemap = false;
-
- bool flip_y = false;
-
- Projection light_projection;
- Transform3D light_transform;
-
- if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) {
- //set pssm stuff
- if (light_instance->last_scene_shadow_pass != scene_pass) {
- light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
- directional_shadow.current_light++;
- light_instance->last_scene_shadow_pass = scene_pass;
- }
-
- use_pancake = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
- light_projection = light_instance->shadow_transform[p_pass].camera;
- light_transform = light_instance->shadow_transform[p_pass].transform;
-
- atlas_rect = light_instance->directional_rect;
-
- if (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
- atlas_rect.size.width /= 2;
- atlas_rect.size.height /= 2;
-
- if (p_pass == 1) {
- atlas_rect.position.x += atlas_rect.size.width;
- } else if (p_pass == 2) {
- atlas_rect.position.y += atlas_rect.size.height;
- } else if (p_pass == 3) {
- atlas_rect.position += atlas_rect.size;
- }
- } else if (RSG::light_storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
- atlas_rect.size.height /= 2;
-
- if (p_pass == 0) {
- } else {
- atlas_rect.position.y += atlas_rect.size.height;
- }
- }
-
- light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect;
-
- light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size;
- light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size;
-
- zfar = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
-
- render_fb = directional_shadow.fb;
- render_texture = RID();
- flip_y = true;
-
- } else {
- //set from shadow atlas
-
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- ERR_FAIL_COND(!shadow_atlas);
- ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light));
-
- _update_shadow_atlas(shadow_atlas);
-
- uint32_t key = shadow_atlas->shadow_owners[p_light];
-
- uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size());
-
- uint32_t quadrant_size = shadow_atlas->size >> 1;
-
- atlas_rect.position.x = (quadrant & 1) * quadrant_size;
- atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
-
- uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
- atlas_rect.position.x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
- atlas_rect.position.y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-
- atlas_rect.size.width = shadow_size;
- atlas_rect.size.height = shadow_size;
-
- zfar = RSG::light_storage->light_get_param(light_instance->light, RS::LIGHT_PARAM_RANGE);
-
- if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_OMNI) {
- bool wrap = (shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision == 0;
- dual_paraboloid_offset = wrap ? Vector2i(1 - shadow_atlas->quadrants[quadrant].subdivision, 1) : Vector2i(1, 0);
-
- if (RSG::light_storage->light_omni_get_shadow_mode(light_instance->light) == RS::LIGHT_OMNI_SHADOW_CUBE) {
- ShadowCubemap *cubemap = _get_shadow_cubemap(shadow_size / 2);
-
- render_fb = cubemap->side_fb[p_pass];
- render_texture = cubemap->cubemap;
-
- light_projection = light_instance->shadow_transform[p_pass].camera;
- light_transform = light_instance->shadow_transform[p_pass].transform;
- render_cubemap = true;
- finalize_cubemap = p_pass == 5;
- atlas_fb = shadow_atlas->fb;
-
- atlas_size = shadow_atlas->size;
-
- if (p_pass == 0) {
- _render_shadow_begin();
- }
-
- } else {
- atlas_rect.position.x += 1;
- atlas_rect.position.y += 1;
- atlas_rect.size.x -= 2;
- atlas_rect.size.y -= 2;
-
- atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
-
- light_projection = light_instance->shadow_transform[0].camera;
- light_transform = light_instance->shadow_transform[0].transform;
-
- using_dual_paraboloid = true;
- using_dual_paraboloid_flip = p_pass == 1;
- render_fb = shadow_atlas->fb;
- flip_y = true;
- }
-
- } else if (RSG::light_storage->light_get_type(light_instance->light) == RS::LIGHT_SPOT) {
- light_projection = light_instance->shadow_transform[0].camera;
- light_transform = light_instance->shadow_transform[0].transform;
-
- render_fb = shadow_atlas->fb;
-
- flip_y = true;
- }
- }
-
- if (render_cubemap) {
- //rendering to cubemap
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
- if (finalize_cubemap) {
- _render_shadow_process();
- _render_shadow_end();
- //reblit
- Rect2 atlas_rect_norm = atlas_rect;
- atlas_rect_norm.position /= float(atlas_size);
- atlas_rect_norm.size /= float(atlas_size);
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
- atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
- copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
-
- //restore transform so it can be properly used
- light_instance_set_shadow_transform(p_light, Projection(), light_instance->transform, zfar, 0, 0, 0);
- }
-
- } else {
- //render shadow
- _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
- }
}
void RendererSceneRenderRD::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) {
@@ -3495,58 +1198,11 @@ bool RendererSceneRenderRD::free(RID p_rid) {
environment_free(p_rid);
} else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
RSG::camera_attributes->camera_attributes_free(p_rid);
- } else if (reflection_atlas_owner.owns(p_rid)) {
- reflection_atlas_set_size(p_rid, 0, 0);
- ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_rid);
- if (ra->cluster_builder) {
- memdelete(ra->cluster_builder);
- }
- reflection_atlas_owner.free(p_rid);
- } else if (reflection_probe_instance_owner.owns(p_rid)) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_rid);
- _free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id);
- reflection_probe_release_atlas_index(p_rid);
- reflection_probe_instance_owner.free(p_rid);
- } else if (decal_instance_owner.owns(p_rid)) {
- DecalInstance *di = decal_instance_owner.get_or_null(p_rid);
- _free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id);
- decal_instance_owner.free(p_rid);
- } else if (lightmap_instance_owner.owns(p_rid)) {
- lightmap_instance_owner.free(p_rid);
} else if (gi.voxel_gi_instance_owns(p_rid)) {
gi.voxel_gi_instance_free(p_rid);
} else if (sky.sky_owner.owns(p_rid)) {
sky.update_dirty_skys();
sky.free_sky(p_rid);
- } else if (light_instance_owner.owns(p_rid)) {
- LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
-
- //remove from shadow atlases..
- for (const RID &E : light_instance->shadow_atlases) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E);
- ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid));
- uint32_t key = shadow_atlas->shadow_owners[p_rid];
- uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
-
- if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
- // Omni lights use two atlas spots, make sure to clear the other as well
- shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID();
- }
-
- shadow_atlas->shadow_owners.erase(p_rid);
- }
-
- if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
- _free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id);
- }
- light_instance_owner.free(p_rid);
-
- } else if (shadow_atlas_owner.owns(p_rid)) {
- shadow_atlas_set_size(p_rid, 0);
- shadow_atlas_owner.free(p_rid);
} else if (RendererRD::Fog::get_singleton()->owns_fog_volume_instance(p_rid)) {
RendererRD::Fog::get_singleton()->fog_instance_free(p_rid);
} else {
@@ -3620,8 +1276,8 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Typed
//RID sampled_light;
- RenderGeometryInstance *gi = geometry_instance_create(p_base);
- ERR_FAIL_NULL_V(gi, TypedArray<Image>());
+ RenderGeometryInstance *gi_inst = geometry_instance_create(p_base);
+ ERR_FAIL_NULL_V(gi_inst, TypedArray<Image>());
uint32_t sc = RSG::mesh_storage->mesh_get_surface_count(p_base);
Vector<RID> materials;
@@ -3633,50 +1289,42 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Typed
}
}
- gi->set_surface_materials(materials);
+ gi_inst->set_surface_materials(materials);
if (cull_argument.size() == 0) {
cull_argument.push_back(nullptr);
}
- cull_argument[0] = gi;
+ cull_argument[0] = gi_inst;
_render_uv2(cull_argument, fb, Rect2i(0, 0, p_image_size.width, p_image_size.height));
- geometry_instance_free(gi);
+ geometry_instance_free(gi_inst);
TypedArray<Image> ret;
{
PackedByteArray data = RD::get_singleton()->texture_get_data(albedo_alpha_tex, 0);
- Ref<Image> img;
- img.instantiate();
- img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
+ Ref<Image> img = Image::create_from_data(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(albedo_alpha_tex);
ret.push_back(img);
}
{
PackedByteArray data = RD::get_singleton()->texture_get_data(normal_tex, 0);
- Ref<Image> img;
- img.instantiate();
- img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
+ Ref<Image> img = Image::create_from_data(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(normal_tex);
ret.push_back(img);
}
{
PackedByteArray data = RD::get_singleton()->texture_get_data(orm_tex, 0);
- Ref<Image> img;
- img.instantiate();
- img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
+ Ref<Image> img = Image::create_from_data(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data);
RD::get_singleton()->free(orm_tex);
ret.push_back(img);
}
{
PackedByteArray data = RD::get_singleton()->texture_get_data(emission_tex, 0);
- Ref<Image> img;
- img.instantiate();
- img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBAH, data);
+ Ref<Image> img = Image::create_from_data(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBAH, data);
RD::get_singleton()->free(emission_tex);
ret.push_back(img);
}
@@ -3694,27 +1342,6 @@ void RendererSceneRenderRD::sdfgi_set_debug_probe_select(const Vector3 &p_positi
RendererSceneRenderRD *RendererSceneRenderRD::singleton = nullptr;
-RID RendererSceneRenderRD::get_reflection_probe_buffer() {
- return cluster.reflection_buffer;
-}
-RID RendererSceneRenderRD::get_omni_light_buffer() {
- return cluster.omni_light_buffer;
-}
-
-RID RendererSceneRenderRD::get_spot_light_buffer() {
- return cluster.spot_light_buffer;
-}
-
-RID RendererSceneRenderRD::get_directional_light_buffer() {
- return cluster.directional_light_buffer;
-}
-RID RendererSceneRenderRD::get_decal_buffer() {
- return cluster.decal_buffer;
-}
-int RendererSceneRenderRD::get_max_directional_lights() const {
- return cluster.max_directional_lights;
-}
-
bool RendererSceneRenderRD::is_vrs_supported() const {
return RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS);
}
@@ -3724,11 +1351,6 @@ bool RendererSceneRenderRD::is_dynamic_gi_supported() const {
return true;
}
-bool RendererSceneRenderRD::is_clustered_enabled() const {
- // used by default.
- return true;
-}
-
bool RendererSceneRenderRD::is_volumetric_supported() const {
// usable by default (unless low end = true)
return true;
@@ -3744,9 +1366,10 @@ RendererSceneRenderRD::RendererSceneRenderRD() {
void RendererSceneRenderRD::init() {
max_cluster_elements = get_max_elements();
+ RendererRD::LightStorage::get_singleton()->set_max_cluster_elements(max_cluster_elements);
- directional_shadow.size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size");
- directional_shadow.use_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
+ /* Forward ID */
+ forward_id_storage = create_forward_id_storage();
/* SKY SHADER */
@@ -3759,68 +1382,25 @@ void RendererSceneRenderRD::init() {
}
{ //decals
- cluster.max_decals = max_cluster_elements;
- uint32_t decal_buffer_size = cluster.max_decals * sizeof(Cluster::DecalData);
- cluster.decals = memnew_arr(Cluster::DecalData, cluster.max_decals);
- cluster.decal_sort = memnew_arr(Cluster::InstanceSort<DecalInstance>, cluster.max_decals);
- cluster.decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
- }
-
- { //reflections
-
- cluster.max_reflections = max_cluster_elements;
- cluster.reflections = memnew_arr(Cluster::ReflectionData, cluster.max_reflections);
- cluster.reflection_sort = memnew_arr(Cluster::InstanceSort<ReflectionProbeInstance>, cluster.max_reflections);
- cluster.reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(Cluster::ReflectionData) * cluster.max_reflections);
+ RendererRD::TextureStorage::get_singleton()->set_max_decals(max_cluster_elements);
}
{ //lights
- cluster.max_lights = max_cluster_elements;
-
- uint32_t light_buffer_size = cluster.max_lights * sizeof(Cluster::LightData);
- cluster.omni_lights = memnew_arr(Cluster::LightData, cluster.max_lights);
- cluster.omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
- cluster.omni_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights);
- cluster.spot_lights = memnew_arr(Cluster::LightData, cluster.max_lights);
- cluster.spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
- cluster.spot_light_sort = memnew_arr(Cluster::InstanceSort<LightInstance>, cluster.max_lights);
- //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(cluster.max_lights) + "\n";
-
- cluster.max_directional_lights = MAX_DIRECTIONAL_LIGHTS;
- uint32_t directional_light_buffer_size = cluster.max_directional_lights * sizeof(Cluster::DirectionalLightData);
- cluster.directional_lights = memnew_arr(Cluster::DirectionalLightData, cluster.max_directional_lights);
- cluster.directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
}
if (is_volumetric_supported()) {
- RendererRD::Fog::get_singleton()->init_fog_shader(cluster.max_directional_lights, get_roughness_layers(), is_using_radiance_cubemap_array());
- }
-
- {
- RD::SamplerState sampler;
- sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
- sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
- shadow_sampler = RD::get_singleton()->sampler_create(sampler);
+ RendererRD::Fog::get_singleton()->init_fog_shader(RendererRD::LightStorage::get_singleton()->get_max_directional_lights(), get_roughness_layers(), is_using_radiance_cubemap_array());
}
RSG::camera_attributes->camera_attributes_set_dof_blur_bokeh_shape(RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape"))));
RSG::camera_attributes->camera_attributes_set_dof_blur_quality(RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))), GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"));
use_physical_light_units = GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units");
- environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
screen_space_roughness_limiter = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled");
screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount");
screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit");
glow_bicubic_upscale = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality");
- ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
- sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
- sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
- sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
-
- environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to"));
directional_penumbra_shadow_kernel = memnew_arr(float, 128);
directional_soft_shadow_kernel = memnew_arr(float, 128);
@@ -3844,11 +1424,14 @@ void RendererSceneRenderRD::init() {
vrs = memnew(RendererRD::VRS);
if (can_use_storage) {
fsr = memnew(RendererRD::FSR);
- ss_effects = memnew(RendererRD::SSEffects);
}
}
RendererSceneRenderRD::~RendererSceneRenderRD() {
+ if (forward_id_storage) {
+ memdelete(forward_id_storage);
+ }
+
if (bokeh_dof) {
memdelete(bokeh_dof);
}
@@ -3864,13 +1447,6 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
if (fsr) {
memdelete(fsr);
}
- if (ss_effects) {
- memdelete(ss_effects);
- }
-
- for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) {
- RD::get_singleton()->free(E.value.cubemap);
- }
if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) {
RD::get_singleton()->free(sky.sky_scene_state.uniform_set);
@@ -3889,25 +1465,6 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
memdelete_arr(penumbra_shadow_kernel);
memdelete_arr(soft_shadow_kernel);
- {
- RD::get_singleton()->free(cluster.directional_light_buffer);
- RD::get_singleton()->free(cluster.omni_light_buffer);
- RD::get_singleton()->free(cluster.spot_light_buffer);
- RD::get_singleton()->free(cluster.reflection_buffer);
- RD::get_singleton()->free(cluster.decal_buffer);
- memdelete_arr(cluster.directional_lights);
- memdelete_arr(cluster.omni_lights);
- memdelete_arr(cluster.spot_lights);
- memdelete_arr(cluster.omni_light_sort);
- memdelete_arr(cluster.spot_light_sort);
- memdelete_arr(cluster.reflections);
- memdelete_arr(cluster.reflection_sort);
- memdelete_arr(cluster.decals);
- memdelete_arr(cluster.decal_sort);
- }
-
- RD::get_singleton()->free(shadow_sampler);
-
- directional_shadow_atlas_set_size(0);
+ RSG::light_storage->directional_shadow_atlas_set_size(0);
cull_argument.reset(); //avoid exit error
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 82dc2fd09f..2312603829 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -38,19 +38,21 @@
#include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/effects/fsr.h"
-#include "servers/rendering/renderer_rd/effects/ss_effects.h"
#include "servers/rendering/renderer_rd/effects/tone_mapper.h"
#include "servers/rendering/renderer_rd/effects/vrs.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/environment/gi.h"
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.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"
+// For RenderDataRD, possibly inherited from RefCounted and add proper getters for our implementation classes
+
struct RenderDataRD {
Ref<RenderSceneBuffersRD> render_buffers;
RenderSceneDataRD *scene_data;
@@ -65,6 +67,7 @@ struct RenderDataRD {
RID environment;
RID camera_attributes;
RID shadow_atlas;
+ RID occluder_debug_tex;
RID reflection_atlas;
RID reflection_probe;
int reflection_probe_pass = 0;
@@ -77,6 +80,21 @@ struct RenderDataRD {
bool directional_light_soft_shadows = false;
RenderingMethod::RenderInfo *render_info = nullptr;
+
+ /* Shadow data */
+ const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
+ int render_shadow_count = 0;
+
+ LocalVector<int> cube_shadows;
+ LocalVector<int> shadows;
+ LocalVector<int> directional_shadows;
+
+ /* GI info */
+ const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr;
+ int render_sdfgi_region_count = 0;
+ const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
+
+ uint32_t voxel_gi_count = 0;
};
class RendererSceneRenderRD : public RendererSceneRender {
@@ -84,6 +102,7 @@ class RendererSceneRenderRD : public RendererSceneRender {
friend RendererRD::GI;
protected:
+ RendererRD::ForwardIDStorage *forward_id_storage = nullptr;
RendererRD::BokehDOF *bokeh_dof = nullptr;
RendererRD::CopyEffects *copy_effects = nullptr;
RendererRD::ToneMapper *tone_mapper = nullptr;
@@ -92,18 +111,23 @@ protected:
double time = 0.0;
double time_step = 0.0;
- virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
+ /* ENVIRONMENT */
- void _setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
- void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
- void _setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
+ bool glow_bicubic_upscale = false;
+ bool glow_high_quality = false;
- virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
+ bool use_physical_light_units = false;
+
+ ////////////////////////////////
+
+ virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); };
- 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, 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;
+ void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers);
+
+ virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
+
+ virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
+ virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
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, float p_exposure_normalization) = 0;
virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
@@ -111,25 +135,14 @@ protected:
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
- void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
- virtual void _base_uniforms_changed() = 0;
virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
- void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
- void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
- void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
- void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
-
- void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
-
bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
- void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
-
void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
@@ -140,26 +153,8 @@ protected:
PagedArrayPool<RenderGeometryInstance *> cull_argument_pool;
PagedArray<RenderGeometryInstance *> cull_argument; //need this to exist
- RendererRD::SSEffects *ss_effects = nullptr;
- RendererRD::GI gi;
RendererRD::SkyRD sky;
-
- //used for mobile renderer mostly
-
- typedef int32_t ForwardID;
-
- enum ForwardIDType {
- FORWARD_ID_TYPE_OMNI_LIGHT,
- FORWARD_ID_TYPE_SPOT_LIGHT,
- FORWARD_ID_TYPE_REFLECTION_PROBE,
- FORWARD_ID_TYPE_DECAL,
- FORWARD_ID_MAX,
- };
-
- virtual ForwardID _allocate_forward_id(ForwardIDType p_type) { return -1; }
- virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) {}
- virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {}
- virtual bool _uses_forward_ids() const { return false; }
+ RendererRD::GI gi;
virtual void _update_shader_quality_settings() {}
@@ -167,125 +162,7 @@ private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
static RendererSceneRenderRD *singleton;
- /* REFLECTION ATLAS */
-
- struct ReflectionAtlas {
- int count = 0;
- int size = 0;
-
- RID reflection;
- RID depth_buffer;
- RID depth_fb;
-
- struct Reflection {
- RID owner;
- RendererRD::SkyRD::ReflectionData data;
- RID fbs[6];
- };
-
- Vector<Reflection> reflections;
-
- ClusterBuilderRD *cluster_builder = nullptr;
- };
-
- mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
-
- /* REFLECTION PROBE INSTANCE */
-
- struct ReflectionProbeInstance {
- RID probe;
- int atlas_index = -1;
- RID atlas;
-
- bool dirty = true;
- bool rendering = false;
- int processing_layer = 1;
- int processing_side = 0;
-
- uint32_t render_step = 0;
- uint64_t last_pass = 0;
- uint32_t cull_mask = 0;
-
- ForwardID forward_id = -1;
-
- Transform3D transform;
- };
-
- mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
-
- /* DECAL INSTANCE */
-
- struct DecalInstance {
- RID decal;
- Transform3D transform;
- uint32_t cull_mask = 0;
- ForwardID forward_id = -1;
- };
-
- mutable RID_Owner<DecalInstance> decal_instance_owner;
-
- /* LIGHTMAP INSTANCE */
-
- struct LightmapInstance {
- RID lightmap;
- Transform3D transform;
- };
-
- mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
-
- /* SHADOW ATLAS */
-
- struct ShadowShrinkStage {
- RID texture;
- RID filter_texture;
- uint32_t size = 0;
- };
-
- struct ShadowAtlas {
- enum {
- QUADRANT_SHIFT = 27,
- OMNI_LIGHT_FLAG = 1 << 26,
- SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
- SHADOW_INVALID = 0xFFFFFFFF
- };
-
- struct Quadrant {
- uint32_t subdivision = 0;
-
- struct Shadow {
- RID owner;
- uint64_t version = 0;
- uint64_t fog_version = 0; // used for fog
- uint64_t alloc_tick = 0;
-
- Shadow() {}
- };
-
- Vector<Shadow> shadows;
-
- Quadrant() {}
- } quadrants[4];
-
- int size_order[4] = { 0, 1, 2, 3 };
- uint32_t smallest_subdiv = 0;
-
- int size = 0;
- bool use_16_bits = true;
-
- RID depth;
- RID fb; //for copying
-
- HashMap<RID, uint32_t> shadow_owners;
- };
-
- RID_Owner<ShadowAtlas> shadow_atlas_owner;
-
- void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
-
- void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
- bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
- bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
-
+ /* Shadow atlas */
RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
float shadows_quality_radius = 1.0;
@@ -302,299 +179,36 @@ private:
RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS;
RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS;
- /* DIRECTIONAL SHADOW */
-
- struct DirectionalShadow {
- RID depth;
- RID fb; //when renderign direct
-
- int light_count = 0;
- int size = 0;
- bool use_16_bits = true;
- int current_light = 0;
- } directional_shadow;
-
- void _update_directional_shadow_atlas();
-
- /* SHADOW CUBEMAPS */
-
- struct ShadowCubemap {
- RID cubemap;
- RID side_fb[6];
- };
-
- HashMap<int, ShadowCubemap> shadow_cubemaps;
- ShadowCubemap *_get_shadow_cubemap(int p_size);
-
- void _create_shadow_cubemaps();
-
- /* LIGHT INSTANCE */
-
- struct LightInstance {
- struct ShadowTransform {
- Projection camera;
- Transform3D transform;
- float farplane;
- float split;
- float bias_scale;
- float shadow_texel_size;
- float range_begin;
- Rect2 atlas_rect;
- Vector2 uv_scale;
- };
-
- RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
-
- ShadowTransform shadow_transform[6];
-
- AABB aabb;
- RID self;
- RID light;
- Transform3D transform;
-
- Vector3 light_vector;
- Vector3 spot_vector;
- float linear_att = 0.0;
-
- uint64_t shadow_pass = 0;
- uint64_t last_scene_pass = 0;
- uint64_t last_scene_shadow_pass = 0;
- uint64_t last_pass = 0;
- uint32_t cull_mask = 0;
- uint32_t light_directional_index = 0;
-
- Rect2 directional_rect;
-
- HashSet<RID> shadow_atlases; //shadow atlases where this light is registered
-
- ForwardID forward_id = -1;
-
- LightInstance() {}
- };
-
- mutable RID_Owner<LightInstance> light_instance_owner;
-
- /* ENVIRONMENT */
-
- RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
- bool ssao_half_size = false;
- float ssao_adaptive_target = 0.5;
- int ssao_blur_passes = 2;
- float ssao_fadeout_from = 50.0;
- float ssao_fadeout_to = 300.0;
-
- RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
- bool ssil_half_size = false;
- bool ssil_using_half_size = false;
- float ssil_adaptive_target = 0.5;
- int ssil_blur_passes = 4;
- float ssil_fadeout_from = 50.0;
- float ssil_fadeout_to = 300.0;
-
- bool glow_bicubic_upscale = false;
- bool glow_high_quality = false;
- RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
-
- RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
- float sss_scale = 0.05;
- float sss_depth_scale = 0.01;
-
- bool use_physical_light_units = false;
-
- /* Cluster builder */
-
- ClusterBuilderSharedDataRD cluster_builder_shared;
- ClusterBuilderRD *current_cluster_builder = nullptr;
-
/* RENDER BUFFERS */
+ // TODO move into effects/luminance.h/cpp
void _allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb);
- void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
-
/* GI */
bool screen_space_roughness_limiter = false;
float screen_space_roughness_limiter_amount = 0.25;
float screen_space_roughness_limiter_limit = 0.18;
- /* Cluster */
-
- struct Cluster {
- /* Scene State UBO */
-
- // !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate
-
- enum {
- REFLECTION_AMBIENT_DISABLED = 0,
- REFLECTION_AMBIENT_ENVIRONMENT = 1,
- REFLECTION_AMBIENT_COLOR = 2,
- };
-
- struct ReflectionData {
- float box_extents[3];
- float index;
- float box_offset[3];
- uint32_t mask;
- float ambient[3]; // ambient color,
- float intensity;
- uint32_t exterior;
- uint32_t box_project;
- uint32_t ambient_mode;
- float exposure_normalization;
- float local_matrix[16]; // up to here for spot and omni, rest is for directional
- };
-
- struct LightData {
- float position[3];
- float inv_radius;
- float direction[3]; // in omni, x and y are used for dual paraboloid offset
- float size;
-
- float color[3];
- float attenuation;
-
- float inv_spot_attenuation;
- float cos_spot_angle;
- float specular_amount;
- float shadow_opacity;
-
- float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
- float shadow_matrix[16];
- float shadow_bias;
- float shadow_normal_bias;
- float transmittance_bias;
- float soft_shadow_size;
- float soft_shadow_scale;
- uint32_t mask;
- float volumetric_fog_energy;
- uint32_t bake_mode;
- float projector_rect[4];
- };
-
- struct DirectionalLightData {
- float direction[3];
- float energy;
- float color[3];
- float size;
- float specular;
- uint32_t mask;
- float softshadow_angle;
- float soft_shadow_scale;
- uint32_t blend_splits;
- float shadow_opacity;
- float fade_from;
- float fade_to;
- uint32_t pad[2];
- uint32_t bake_mode;
- float volumetric_fog_energy;
- float shadow_bias[4];
- float shadow_normal_bias[4];
- float shadow_transmittance_bias[4];
- float shadow_z_range[4];
- float shadow_range_begin[4];
- float shadow_split_offsets[4];
- float shadow_matrices[4][16];
- float uv_scale1[2];
- float uv_scale2[2];
- float uv_scale3[2];
- float uv_scale4[2];
- };
-
- struct DecalData {
- float xform[16];
- float inv_extents[3];
- float albedo_mix;
- float albedo_rect[4];
- float normal_rect[4];
- float orm_rect[4];
- float emission_rect[4];
- float modulate[4];
- float emission_energy;
- uint32_t mask;
- float upper_fade;
- float lower_fade;
- float normal_xform[12];
- float normal[3];
- float normal_fade;
- };
-
- template <class T>
- struct InstanceSort {
- float depth;
- T *instance = nullptr;
- bool operator<(const InstanceSort &p_sort) const {
- return depth < p_sort.depth;
- }
- };
-
- ReflectionData *reflections = nullptr;
- InstanceSort<ReflectionProbeInstance> *reflection_sort;
- uint32_t max_reflections;
- RID reflection_buffer;
- uint32_t max_reflection_probes_per_instance;
- uint32_t reflection_count = 0;
-
- DecalData *decals = nullptr;
- InstanceSort<DecalInstance> *decal_sort;
- uint32_t max_decals;
- RID decal_buffer;
- uint32_t decal_count;
-
- LightData *omni_lights = nullptr;
- LightData *spot_lights = nullptr;
-
- InstanceSort<LightInstance> *omni_light_sort;
- InstanceSort<LightInstance> *spot_light_sort;
- uint32_t max_lights;
- RID omni_light_buffer;
- RID spot_light_buffer;
- uint32_t omni_light_count = 0;
- uint32_t spot_light_count = 0;
-
- DirectionalLightData *directional_lights = nullptr;
- uint32_t max_directional_lights;
- RID directional_light_buffer;
-
- } cluster;
-
- struct RenderState {
- const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
- int render_shadow_count = 0;
- const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr;
- int render_sdfgi_region_count = 0;
- const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
-
- uint32_t voxel_gi_count = 0;
-
- LocalVector<int> cube_shadows;
- LocalVector<int> shadows;
- LocalVector<int> directional_shadows;
-
- bool depth_prepass_used; // this does not seem used anywhere...
- } render_state;
-
- RID shadow_sampler;
+ /* Light data */
uint64_t scene_pass = 0;
- uint64_t shadow_atlas_realloc_tolerance_msec = 500;
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, RenderingMethod::RenderInfo *p_render_info = nullptr);
-
/* Volumetric Fog */
uint32_t volumetric_fog_size = 128;
uint32_t volumetric_fog_depth = 128;
bool volumetric_fog_filter_active = true;
- void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
-
public:
static RendererSceneRenderRD *get_singleton() { return singleton; }
- /* Cluster builder */
- ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+ /* LIGHTING */
+
+ virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents){};
+ virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture){};
+ virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents){};
/* GI */
@@ -604,42 +218,6 @@ public:
RendererRD::SkyRD *get_sky() { return &sky; }
- /* SHADOW ATLAS API */
-
- virtual RID shadow_atlas_create() override;
- virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
- virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
- virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
- _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
- ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, false);
- return atlas->shadow_owners.has(p_light_intance);
- }
-
- _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->depth;
- }
-
- _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) {
- ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
- ERR_FAIL_COND_V(!atlas, Size2i());
- return Size2(atlas->size, atlas->size);
- }
-
- virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
- virtual int get_directional_light_shadow_size(RID p_light_intance) override;
- virtual void set_directional_shadow_count(int p_count) override;
-
- _FORCE_INLINE_ RID directional_shadow_get_texture() {
- return directional_shadow.depth;
- }
-
- _FORCE_INLINE_ Size2i directional_shadow_get_size() {
- return Size2i(directional_shadow.size, directional_shadow.size);
- }
-
/* SDFGI UPDATE */
virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
@@ -666,266 +244,32 @@ public:
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override;
- virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
-
- virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
-
virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override;
virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override;
virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override;
- virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
- RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const;
-
virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
_FORCE_INLINE_ bool is_using_physical_light_units() {
return use_physical_light_units;
}
- /* LIGHT INSTANCE API */
-
- virtual RID light_instance_create(RID p_light) override;
- virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
- virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
- virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
- virtual void light_instance_mark_visible(RID p_light_instance) override;
-
- _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->light;
- }
-
- _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->transform;
- }
-
- _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- uint32_t key = shadow_atlas->shadow_owners[li->self];
-
- uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
- uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
- ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
-
- uint32_t atlas_size = shadow_atlas->size;
- uint32_t quadrant_size = atlas_size >> 1;
-
- uint32_t x = (quadrant & 1) * quadrant_size;
- uint32_t y = (quadrant >> 1) * quadrant_size;
-
- uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
- x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
- y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-
- if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
- if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
- r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
- r_omni_offset.y = 1;
- } else {
- r_omni_offset.x = 1;
- r_omni_offset.y = 0;
- }
- }
-
- uint32_t width = shadow_size;
- uint32_t height = shadow_size;
-
- return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
- }
-
- _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].camera;
- }
-
- _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
-#ifdef DEBUG_ENABLED
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
-#endif
- ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
- ERR_FAIL_COND_V(!shadow_atlas, 0);
-#ifdef DEBUG_ENABLED
- ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
-#endif
- uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
-
- uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
-
- uint32_t quadrant_size = shadow_atlas->size >> 1;
-
- uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
-
- return float(1.0) / shadow_size;
- }
-
- _FORCE_INLINE_ Transform3D
- light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].transform;
- }
- _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].bias_scale;
- }
- _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].farplane;
- }
- _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].range_begin;
- }
-
- _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].uv_scale;
- }
-
- _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].atlas_rect;
- }
-
- _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].split;
- }
-
- _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->shadow_transform[p_index].shadow_texel_size;
- }
-
- _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- li->last_pass = p_pass;
- }
-
- _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->last_pass;
- }
-
- _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->forward_id;
- }
+ /* REFLECTION PROBE */
- _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
- LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
- return li->light_type;
- }
+ virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
/* FOG VOLUMES */
+ uint32_t get_volumetric_fog_size() const { return volumetric_fog_size; }
+ uint32_t get_volumetric_fog_depth() const { return volumetric_fog_depth; }
+ bool get_volumetric_fog_filter_active() const { return volumetric_fog_filter_active; }
+
virtual RID fog_volume_instance_create(RID p_fog_volume) override;
virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
- virtual RID reflection_atlas_create() override;
- virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
- virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
-
- _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
- ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
- ERR_FAIL_COND_V(!atlas, RID());
- return atlas->reflection;
- }
-
- virtual RID reflection_probe_instance_create(RID p_probe) override;
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
- virtual void reflection_probe_release_atlas_index(RID p_instance) override;
- virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
- virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
- virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
- virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
- virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
-
- uint32_t reflection_probe_instance_get_resolution(RID p_instance);
- RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
- RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
-
- _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, RID());
-
- return rpi->probe;
- }
-
- _FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- return rpi->forward_id;
- }
-
- _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND(!rpi);
- rpi->last_pass = p_render_pass;
- }
-
- _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, 0);
-
- return rpi->last_pass;
- }
-
- _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, Transform3D());
-
- return rpi->transform;
- }
-
- _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
- ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
- ERR_FAIL_COND_V(!rpi, -1);
-
- return rpi->atlas_index;
- }
-
- virtual RID decal_instance_create(RID p_decal) override;
- virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
-
- _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const {
- DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
- return decal->decal;
- }
-
- _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const {
- DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
- return decal->forward_id;
- }
-
- _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const {
- DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
- return decal->transform;
- }
-
- virtual RID lightmap_instance_create(RID p_lightmap) override;
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
- _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
- return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr;
- }
-
- _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) {
- LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
- return li->lightmap;
- }
- _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
- LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
- return li->transform;
- }
-
/* gi light probes */
virtual RID voxel_gi_instance_create(RID p_base) override;
@@ -944,6 +288,7 @@ public:
RID render_buffers_get_default_voxel_gi_buffer();
+ virtual void base_uniforms_changed() = 0;
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, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
@@ -964,10 +309,6 @@ public:
virtual float screen_space_roughness_limiter_get_amount() const;
virtual float screen_space_roughness_limiter_get_limit() const;
- virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
- RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const;
- virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
-
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
@@ -1036,18 +377,10 @@ public:
virtual void set_time(double p_time, double p_step) override;
- RID get_reflection_probe_buffer();
- RID get_omni_light_buffer();
- RID get_spot_light_buffer();
- RID get_directional_light_buffer();
- RID get_decal_buffer();
- int get_max_directional_lights() const;
-
virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
virtual bool is_vrs_supported() const;
virtual bool is_dynamic_gi_supported() const;
- virtual bool is_clustered_enabled() const;
virtual bool is_volumetric_supported() const;
virtual uint32_t get_max_elements() const;
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index 0f2dea6fe9..5e9eadadd9 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -180,6 +180,7 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
builder.append("#define MOLTENVK_USED\n");
#endif
+ builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n");
} break;
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 45dc63aa17..8593e6b265 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -598,13 +598,11 @@ void main() {
normal = normalize((canvas_data.canvas_normal_transform * vec4(normal, 0.0)).xyz);
}
- vec3 base_color = color.rgb;
+ vec4 base_color = color;
if (bool(draw_data.flags & FLAGS_USING_LIGHT_MASK)) {
color = vec4(0.0); //invisible by default due to using light mask
}
- vec4 original_color = color;
-
#ifdef MODE_LIGHT_ONLY
color = vec4(0.0);
#elif !defined(MODE_UNSHADED)
@@ -624,12 +622,14 @@ void main() {
#ifdef LIGHT_CODE_USED
vec4 shadow_modulate = vec4(1.0);
- light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, true);
+ light_color = light_compute(light_vertex, vec3(direction, light_array.data[light_base].height), normal, light_color, light_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, true);
#else
if (normal_used) {
vec3 light_vec = normalize(mix(vec3(direction, 0.0), vec3(0, 0, 1), light_array.data[light_base].height));
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
}
#endif
@@ -646,8 +646,6 @@ void main() {
);
}
- light_color.rgb *= original_color.rgb;
-
light_blend_compute(light_base, light_color, color.rgb);
}
@@ -657,20 +655,7 @@ void main() {
if (i >= light_count) {
break;
}
- uint light_base;
- if (i < 8) {
- if (i < 4) {
- light_base = draw_data.lights[0];
- } else {
- light_base = draw_data.lights[1];
- }
- } else {
- if (i < 12) {
- light_base = draw_data.lights[2];
- } else {
- light_base = draw_data.lights[3];
- }
- }
+ uint light_base = draw_data.lights[i >> 2];
light_base >>= (i & 3) * 8;
light_base &= 0xFF;
@@ -685,7 +670,7 @@ void main() {
vec3 light_position = vec3(light_array.data[light_base].position, light_array.data[light_base].height);
light_color.rgb *= light_base_color.rgb;
- light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, color, false);
+ light_color = light_compute(light_vertex, light_position, normal, light_color, light_base_color.a, specular_shininess, shadow_modulate, screen_uv, uv, base_color, false);
#else
light_color.rgb *= light_base_color.rgb * light_base_color.a;
@@ -695,7 +680,9 @@ void main() {
vec3 pos = light_vertex;
vec3 light_vec = normalize(light_pos - pos);
- light_color.rgb = light_normal_compute(light_vec, normal, base_color, light_color.rgb, specular_shininess, specular_shininess_used);
+ light_color.rgb = light_normal_compute(light_vec, normal, base_color.rgb, light_color.rgb, specular_shininess, specular_shininess_used);
+ } else {
+ light_color.rgb *= base_color.rgb;
}
#endif
if (any(lessThan(tex_uv, vec2(0.0, 0.0))) || any(greaterThanEqual(tex_uv, vec2(1.0, 1.0)))) {
@@ -743,8 +730,6 @@ void main() {
);
}
- light_color.rgb *= original_color.rgb;
-
light_blend_compute(light_base, light_color, color.rgb);
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/cluster_render.glsl b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
index 2fe230f0bf..932312de82 100644
--- a/servers/rendering/renderer_rd/shaders/cluster_render.glsl
+++ b/servers/rendering/renderer_rd/shaders/cluster_render.glsl
@@ -64,7 +64,7 @@ void main() {
#version 450
#VERSION_DEFINES
-
+#ifndef MOLTENVK_USED // Metal will corrupt GPU state otherwise
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) && defined(has_GL_KHR_shader_subgroup_vote)
#extension GL_KHR_shader_subgroup_ballot : enable
@@ -73,6 +73,7 @@ void main() {
#define USE_SUBGROUPS
#endif
+#endif
layout(location = 0) in float depth_interp;
layout(location = 1) in flat uint element_index;
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index 9f86643e52..9d8294a7da 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -121,7 +121,7 @@ void main() {
// clip z and w advance to line advance
vec2 line_advance = normalize(line_dir); // down to pixel
- float step_size = length(line_advance) / length(line_dir);
+ float step_size = 1.0 / length(line_dir);
float z_advance = z_dir * step_size; // adapt z advance to line advance
float w_advance = w_dir * step_size; // adapt w advance to line advance
@@ -139,6 +139,14 @@ void main() {
float depth;
vec2 prev_pos = pos;
+ if (ivec2(pos + line_advance - 0.5) == ssC) {
+ // It is possible for rounding to cause our first pixel to check to be the pixel we're reflecting.
+ // Make sure we skip it
+ pos += line_advance;
+ z += z_advance;
+ w += w_advance;
+ }
+
bool found = false;
float steps_taken = 0.0;
@@ -149,8 +157,8 @@ void main() {
w += w_advance;
// convert to linear depth
-
- depth = imageLoad(source_depth, ivec2(pos - 0.5)).r;
+ ivec2 test_pos = ivec2(pos - 0.5);
+ depth = imageLoad(source_depth, test_pos).r;
if (sc_multiview) {
depth = depth * 2.0 - 1.0;
depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
@@ -161,13 +169,21 @@ void main() {
z_to = z / w;
if (depth > z_to) {
- // if depth was surpassed
- if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far * 0.95) {
- // check the depth tolerance and far clip
- // check that normal is valid
- found = true;
+ // Test if our ray is hitting the "right" side of the surface, if not we're likely self reflecting and should skip.
+ vec4 test_normal_roughness = imageLoad(source_normal_roughness, test_pos);
+ vec3 test_normal = test_normal_roughness.xyz * 2.0 - 1.0;
+ test_normal = normalize(test_normal);
+ test_normal.y = -test_normal.y; //because this code reads flipped
+
+ if (dot(ray_dir, test_normal) < 0.001) {
+ // if depth was surpassed
+ if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far * 0.95) {
+ // check the depth tolerance and far clip
+ // check that normal is valid
+ found = true;
+ }
+ break;
}
- break;
}
steps_taken += 1.0;
diff --git a/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
index b0a0839836..02566d8e35 100644
--- a/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
@@ -32,7 +32,9 @@
// Based on Spartan Engine's TAA implementation (without TAA upscale).
// <https://github.com/PanosK92/SpartanEngine/blob/a8338d0609b85dc32f3732a5c27fb4463816a3b9/Data/shaders/temporal_antialiasing.hlsl>
+#ifndef MOLTENVK_USED
#define USE_SUBGROUPS
+#endif // MOLTENVK_USED
#define GROUP_SIZE 8
#define FLT_MIN 0.00000001
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index eed9038502..28507e6c12 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -381,7 +381,7 @@ void main() {
float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1));
//compute directional lights
- if (total_density > 0.001) {
+ if (total_density > 0.00005) {
for (uint i = 0; i < params.directional_light_count; i++) {
if (directional_lights.data[i].volumetric_fog_energy > 0.001) {
vec3 shadow_attenuation = vec3(1.0);
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 1a8a1f3aa3..0bdf0e50aa 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -97,9 +97,7 @@ layout(location = 8) out vec4 prev_screen_position;
#ifdef MATERIAL_UNIFORMS_USED
layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{
-
#MATERIAL_UNIFORMS
-
} material;
#endif
@@ -691,7 +689,7 @@ vec4 fog_process(vec3 vertex) {
void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) {
uint item_min_max = cluster_buffer.data[p_offset];
- item_min = item_min_max & 0xFFFF;
+ item_min = item_min_max & 0xFFFFu;
item_max = item_min_max >> 16;
item_from = item_min >> 5;
@@ -958,9 +956,9 @@ void fragment_shader(in SceneData scene_data) {
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ merged_mask &= ~(1u << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ if (((1u << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
@@ -1419,9 +1417,9 @@ void fragment_shader(in SceneData scene_data) {
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ merged_mask &= ~(1u << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ if (((1u << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
@@ -1447,18 +1445,24 @@ void fragment_shader(in SceneData scene_data) {
}
//finalize ambient light here
- ambient_light *= albedo.rgb;
- ambient_light *= ao;
+ {
+#if defined(AMBIENT_LIGHT_DISABLED)
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+
+ 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;
+ }
+#endif // AMBIENT_LIGHT_DISABLED
+ }
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
- 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;
- }
-
//this saves some VGPRs
vec3 f0 = F0(metallic, specular, albedo);
@@ -1775,9 +1779,9 @@ void fragment_shader(in SceneData scene_data) {
float shadow = 1.0;
#ifndef SHADOWS_DISABLED
if (i < 4) {
- shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0;
+ shadow = float(shadow0 >> (i * 8u) & 0xFFu) / 255.0;
} else {
- shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
+ shadow = float(shadow1 >> ((i - 4u) * 8u) & 0xFFu) / 255.0;
}
shadow = shadow * directional_lights.data[i].shadow_opacity + 1.0 - directional_lights.data[i].shadow_opacity;
@@ -1839,9 +1843,9 @@ void fragment_shader(in SceneData scene_data) {
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ merged_mask &= ~(1u << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ if (((1u << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
@@ -1910,9 +1914,9 @@ void fragment_shader(in SceneData scene_data) {
while (merged_mask != 0) {
uint bit = findMSB(merged_mask);
- merged_mask &= ~(1 << bit);
+ merged_mask &= ~(1u << bit);
#ifdef USE_SUBGROUPS
- if (((1 << bit) & mask) == 0) { //do not process if not originally here
+ if (((1u << bit) & mask) == 0) { //do not process if not originally here
continue;
}
#endif
@@ -2065,7 +2069,7 @@ void fragment_shader(in SceneData scene_data) {
float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f);
float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f);
//store as 8985 to have 2 extra neighbour bits
- uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25);
+ uint light_rgbe = ((uint(sRed) & 0x1FFu) >> 1) | ((uint(sGreen) & 0x1FFu) << 8) | (((uint(sBlue) & 0x1FFu) >> 1) << 17) | ((uint(exps) & 0x1Fu) << 25);
imageStore(emission_grid, grid_pos, uvec4(light_rgbe));
imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso));
@@ -2099,8 +2103,8 @@ void fragment_shader(in SceneData scene_data) {
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
uint index2 = instances.data[instance_index].gi_offset >> 16;
- voxel_gi_buffer.x = index1 & 0xFF;
- voxel_gi_buffer.y = index2 & 0xFF;
+ voxel_gi_buffer.x = index1 & 0xFFu;
+ voxel_gi_buffer.y = index2 & 0xFFu;
} else {
voxel_gi_buffer.x = 0xFF;
voxel_gi_buffer.y = 0xFF;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 0d36b98645..3a45ab0059 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -4,14 +4,15 @@
#define MAX_VOXEL_GI_INSTANCES 8
#define MAX_VIEWS 2
+#ifndef MOLTENVK_USED
#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic)
#extension GL_KHR_shader_subgroup_ballot : enable
#extension GL_KHR_shader_subgroup_arithmetic : enable
#define USE_SUBGROUPS
-
#endif
+#endif // MOLTENVK_USED
#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
#extension GL_EXT_multiview : enable
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 33fd4c35b1..9aeaa6d978 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -1172,8 +1172,14 @@ void main() {
} //Reflection probes
// finalize ambient light here
- ambient_light *= albedo.rgb;
- ambient_light *= ao;
+ {
+#if defined(AMBIENT_LIGHT_DISABLED)
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ ambient_light *= albedo.rgb;
+ ambient_light *= ao;
+#endif // AMBIENT_LIGHT_DISABLED
+ }
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
diff --git a/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp
new file mode 100644
index 0000000000..c7f106eba0
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* forward_id_storage.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 "forward_id_storage.h"
+
+using namespace RendererRD;
+
+ForwardIDStorage *ForwardIDStorage::singleton = nullptr;
+
+ForwardIDStorage::ForwardIDStorage() {
+ singleton = this;
+}
+
+ForwardIDStorage::~ForwardIDStorage() {
+ singleton = nullptr;
+}
diff --git a/modules/websocket/emws_client.h b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h
index cdcec31e19..f6a74383d4 100644
--- a/modules/websocket/emws_client.h
+++ b/servers/rendering/renderer_rd/storage_rd/forward_id_storage.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* emws_client.h */
+/* forward_id_storage.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,44 +28,41 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EMWS_CLIENT_H
-#define EMWS_CLIENT_H
+#ifndef FORWARD_ID_STORAGE_H
+#define FORWARD_ID_STORAGE_H
-#ifdef WEB_ENABLED
+#include "servers/rendering/storage/utilities.h"
-#include "core/error/error_list.h"
-#include "emws_peer.h"
-#include "websocket_client.h"
+class RendererSceneRenderRD;
-class EMWSClient : public WebSocketClient {
- GDCIIMPL(EMWSClient, WebSocketClient);
+namespace RendererRD {
-private:
- int _js_id = 0;
- bool _is_connecting = false;
- int _in_buf_size = DEF_BUF_SHIFT;
- int _in_pkt_size = DEF_PKT_SHIFT;
- int _out_buf_size = DEF_BUF_SHIFT;
+typedef int32_t ForwardID;
+
+enum ForwardIDType {
+ FORWARD_ID_TYPE_OMNI_LIGHT,
+ FORWARD_ID_TYPE_SPOT_LIGHT,
+ FORWARD_ID_TYPE_REFLECTION_PROBE,
+ FORWARD_ID_TYPE_DECAL,
+ FORWARD_ID_MAX,
+};
- static void _esws_on_connect(void *obj, char *proto);
- static void _esws_on_message(void *obj, const uint8_t *p_data, int p_data_size, int p_is_string);
- static void _esws_on_error(void *obj);
- static void _esws_on_close(void *obj, int code, const char *reason, int was_clean);
+class ForwardIDStorage {
+private:
+ static ForwardIDStorage *singleton;
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_tls, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
- Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
- void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
- IPAddress get_connected_host() const override;
- uint16_t get_connected_port() const override;
- virtual ConnectionStatus get_connection_status() const override;
- int get_max_packet_size() const override;
- virtual void poll() override;
- EMWSClient();
- ~EMWSClient();
+ static ForwardIDStorage *get_singleton() { return singleton; }
+
+ ForwardIDStorage();
+ virtual ~ForwardIDStorage();
+
+ virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) { return -1; }
+ virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {}
+ virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {}
+ virtual bool uses_forward_ids() const { return false; }
};
-#endif // WEB_ENABLED
+} // namespace RendererRD
-#endif // EMWS_CLIENT_H
+#endif // FORWARD_ID_STORAGE_H
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 81b0661481..c83473ef07 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -30,6 +30,7 @@
#include "light_storage.h"
#include "core/config/project_settings.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
#include "texture_storage.h"
using namespace RendererRD;
@@ -45,6 +46,9 @@ LightStorage::LightStorage() {
TextureStorage *texture_storage = TextureStorage::get_singleton();
+ directional_shadow.size = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/size");
+ directional_shadow.use_16_bits = GLOBAL_GET("rendering/lights_and_shadows/directional_shadow/16_bits");
+
using_lightmap_array = true; // high end
if (using_lightmap_array) {
uint64_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
@@ -56,7 +60,7 @@ LightStorage::LightStorage() {
}
for (int i = 0; i < lightmap_textures.size(); i++) {
- lightmap_textures.write[i] = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ lightmap_textures.write[i] = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
}
@@ -64,9 +68,46 @@ LightStorage::LightStorage() {
}
LightStorage::~LightStorage() {
+ free_reflection_data();
+ free_light_data();
+
+ for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) {
+ RD::get_singleton()->free(E.value.cubemap);
+ }
+
singleton = nullptr;
}
+bool LightStorage::free(RID p_rid) {
+ if (owns_reflection_probe(p_rid)) {
+ reflection_probe_free(p_rid);
+ return true;
+ } else if (owns_reflection_atlas(p_rid)) {
+ reflection_atlas_free(p_rid);
+ return true;
+ } else if (owns_reflection_probe_instance(p_rid)) {
+ reflection_probe_instance_free(p_rid);
+ return true;
+ } else if (owns_light(p_rid)) {
+ light_free(p_rid);
+ return true;
+ } else if (owns_light_instance(p_rid)) {
+ light_instance_free(p_rid);
+ return true;
+ } else if (owns_lightmap(p_rid)) {
+ lightmap_free(p_rid);
+ return true;
+ } else if (owns_lightmap_instance(p_rid)) {
+ lightmap_instance_free(p_rid);
+ return true;
+ } else if (owns_shadow_atlas(p_rid)) {
+ shadow_atlas_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
/* LIGHT */
void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
@@ -183,7 +224,7 @@ void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
}
void LightStorage::light_set_projector(RID p_light, RID p_texture) {
- RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ TextureStorage *texture_storage = TextureStorage::get_singleton();
Light *light = light_owner.get_or_null(p_light);
ERR_FAIL_COND(!light);
@@ -375,6 +416,595 @@ Dependency *LightStorage::light_get_dependency(RID p_light) const {
return &light->dependency;
}
+/* LIGHT INSTANCE API */
+
+RID LightStorage::light_instance_create(RID p_light) {
+ RID li = light_instance_owner.make_rid(LightInstance());
+
+ LightInstance *light_instance = light_instance_owner.get_or_null(li);
+
+ light_instance->self = li;
+ light_instance->light = p_light;
+ light_instance->light_type = light_get_type(p_light);
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ light_instance->forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT);
+ }
+
+ return li;
+}
+
+void LightStorage::light_instance_free(RID p_light) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light);
+
+ //remove from shadow atlases..
+ for (const RID &E : light_instance->shadow_atlases) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E);
+ ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_light));
+ uint32_t key = shadow_atlas->shadow_owners[p_light];
+ uint32_t q = (key >> QUADRANT_SHIFT) & 0x3;
+ uint32_t s = key & SHADOW_INDEX_MASK;
+
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+ if (key & OMNI_LIGHT_FLAG) {
+ // Omni lights use two atlas spots, make sure to clear the other as well
+ shadow_atlas->quadrants[q].shadows.write[s + 1].owner = RID();
+ }
+
+ shadow_atlas->shadow_owners.erase(p_light);
+ }
+
+ if (light_instance->light_type != RS::LIGHT_DIRECTIONAL) {
+ ForwardIDStorage::get_singleton()->free_forward_id(light_instance->light_type == RS::LIGHT_OMNI ? FORWARD_ID_TYPE_OMNI_LIGHT : FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id);
+ }
+ light_instance_owner.free(p_light);
+}
+
+void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
+}
+
+void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->aabb = p_aabb;
+}
+
+void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ ERR_FAIL_INDEX(p_pass, 6);
+
+ light_instance->shadow_transform[p_pass].camera = p_projection;
+ light_instance->shadow_transform[p_pass].transform = p_transform;
+ light_instance->shadow_transform[p_pass].farplane = p_far;
+ light_instance->shadow_transform[p_pass].split = p_split;
+ light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
+ light_instance->shadow_transform[p_pass].range_begin = p_range_begin;
+ light_instance->shadow_transform[p_pass].shadow_texel_size = p_shadow_texel_size;
+ light_instance->shadow_transform[p_pass].uv_scale = p_uv_scale;
+}
+
+void LightStorage::light_instance_mark_visible(RID p_light_instance) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->last_scene_pass = RendererSceneRenderRD::get_singleton()->get_scene_pass();
+}
+
+/* LIGHT DATA */
+
+void LightStorage::free_light_data() {
+ if (directional_light_buffer.is_valid()) {
+ RD::get_singleton()->free(directional_light_buffer);
+ directional_light_buffer = RID();
+ }
+
+ if (omni_light_buffer.is_valid()) {
+ RD::get_singleton()->free(omni_light_buffer);
+ omni_light_buffer = RID();
+ }
+
+ if (spot_light_buffer.is_valid()) {
+ RD::get_singleton()->free(spot_light_buffer);
+ spot_light_buffer = RID();
+ }
+
+ if (directional_lights != nullptr) {
+ memdelete_arr(directional_lights);
+ directional_lights = nullptr;
+ }
+
+ if (omni_lights != nullptr) {
+ memdelete_arr(omni_lights);
+ omni_lights = nullptr;
+ }
+
+ if (spot_lights != nullptr) {
+ memdelete_arr(spot_lights);
+ spot_lights = nullptr;
+ }
+
+ if (omni_light_sort != nullptr) {
+ memdelete_arr(omni_light_sort);
+ omni_light_sort = nullptr;
+ }
+
+ if (spot_light_sort != nullptr) {
+ memdelete_arr(spot_light_sort);
+ spot_light_sort = nullptr;
+ }
+}
+
+void LightStorage::set_max_lights(const uint32_t p_max_lights) {
+ max_lights = p_max_lights;
+
+ uint32_t light_buffer_size = max_lights * sizeof(LightData);
+ omni_lights = memnew_arr(LightData, max_lights);
+ omni_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
+ omni_light_sort = memnew_arr(LightInstanceDepthSort, max_lights);
+ spot_lights = memnew_arr(LightData, max_lights);
+ spot_light_buffer = RD::get_singleton()->storage_buffer_create(light_buffer_size);
+ spot_light_sort = memnew_arr(LightInstanceDepthSort, max_lights);
+ //defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(max_lights) + "\n";
+
+ max_directional_lights = RendererSceneRender::MAX_DIRECTIONAL_LIGHTS;
+ uint32_t directional_light_buffer_size = max_directional_lights * sizeof(DirectionalLightData);
+ directional_lights = memnew_arr(DirectionalLightData, max_directional_lights);
+ directional_light_buffer = RD::get_singleton()->uniform_buffer_create(directional_light_buffer_size);
+}
+
+void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows) {
+ ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton();
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+
+ Transform3D inverse_transform = p_camera_transform.affine_inverse();
+
+ r_directional_light_count = 0;
+ r_positional_light_count = 0;
+
+ Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin);
+
+ omni_light_count = 0;
+ spot_light_count = 0;
+
+ r_directional_light_soft_shadows = false;
+
+ for (int i = 0; i < (int)p_lights.size(); i++) {
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_lights[i]);
+ if (!light_instance) {
+ continue;
+ }
+ Light *light = light_owner.get_or_null(light_instance->light);
+
+ ERR_CONTINUE(light == nullptr);
+
+ switch (light->type) {
+ case RS::LIGHT_DIRECTIONAL: {
+ if (r_directional_light_count >= max_directional_lights || light->directional_sky_mode == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
+ continue;
+ }
+
+ DirectionalLightData &light_data = directional_lights[r_directional_light_count];
+
+ Transform3D light_transform = light_instance->transform;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = light->negative ? -1 : 1;
+
+ light_data.energy = sign * light->param[RS::LIGHT_PARAM_ENERGY];
+
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+ light_data.energy *= light->param[RS::LIGHT_PARAM_INTENSITY];
+ } else {
+ light_data.energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
+ Color linear_col = light->color.srgb_to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ light_data.specular = light->param[RS::LIGHT_PARAM_SPECULAR];
+ light_data.volumetric_fog_energy = light->param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY];
+ light_data.mask = light->cull_mask;
+
+ float size = light->param[RS::LIGHT_PARAM_SIZE];
+
+ light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset
+
+ if (RendererSceneRenderRD::get_singleton()->get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
+ WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet.");
+ }
+
+ light_data.shadow_opacity = (p_using_shadows && light->shadow)
+ ? light->param[RS::LIGHT_PARAM_SHADOW_OPACITY]
+ : 0.0;
+
+ float angular_diameter = light->param[RS::LIGHT_PARAM_SIZE];
+ if (angular_diameter > 0.0) {
+ // I know tan(0) is 0, but let's not risk it with numerical precision.
+ // technically this will keep expanding until reaching the sun, but all we care
+ // is expand until we reach the radius of the near plane (there can't be more occluders than that)
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
+ if (light->shadow && light->param[RS::LIGHT_PARAM_SHADOW_BLUR] > 0.0) {
+ // Only enable PCSS-like soft shadows if blurring is enabled.
+ // Otherwise, performance would decrease with no visual difference.
+ r_directional_light_soft_shadows = true;
+ }
+ } else {
+ angular_diameter = 0.0;
+ }
+
+ if (light_data.shadow_opacity > 0.001) {
+ RS::LightDirectionalShadowMode smode = light->directional_shadow_mode;
+
+ int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
+ light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits;
+ for (int j = 0; j < 4; j++) {
+ Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect;
+ Projection matrix = light_instance->shadow_transform[j].camera;
+ float split = light_instance->shadow_transform[MIN(limit, j)].split;
+
+ Projection bias;
+ bias.set_light_bias();
+ Projection rectm;
+ rectm.set_light_atlas_rect(atlas_rect);
+
+ Transform3D modelview = (inverse_transform * light_instance->shadow_transform[j].transform).inverse();
+
+ Projection shadow_mtx = rectm * bias * matrix * modelview;
+ light_data.shadow_split_offsets[j] = split;
+ float bias_scale = light_instance->shadow_transform[j].bias_scale;
+ light_data.shadow_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] / 100.0 * bias_scale;
+ light_data.shadow_normal_bias[j] = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * light_instance->shadow_transform[j].shadow_texel_size;
+ light_data.shadow_transmittance_bias[j] = light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS] * bias_scale;
+ light_data.shadow_z_range[j] = light_instance->shadow_transform[j].farplane;
+ light_data.shadow_range_begin[j] = light_instance->shadow_transform[j].range_begin;
+ RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrices[j]);
+
+ Vector2 uv_scale = light_instance->shadow_transform[j].uv_scale;
+ uv_scale *= atlas_rect.size; //adapt to atlas size
+ switch (j) {
+ case 0: {
+ light_data.uv_scale1[0] = uv_scale.x;
+ light_data.uv_scale1[1] = uv_scale.y;
+ } break;
+ case 1: {
+ light_data.uv_scale2[0] = uv_scale.x;
+ light_data.uv_scale2[1] = uv_scale.y;
+ } break;
+ case 2: {
+ light_data.uv_scale3[0] = uv_scale.x;
+ light_data.uv_scale3[1] = uv_scale.y;
+ } break;
+ case 3: {
+ light_data.uv_scale4[0] = uv_scale.x;
+ light_data.uv_scale4[1] = uv_scale.y;
+ } break;
+ }
+ }
+
+ float fade_start = light->param[RS::LIGHT_PARAM_SHADOW_FADE_START];
+ light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999); //using 1.0 would break smoothstep
+ light_data.fade_to = -light_data.shadow_split_offsets[3];
+
+ light_data.soft_shadow_scale = light->param[RS::LIGHT_PARAM_SHADOW_BLUR];
+ light_data.softshadow_angle = angular_diameter;
+ light_data.bake_mode = light->bake_mode;
+
+ if (angular_diameter <= 0.0) {
+ light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->directional_shadow_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+
+ r_directional_light_count++;
+ } break;
+ case RS::LIGHT_OMNI: {
+ if (omni_light_count >= max_lights) {
+ continue;
+ }
+
+ Transform3D light_transform = light_instance->transform;
+ const real_t distance = camera_plane.distance_to(light_transform.origin);
+
+ if (light->distance_fade) {
+ const float fade_begin = light->distance_fade_begin;
+ const float fade_length = light->distance_fade_length;
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ omni_light_sort[omni_light_count].light_instance = light_instance;
+ omni_light_sort[omni_light_count].light = light;
+ omni_light_sort[omni_light_count].depth = distance;
+ omni_light_count++;
+ } break;
+ case RS::LIGHT_SPOT: {
+ if (spot_light_count >= max_lights) {
+ continue;
+ }
+
+ Transform3D light_transform = light_instance->transform;
+ const real_t distance = camera_plane.distance_to(light_transform.origin);
+
+ if (light->distance_fade) {
+ const float fade_begin = light->distance_fade_begin;
+ const float fade_length = light->distance_fade_length;
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ // Out of range, don't draw this light to improve performance.
+ continue;
+ }
+ }
+ }
+
+ spot_light_sort[spot_light_count].light_instance = light_instance;
+ spot_light_sort[spot_light_count].light = light;
+ spot_light_sort[spot_light_count].depth = distance;
+ spot_light_count++;
+ } break;
+ }
+
+ light_instance->last_pass = RSG::rasterizer->get_frame_number();
+ }
+
+ if (omni_light_count) {
+ SortArray<LightInstanceDepthSort> sorter;
+ sorter.sort(omni_light_sort, omni_light_count);
+ }
+
+ if (spot_light_count) {
+ SortArray<LightInstanceDepthSort> sorter;
+ sorter.sort(spot_light_sort, spot_light_count);
+ }
+
+ bool using_forward_ids = forward_id_storage->uses_forward_ids();
+
+ for (uint32_t i = 0; i < (omni_light_count + spot_light_count); i++) {
+ uint32_t index = (i < omni_light_count) ? i : i - (omni_light_count);
+ LightData &light_data = (i < omni_light_count) ? omni_lights[index] : spot_lights[index];
+ RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
+ LightInstance *light_instance = (i < omni_light_count) ? omni_light_sort[index].light_instance : spot_light_sort[index].light_instance;
+ Light *light = (i < omni_light_count) ? omni_light_sort[index].light : spot_light_sort[index].light;
+
+ if (using_forward_ids) {
+ forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index);
+ }
+
+ Transform3D light_transform = light_instance->transform;
+
+ float sign = light->negative ? -1 : 1;
+ Color linear_col = light->color.srgb_to_linear();
+
+ light_data.attenuation = light->param[RS::LIGHT_PARAM_ATTENUATION];
+
+ // Reuse fade begin, fade length and distance for shadow LOD determination later.
+ float fade_begin = 0.0;
+ float fade_shadow = 0.0;
+ float fade_length = 0.0;
+ real_t distance = 0.0;
+
+ float fade = 1.0;
+ float shadow_opacity_fade = 1.0;
+ if (light->distance_fade) {
+ fade_begin = light->distance_fade_begin;
+ fade_shadow = light->distance_fade_shadow;
+ fade_length = light->distance_fade_length;
+ distance = camera_plane.distance_to(light_transform.origin);
+
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+ if (distance > fade_begin) {
+ fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+ }
+
+ if (distance > fade_shadow) {
+ shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length);
+ }
+ }
+
+ float energy = sign * light->param[RS::LIGHT_PARAM_ENERGY] * fade;
+
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+ energy *= light->param[RS::LIGHT_PARAM_INTENSITY];
+
+ // Convert from Luminous Power to Luminous Intensity
+ if (type == RS::LIGHT_OMNI) {
+ energy *= 1.0 / (Math_PI * 4.0);
+ } else {
+ // Spot Lights are not physically accurate, Luminous Intensity should change in relation to the cone angle.
+ // We make this assumption to keep them easy to control.
+ energy *= 1.0 / Math_PI;
+ }
+ } else {
+ energy *= Math_PI;
+ }
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ }
+
+ light_data.color[0] = linear_col.r * energy;
+ light_data.color[1] = linear_col.g * energy;
+ light_data.color[2] = linear_col.b * energy;
+ light_data.specular_amount = light->param[RS::LIGHT_PARAM_SPECULAR] * 2.0;
+ light_data.volumetric_fog_energy = light->param[RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY];
+ light_data.bake_mode = light->bake_mode;
+
+ float radius = MAX(0.001, light->param[RS::LIGHT_PARAM_RANGE]);
+ light_data.inv_radius = 1.0 / radius;
+
+ Vector3 pos = inverse_transform.xform(light_transform.origin);
+
+ light_data.position[0] = pos.x;
+ light_data.position[1] = pos.y;
+ light_data.position[2] = pos.z;
+
+ Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, -1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float size = light->param[RS::LIGHT_PARAM_SIZE];
+
+ light_data.size = size;
+
+ light_data.inv_spot_attenuation = 1.0f / light->param[RS::LIGHT_PARAM_SPOT_ATTENUATION];
+ float spot_angle = light->param[RS::LIGHT_PARAM_SPOT_ANGLE];
+ light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle));
+
+ light_data.mask = light->cull_mask;
+
+ light_data.atlas_rect[0] = 0;
+ light_data.atlas_rect[1] = 0;
+ light_data.atlas_rect[2] = 0;
+ light_data.atlas_rect[3] = 0;
+
+ RID projector = light->projector;
+
+ if (projector.is_valid()) {
+ Rect2 rect = texture_storage->decal_atlas_get_texture_rect(projector);
+
+ if (type == RS::LIGHT_SPOT) {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y + rect.size.height; //flip because shadow is flipped
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = -rect.size.height;
+ } else {
+ light_data.projector_rect[0] = rect.position.x;
+ light_data.projector_rect[1] = rect.position.y;
+ light_data.projector_rect[2] = rect.size.width;
+ light_data.projector_rect[3] = rect.size.height * 0.5; //used by dp, so needs to be half
+ }
+ } else {
+ light_data.projector_rect[0] = 0;
+ light_data.projector_rect[1] = 0;
+ light_data.projector_rect[2] = 0;
+ light_data.projector_rect[3] = 0;
+ }
+
+ const bool needs_shadow =
+ p_using_shadows &&
+ owns_shadow_atlas(p_shadow_atlas) &&
+ shadow_atlas_owns_light_instance(p_shadow_atlas, light_instance->self) &&
+ light->shadow;
+
+ bool in_shadow_range = true;
+ if (needs_shadow && light->distance_fade) {
+ if (distance > light->distance_fade_shadow + light->distance_fade_length) {
+ // Out of range, don't draw shadows to improve performance.
+ in_shadow_range = false;
+ }
+ }
+
+ if (needs_shadow && in_shadow_range) {
+ // fill in the shadow information
+
+ light_data.shadow_opacity = light->param[RS::LIGHT_PARAM_SHADOW_OPACITY] * shadow_opacity_fade;
+
+ float shadow_texel_size = light_instance_get_shadow_texel_size(light_instance->self, p_shadow_atlas);
+ light_data.shadow_normal_bias = light->param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * shadow_texel_size * 10.0;
+
+ if (type == RS::LIGHT_SPOT) {
+ light_data.shadow_bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS] / 100.0;
+ } else { //omni
+ light_data.shadow_bias = light->param[RS::LIGHT_PARAM_SHADOW_BIAS];
+ }
+
+ light_data.transmittance_bias = light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
+
+ Vector2i omni_offset;
+ Rect2 rect = light_instance_get_shadow_atlas_rect(light_instance->self, p_shadow_atlas, omni_offset);
+
+ light_data.atlas_rect[0] = rect.position.x;
+ light_data.atlas_rect[1] = rect.position.y;
+ light_data.atlas_rect[2] = rect.size.width;
+ light_data.atlas_rect[3] = rect.size.height;
+
+ light_data.soft_shadow_scale = light->param[RS::LIGHT_PARAM_SHADOW_BLUR];
+
+ if (type == RS::LIGHT_OMNI) {
+ Transform3D proj = (inverse_transform * light_transform).inverse();
+
+ RendererRD::MaterialStorage::store_transform(proj, light_data.shadow_matrix);
+
+ if (size > 0.0 && light_data.soft_shadow_scale > 0.0) {
+ // Only enable PCSS-like soft shadows if blurring is enabled.
+ // Otherwise, performance would decrease with no visual difference.
+ light_data.soft_shadow_size = size;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+
+ light_data.direction[0] = omni_offset.x * float(rect.size.width);
+ light_data.direction[1] = omni_offset.y * float(rect.size.height);
+ } else if (type == RS::LIGHT_SPOT) {
+ Transform3D modelview = (inverse_transform * light_transform).inverse();
+ Projection bias;
+ bias.set_light_bias();
+
+ Projection cm = light_instance->shadow_transform[0].camera;
+ Projection shadow_mtx = bias * cm * modelview;
+ RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix);
+
+ if (size > 0.0 && light_data.soft_shadow_scale > 0.0) {
+ // Only enable PCSS-like soft shadows if blurring is enabled.
+ // Otherwise, performance would decrease with no visual difference.
+ float half_np = cm.get_z_near() * Math::tan(Math::deg_to_rad(spot_angle));
+ light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
+ } else {
+ light_data.soft_shadow_size = 0.0;
+ light_data.soft_shadow_scale *= RendererSceneRenderRD::get_singleton()->shadows_quality_radius_get(); // Only use quality radius for PCF
+ }
+ }
+ } else {
+ light_data.shadow_opacity = 0.0;
+ }
+
+ light_instance->cull_mask = light->cull_mask;
+
+ // hook for subclass to do further processing.
+ RendererSceneRenderRD::get_singleton()->setup_added_light(type, light_transform, radius, spot_angle);
+
+ r_positional_light_count++;
+ }
+
+ //update without barriers
+ if (omni_light_count) {
+ RD::get_singleton()->buffer_update(omni_light_buffer, 0, sizeof(LightData) * omni_light_count, omni_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ }
+
+ if (spot_light_count) {
+ RD::get_singleton()->buffer_update(spot_light_buffer, 0, sizeof(LightData) * spot_light_count, spot_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ }
+
+ if (r_directional_light_count) {
+ RD::get_singleton()->buffer_update(directional_light_buffer, 0, sizeof(DirectionalLightData) * r_directional_light_count, directional_lights, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ }
+}
+
/* REFLECTION PROBE */
RID LightStorage::reflection_probe_allocate() {
@@ -631,6 +1261,443 @@ Dependency *LightStorage::reflection_probe_get_dependency(RID p_probe) const {
return &reflection_probe->dependency;
}
+/* REFLECTION ATLAS */
+
+RID LightStorage::reflection_atlas_create() {
+ ReflectionAtlas ra;
+ ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count");
+ ra.size = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_size");
+ ra.cluster_builder = nullptr;
+
+ return reflection_atlas_owner.make_rid(ra);
+}
+
+void LightStorage::reflection_atlas_free(RID p_ref_atlas) {
+ reflection_atlas_set_size(p_ref_atlas, 0, 0);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
+ if (ra->cluster_builder) {
+ memdelete(ra->cluster_builder);
+ }
+ reflection_atlas_owner.free(p_ref_atlas);
+}
+
+void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
+ ERR_FAIL_COND(!ra);
+
+ if (ra->size == p_reflection_size && ra->count == p_reflection_count) {
+ return; //no changes
+ }
+
+ if (ra->cluster_builder) {
+ // only if we're using our cluster
+ ra->cluster_builder->setup(Size2i(ra->size, ra->size), max_cluster_elements, RID(), RID(), RID());
+ }
+
+ ra->size = p_reflection_size;
+ ra->count = p_reflection_count;
+
+ if (ra->reflection.is_valid()) {
+ //clear and invalidate everything
+ RD::get_singleton()->free(ra->reflection);
+ ra->reflection = RID();
+ RD::get_singleton()->free(ra->depth_buffer);
+ ra->depth_buffer = RID();
+ for (int i = 0; i < ra->reflections.size(); i++) {
+ ra->reflections.write[i].data.clear_reflection_data();
+ if (ra->reflections[i].owner.is_null()) {
+ continue;
+ }
+ reflection_probe_release_atlas_index(ra->reflections[i].owner);
+ //rp->atlasindex clear
+ }
+
+ ra->reflections.clear();
+ }
+}
+
+int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas);
+ ERR_FAIL_COND_V(!ra, 0);
+
+ return ra->size;
+}
+
+/* REFLECTION PROBE INSTANCE */
+
+RID LightStorage::reflection_probe_instance_create(RID p_probe) {
+ ReflectionProbeInstance rpi;
+ rpi.probe = p_probe;
+ rpi.forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE);
+
+ return reflection_probe_instance_owner.make_rid(rpi);
+}
+
+void LightStorage::reflection_probe_instance_free(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ForwardIDStorage::get_singleton()->free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id);
+ reflection_probe_release_atlas_index(p_instance);
+ reflection_probe_instance_owner.free(p_instance);
+}
+
+void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!rpi);
+
+ rpi->transform = p_transform;
+ rpi->dirty = true;
+}
+
+void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!rpi);
+
+ if (rpi->atlas.is_null()) {
+ return; //nothing to release
+ }
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
+ ERR_FAIL_COND(!atlas);
+ ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
+ atlas->reflections.write[rpi->atlas_index].owner = RID();
+ rpi->atlas_index = -1;
+ rpi->atlas = RID();
+}
+
+bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ if (rpi->rendering) {
+ return false;
+ }
+
+ if (rpi->dirty) {
+ return true;
+ }
+
+ if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
+ return true;
+ }
+
+ return rpi->atlas_index == -1;
+}
+
+bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ return rpi->atlas.is_valid();
+}
+
+bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
+
+ ERR_FAIL_COND_V(!atlas, false);
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+
+ RD::get_singleton()->draw_command_begin_label("Reflection probe render");
+
+ if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
+ WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
+ reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
+ }
+
+ if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 8) {
+ // Invalidate reflection atlas, need to regenerate
+ RD::get_singleton()->free(atlas->reflection);
+ atlas->reflection = RID();
+
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ if (atlas->reflections[i].owner.is_null()) {
+ continue;
+ }
+ reflection_probe_release_atlas_index(atlas->reflections[i].owner);
+ }
+
+ atlas->reflections.clear();
+ }
+
+ if (atlas->reflection.is_null()) {
+ int mipmaps = MIN(RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
+ mipmaps = LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS ? 8 : mipmaps; // always use 8 mipmaps with real time filtering
+ {
+ //reflection atlas was unused, create:
+ RD::TextureFormat tf;
+ tf.array_layers = 6 * atlas->count;
+ tf.format = RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format();
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
+ tf.mipmaps = mipmaps;
+ tf.width = atlas->size;
+ tf.height = atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0);
+
+ atlas->reflection = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+ tf.width = atlas->size;
+ tf.height = atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ atlas->depth_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+ atlas->reflections.resize(atlas->count);
+ for (int i = 0; i < atlas->count; i++) {
+ atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, RendererSceneRenderRD::get_singleton()->get_sky()->roughness_layers, RendererSceneRenderRD::get_singleton()->_render_buffers_get_color_format());
+ for (int j = 0; j < 6; j++) {
+ atlas->reflections.write[i].fbs[j] = RendererSceneRenderRD::get_singleton()->reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer);
+ }
+ }
+
+ Vector<RID> fb;
+ fb.push_back(atlas->depth_buffer);
+ atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
+ }
+
+ if (rpi->atlas_index == -1) {
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ if (atlas->reflections[i].owner.is_null()) {
+ rpi->atlas_index = i;
+ break;
+ }
+ }
+ //find the one used last
+ if (rpi->atlas_index == -1) {
+ //everything is in use, find the one least used via LRU
+ uint64_t pass_min = 0;
+
+ for (int i = 0; i < atlas->reflections.size(); i++) {
+ ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner);
+ if (rpi2->last_pass < pass_min) {
+ pass_min = rpi2->last_pass;
+ rpi->atlas_index = i;
+ }
+ }
+ }
+ }
+
+ if (rpi->atlas_index != -1) { // should we fail if this is still -1 ?
+ atlas->reflections.write[rpi->atlas_index].owner = p_instance;
+ }
+
+ rpi->atlas = p_reflection_atlas;
+ rpi->rendering = true;
+ rpi->dirty = false;
+ rpi->processing_layer = 1;
+ rpi->processing_side = 0;
+
+ RD::get_singleton()->draw_command_end_label();
+
+ return true;
+}
+
+bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, false);
+ ERR_FAIL_COND_V(!rpi->rendering, false);
+ ERR_FAIL_COND_V(rpi->atlas.is_null(), false);
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
+ if (!atlas || rpi->atlas_index == -1) {
+ //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering)
+ rpi->rendering = false;
+ return false;
+ }
+
+ if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS) {
+ // Using real time reflections, all roughness is done in one step
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_fast_filter(false);
+ rpi->rendering = false;
+ rpi->processing_side = 0;
+ rpi->processing_layer = 1;
+ return true;
+ }
+
+ if (rpi->processing_layer > 1) {
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, 10, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality);
+ rpi->processing_layer++;
+ if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
+ rpi->rendering = false;
+ rpi->processing_side = 0;
+ rpi->processing_layer = 1;
+ return true;
+ }
+ return false;
+
+ } else {
+ atlas->reflections.write[rpi->atlas_index].data.create_reflection_importance_sample(false, rpi->processing_side, rpi->processing_layer, RendererSceneRenderRD::get_singleton()->get_sky()->sky_ggx_samples_quality);
+ }
+
+ rpi->processing_side++;
+ if (rpi->processing_side == 6) {
+ rpi->processing_side = 0;
+ rpi->processing_layer++;
+ }
+
+ return false;
+}
+
+uint32_t LightStorage::reflection_probe_instance_get_resolution(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, 0);
+ return atlas->size;
+}
+
+RID LightStorage::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->reflections[rpi->atlas_index].fbs[p_index];
+}
+
+RID LightStorage::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+ ERR_FAIL_INDEX_V(p_index, 6, RID());
+
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->depth_fb;
+}
+
+ClusterBuilderRD *LightStorage::reflection_probe_instance_get_cluster_builder(RID p_instance, ClusterBuilderSharedDataRD *p_cluster_builder_shared) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas);
+ if (!ra) {
+ ERR_PRINT("reflection probe has no reflection atlas! Bug?");
+ return nullptr;
+ } else {
+ if (ra->cluster_builder == nullptr) {
+ ra->cluster_builder = memnew(ClusterBuilderRD);
+ ra->cluster_builder->set_shared(p_cluster_builder_shared);
+ ra->cluster_builder->setup(Size2i(ra->size, ra->size), get_max_cluster_elements(), RID(), RID(), RID());
+ }
+ return ra->cluster_builder;
+ }
+}
+
+/* REFLECTION DATA */
+
+void LightStorage::free_reflection_data() {
+ if (reflection_buffer.is_valid()) {
+ RD::get_singleton()->free(reflection_buffer);
+ reflection_buffer = RID();
+ }
+
+ if (reflections != nullptr) {
+ memdelete_arr(reflections);
+ reflections = nullptr;
+ }
+
+ if (reflection_sort != nullptr) {
+ memdelete_arr(reflection_sort);
+ reflection_sort = nullptr;
+ }
+}
+
+void LightStorage::set_max_reflection_probes(const uint32_t p_max_reflection_probes) {
+ max_reflections = p_max_reflection_probes;
+ reflections = memnew_arr(ReflectionData, max_reflections);
+ reflection_sort = memnew_arr(ReflectionProbeInstanceSort, max_reflections);
+ reflection_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ReflectionData) * max_reflections);
+}
+
+void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) {
+ ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton();
+
+ reflection_count = 0;
+
+ for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) {
+ if (reflection_count == max_reflections) {
+ break;
+ }
+
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]);
+ if (!rpi) {
+ continue;
+ }
+
+ Transform3D transform = rpi->transform;
+
+ reflection_sort[reflection_count].probe_instance = rpi;
+ reflection_sort[reflection_count].depth = -p_camera_inverse_transform.xform(transform.origin).z;
+ reflection_count++;
+ }
+
+ if (reflection_count > 0) {
+ SortArray<ReflectionProbeInstanceSort> sort_array;
+ sort_array.sort(reflection_sort, reflection_count);
+ }
+
+ bool using_forward_ids = forward_id_storage->uses_forward_ids();
+ for (uint32_t i = 0; i < reflection_count; i++) {
+ ReflectionProbeInstance *rpi = reflection_sort[i].probe_instance;
+
+ if (using_forward_ids) {
+ forward_id_storage->map_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id, i);
+ }
+
+ ReflectionProbe *probe = reflection_probe_owner.get_or_null(rpi->probe);
+
+ ReflectionData &reflection_ubo = reflections[i];
+
+ Vector3 extents = probe->extents;
+
+ rpi->cull_mask = probe->cull_mask;
+
+ reflection_ubo.box_extents[0] = extents.x;
+ reflection_ubo.box_extents[1] = extents.y;
+ reflection_ubo.box_extents[2] = extents.z;
+ reflection_ubo.index = rpi->atlas_index;
+
+ Vector3 origin_offset = probe->origin_offset;
+
+ reflection_ubo.box_offset[0] = origin_offset.x;
+ reflection_ubo.box_offset[1] = origin_offset.y;
+ reflection_ubo.box_offset[2] = origin_offset.z;
+ reflection_ubo.mask = probe->cull_mask;
+
+ reflection_ubo.intensity = probe->intensity;
+ reflection_ubo.ambient_mode = probe->ambient_mode;
+
+ reflection_ubo.exterior = !probe->interior;
+ reflection_ubo.box_project = probe->box_projection;
+ reflection_ubo.exposure_normalization = 1.0;
+
+ if (p_render_data->camera_attributes.is_valid()) {
+ float exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
+ reflection_ubo.exposure_normalization = exposure / probe->baked_exposure;
+ }
+
+ Color ambient_linear = probe->ambient_color.srgb_to_linear();
+ float interior_ambient_energy = probe->ambient_color_energy;
+ reflection_ubo.ambient[0] = ambient_linear.r * interior_ambient_energy;
+ reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy;
+ reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy;
+
+ Transform3D transform = rpi->transform;
+ Transform3D proj = (p_camera_inverse_transform * transform).inverse();
+ MaterialStorage::store_transform(proj, reflection_ubo.local_matrix);
+
+ // hook for subclass to do further processing.
+ RendererSceneRenderRD::get_singleton()->setup_added_reflection_probe(transform, extents);
+
+ rpi->last_pass = RSG::rasterizer->get_frame_number();
+ }
+
+ if (reflection_count) {
+ RD::get_singleton()->buffer_update(reflection_buffer, 0, reflection_count * sizeof(ReflectionData), reflections, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ }
+}
+
/* LIGHTMAP API */
RID LightStorage::lightmap_allocate() {
@@ -649,7 +1716,7 @@ void LightStorage::lightmap_free(RID p_rid) {
}
void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) {
- RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ TextureStorage *texture_storage = TextureStorage::get_singleton();
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
@@ -658,17 +1725,17 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
//erase lightmap users
if (lm->light_texture.is_valid()) {
- RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(lm->light_texture);
+ TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(lm->light_texture);
if (t) {
t->lightmap_users.erase(p_lightmap);
}
}
- RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(p_light);
+ TextureStorage::Texture *t = texture_storage->get_singleton()->get_texture(p_light);
lm->light_texture = p_light;
lm->uses_spherical_harmonics = p_uses_spherical_haromics;
- RID default_2d_array = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ RID default_2d_array = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
if (!t) {
if (using_lightmap_array) {
if (lm->array_index >= 0) {
@@ -830,3 +1897,550 @@ AABB LightStorage::lightmap_get_aabb(RID p_lightmap) const {
ERR_FAIL_COND_V(!lm, AABB());
return lm->bounds;
}
+
+/* LIGHTMAP INSTANCE */
+
+RID LightStorage::lightmap_instance_create(RID p_lightmap) {
+ LightmapInstance li;
+ li.lightmap = p_lightmap;
+ return lightmap_instance_owner.make_rid(li);
+}
+
+void LightStorage::lightmap_instance_free(RID p_lightmap) {
+ lightmap_instance_owner.free(p_lightmap);
+}
+
+void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap);
+ ERR_FAIL_COND(!li);
+ li->transform = p_transform;
+}
+
+/* SHADOW ATLAS API */
+
+RID LightStorage::shadow_atlas_create() {
+ return shadow_atlas_owner.make_rid(ShadowAtlas());
+}
+
+void LightStorage::shadow_atlas_free(RID p_atlas) {
+ shadow_atlas_set_size(p_atlas, 0);
+ shadow_atlas_owner.free(p_atlas);
+}
+
+void LightStorage::_update_shadow_atlas(ShadowAtlas *shadow_atlas) {
+ if (shadow_atlas->size > 0 && shadow_atlas->depth.is_null()) {
+ RD::TextureFormat tf;
+ tf.format = shadow_atlas->use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
+ tf.width = shadow_atlas->size;
+ tf.height = shadow_atlas->size;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ shadow_atlas->depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ Vector<RID> fb_tex;
+ fb_tex.push_back(shadow_atlas->depth);
+ shadow_atlas->fb = RD::get_singleton()->framebuffer_create(fb_tex);
+ }
+}
+
+void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_COND(p_size < 0);
+ p_size = next_power_of_2(p_size);
+
+ if (p_size == shadow_atlas->size && p_16_bits == shadow_atlas->use_16_bits) {
+ return;
+ }
+
+ // erasing atlas
+ if (shadow_atlas->depth.is_valid()) {
+ RD::get_singleton()->free(shadow_atlas->depth);
+ shadow_atlas->depth = RID();
+ }
+ for (int i = 0; i < 4; i++) {
+ //clear subdivisions
+ shadow_atlas->quadrants[i].shadows.clear();
+ shadow_atlas->quadrants[i].shadows.resize(1 << shadow_atlas->quadrants[i].subdivision);
+ }
+
+ //erase shadow atlas reference from lights
+ for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) {
+ LightInstance *li = light_instance_owner.get_or_null(E.key);
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+
+ //clear owners
+ shadow_atlas->shadow_owners.clear();
+
+ shadow_atlas->size = p_size;
+ shadow_atlas->use_16_bits = p_16_bits;
+}
+
+void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_INDEX(p_quadrant, 4);
+ ERR_FAIL_INDEX(p_subdivision, 16384);
+
+ uint32_t subdiv = next_power_of_2(p_subdivision);
+ if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer
+ subdiv <<= 1;
+ }
+
+ subdiv = int(Math::sqrt((float)subdiv));
+
+ //obtain the number that will be x*x
+
+ if (shadow_atlas->quadrants[p_quadrant].subdivision == subdiv) {
+ return;
+ }
+
+ //erase all data from quadrant
+ for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
+ if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
+ shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+ }
+
+ shadow_atlas->quadrants[p_quadrant].shadows.clear();
+ shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv * subdiv);
+ shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
+
+ //cache the smallest subdiv (for faster allocation in light update)
+
+ shadow_atlas->smallest_subdiv = 1 << 30;
+
+ for (int i = 0; i < 4; i++) {
+ if (shadow_atlas->quadrants[i].subdivision) {
+ shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
+ }
+ }
+
+ if (shadow_atlas->smallest_subdiv == 1 << 30) {
+ shadow_atlas->smallest_subdiv = 0;
+ }
+
+ //resort the size orders, simple bublesort for 4 elements..
+
+ int swaps = 0;
+ do {
+ swaps = 0;
+
+ for (int i = 0; i < 3; i++) {
+ if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
+ SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
+ swaps++;
+ }
+ }
+ } while (swaps > 0);
+}
+
+bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ //look for an empty space
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
+
+ int found_free_idx = -1; //found a free one
+ int found_used_idx = -1; //found existing one, must steal it
+ uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion)
+
+ for (int j = 0; j < sc; j++) {
+ if (!sarr[j].owner.is_valid()) {
+ found_free_idx = j;
+ break;
+ }
+
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass != RendererSceneRenderRD::get_singleton()->get_scene_pass()) {
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+
+ if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
+ found_used_idx = j;
+ min_pass = sli->last_scene_pass;
+ }
+ }
+ }
+
+ if (found_free_idx == -1 && found_used_idx == -1) {
+ continue; //nothing found
+ }
+
+ if (found_free_idx == -1 && found_used_idx != -1) {
+ found_free_idx = found_used_idx;
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_free_idx;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool LightStorage::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ //look for an empty space
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+ const ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptr();
+
+ int found_idx = -1;
+ uint64_t min_pass = 0; // sum of currently selected spots, try to get the least recently used pair
+
+ for (int j = 0; j < sc - 1; j++) {
+ uint64_t pass = 0;
+
+ if (sarr[j].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == RendererSceneRenderRD::get_singleton()->get_scene_pass()) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (sarr[j + 1].owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass == RendererSceneRenderRD::get_singleton()->get_scene_pass()) {
+ continue;
+ }
+
+ //was just allocated, don't kill it so soon, wait a bit..
+ if (p_tick - sarr[j + 1].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+ pass += sli->last_scene_pass;
+ }
+
+ if (found_idx == -1 || pass < min_pass) {
+ found_idx = j;
+ min_pass = pass;
+
+ // we found two empty spots, no need to check the rest
+ if (pass == 0) {
+ break;
+ }
+ }
+ }
+
+ if (found_idx == -1) {
+ continue; //nothing found
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_idx;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!shadow_atlas, false);
+
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND_V(!li, false);
+
+ if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
+ return false;
+ }
+
+ uint32_t quad_size = shadow_atlas->size >> 1;
+ int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
+
+ int valid_quadrants[4];
+ int valid_quadrant_count = 0;
+ int best_size = -1; //best size found
+ int best_subdiv = -1; //subdiv for the best size
+
+ //find the quadrants this fits into, and the best possible size it can fit into
+ for (int i = 0; i < 4; i++) {
+ int q = shadow_atlas->size_order[i];
+ int sd = shadow_atlas->quadrants[q].subdivision;
+ if (sd == 0) {
+ continue; //unused
+ }
+
+ int max_fit = quad_size / sd;
+
+ if (best_size != -1 && max_fit > best_size) {
+ break; //too large
+ }
+
+ valid_quadrants[valid_quadrant_count++] = q;
+ best_subdiv = sd;
+
+ if (max_fit >= desired_fit) {
+ best_size = max_fit;
+ }
+ }
+
+ ERR_FAIL_COND_V(valid_quadrant_count == 0, false);
+
+ uint64_t tick = OS::get_singleton()->get_ticks_msec();
+
+ uint32_t old_key = SHADOW_INVALID;
+ uint32_t old_quadrant = SHADOW_INVALID;
+ uint32_t old_shadow = SHADOW_INVALID;
+ int old_subdivision = -1;
+
+ bool should_realloc = false;
+ bool should_redraw = false;
+
+ if (shadow_atlas->shadow_owners.has(p_light_instance)) {
+ old_key = shadow_atlas->shadow_owners[p_light_instance];
+ old_quadrant = (old_key >> QUADRANT_SHIFT) & 0x3;
+ old_shadow = old_key & SHADOW_INDEX_MASK;
+
+ should_realloc = shadow_atlas->quadrants[old_quadrant].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+ should_redraw = shadow_atlas->quadrants[old_quadrant].shadows[old_shadow].version != p_light_version;
+
+ if (!should_realloc) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = p_light_version;
+ //already existing, see if it should redraw or it's just OK
+ return should_redraw;
+ }
+
+ old_subdivision = shadow_atlas->quadrants[old_quadrant].subdivision;
+ }
+
+ bool is_omni = li->light_type == RS::LIGHT_OMNI;
+ bool found_shadow = false;
+ int new_quadrant = -1;
+ int new_shadow = -1;
+
+ if (is_omni) {
+ found_shadow = _shadow_atlas_find_omni_shadows(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ } else {
+ found_shadow = _shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, old_subdivision, tick, new_quadrant, new_shadow);
+ }
+
+ if (found_shadow) {
+ if (old_quadrant != SHADOW_INVALID) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow].owner = RID();
+
+ if (old_key & OMNI_LIGHT_FLAG) {
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].version = 0;
+ shadow_atlas->quadrants[old_quadrant].shadows.write[old_shadow + 1].owner = RID();
+ }
+ }
+
+ uint32_t new_key = new_quadrant << QUADRANT_SHIFT;
+ new_key |= new_shadow;
+
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ _shadow_atlas_invalidate_shadow(sh, p_atlas, shadow_atlas, new_quadrant, new_shadow);
+
+ sh->owner = p_light_instance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
+
+ if (is_omni) {
+ new_key |= OMNI_LIGHT_FLAG;
+
+ int new_omni_shadow = new_shadow + 1;
+ ShadowAtlas::Quadrant::Shadow *extra_sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_omni_shadow];
+ _shadow_atlas_invalidate_shadow(extra_sh, p_atlas, shadow_atlas, new_quadrant, new_omni_shadow);
+
+ extra_sh->owner = p_light_instance;
+ extra_sh->alloc_tick = tick;
+ extra_sh->version = p_light_version;
+ }
+
+ li->shadow_atlases.insert(p_atlas);
+
+ //update it in map
+ shadow_atlas->shadow_owners[p_light_instance] = new_key;
+ //make it dirty, as it should redraw anyway
+ return true;
+ }
+
+ return should_redraw;
+}
+
+void LightStorage::_shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) {
+ if (p_shadow->owner.is_valid()) {
+ LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner);
+ uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner];
+
+ if (old_key & OMNI_LIGHT_FLAG) {
+ uint32_t s = old_key & SHADOW_INDEX_MASK;
+ uint32_t omni_shadow_idx = p_shadow_idx + (s == (uint32_t)p_shadow_idx ? 1 : -1);
+ ShadowAtlas::Quadrant::Shadow *omni_shadow = &p_shadow_atlas->quadrants[p_quadrant].shadows.write[omni_shadow_idx];
+ omni_shadow->version = 0;
+ omni_shadow->owner = RID();
+ }
+
+ p_shadow_atlas->shadow_owners.erase(p_shadow->owner);
+ p_shadow->version = 0;
+ p_shadow->owner = RID();
+ sli->shadow_atlases.erase(p_atlas);
+ }
+}
+
+void LightStorage::shadow_atlas_update(RID p_atlas) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+
+ _update_shadow_atlas(shadow_atlas);
+}
+
+/* DIRECTIONAL SHADOW */
+
+void LightStorage::update_directional_shadow_atlas() {
+ if (directional_shadow.depth.is_null() && directional_shadow.size > 0) {
+ RD::TextureFormat tf;
+ tf.format = directional_shadow.use_16_bits ? RD::DATA_FORMAT_D16_UNORM : RD::DATA_FORMAT_D32_SFLOAT;
+ tf.width = directional_shadow.size;
+ tf.height = directional_shadow.size;
+ tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+
+ directional_shadow.depth = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ Vector<RID> fb_tex;
+ fb_tex.push_back(directional_shadow.depth);
+ directional_shadow.fb = RD::get_singleton()->framebuffer_create(fb_tex);
+ }
+}
+void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+ p_size = nearest_power_of_2_templated(p_size);
+
+ if (directional_shadow.size == p_size && directional_shadow.use_16_bits == p_16_bits) {
+ return;
+ }
+
+ directional_shadow.size = p_size;
+ directional_shadow.use_16_bits = p_16_bits;
+
+ if (directional_shadow.depth.is_valid()) {
+ RD::get_singleton()->free(directional_shadow.depth);
+ directional_shadow.depth = RID();
+ RendererSceneRenderRD::get_singleton()->base_uniforms_changed();
+ }
+}
+
+void LightStorage::set_directional_shadow_count(int p_count) {
+ directional_shadow.light_count = p_count;
+ directional_shadow.current_light = 0;
+}
+
+static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
+ int split_h = 1;
+ int split_v = 1;
+
+ while (split_h * split_v < p_shadow_count) {
+ if (split_h == split_v) {
+ split_h <<= 1;
+ } else {
+ split_v <<= 1;
+ }
+ }
+
+ Rect2i rect(0, 0, p_size, p_size);
+ rect.size.width /= split_h;
+ rect.size.height /= split_v;
+
+ rect.position.x = rect.size.width * (p_shadow_index % split_h);
+ rect.position.y = rect.size.height * (p_shadow_index / split_h);
+
+ return rect;
+}
+
+Rect2i LightStorage::get_directional_shadow_rect() {
+ return _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
+}
+
+int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
+ ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
+
+ Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
+
+ LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance);
+ ERR_FAIL_COND_V(!light_instance, 0);
+
+ switch (light_directional_get_shadow_mode(light_instance->light)) {
+ case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
+ break; //none
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+ r.size.height /= 2;
+ break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
+ r.size /= 2;
+ break;
+ }
+
+ return MAX(r.size.width, r.size.height);
+}
+
+/* SHADOW CUBEMAPS */
+
+LightStorage::ShadowCubemap *LightStorage::_get_shadow_cubemap(int p_size) {
+ if (!shadow_cubemaps.has(p_size)) {
+ ShadowCubemap sc;
+ {
+ RD::TextureFormat tf;
+ tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D32_SFLOAT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D32_SFLOAT : RD::DATA_FORMAT_X8_D24_UNORM_PACK32;
+ tf.width = p_size;
+ tf.height = p_size;
+ tf.texture_type = RD::TEXTURE_TYPE_CUBE;
+ tf.array_layers = 6;
+ tf.usage_bits = RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+ sc.cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ }
+
+ for (int i = 0; i < 6; i++) {
+ RID side_texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), sc.cubemap, i, 0);
+ Vector<RID> fbtex;
+ fbtex.push_back(side_texture);
+ sc.side_fb[i] = RD::get_singleton()->framebuffer_create(fbtex);
+ }
+
+ shadow_cubemaps[p_size] = sc;
+ }
+
+ return &shadow_cubemaps[p_size];
+}
+
+RID LightStorage::get_cubemap(int p_size) {
+ ShadowCubemap *cubemap = _get_shadow_cubemap(p_size);
+
+ return cubemap->cubemap;
+}
+
+RID LightStorage::get_cubemap_fb(int p_size, int p_pass) {
+ ShadowCubemap *cubemap = _get_shadow_cubemap(p_size);
+
+ return cubemap->side_fb[p_pass];
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 4b34cc74cb..79006ad982 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -32,17 +32,32 @@
#define LIGHT_STORAGE_RD_H
#include "core/templates/local_vector.h"
+#include "core/templates/paged_array.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/environment/sky.h"
+#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
+struct RenderDataRD;
+
namespace RendererRD {
class LightStorage : public RendererLightStorage {
+public:
+ enum ShadowAtlastQuadrant {
+ QUADRANT_SHIFT = 27,
+ OMNI_LIGHT_FLAG = 1 << 26,
+ SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
+ SHADOW_INVALID = 0xFFFFFFFF
+ };
+
private:
static LightStorage *singleton;
+ uint32_t max_cluster_elements = 512;
/* LIGHT */
struct Light {
@@ -71,6 +86,135 @@ private:
mutable RID_Owner<Light, true> light_owner;
+ /* LIGHT INSTANCE */
+
+ struct LightInstance {
+ struct ShadowTransform {
+ Projection camera;
+ Transform3D transform;
+ float farplane;
+ float split;
+ float bias_scale;
+ float shadow_texel_size;
+ float range_begin;
+ Rect2 atlas_rect;
+ Vector2 uv_scale;
+ };
+
+ RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+ ShadowTransform shadow_transform[6];
+
+ AABB aabb;
+ RID self;
+ RID light;
+ Transform3D transform;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att = 0.0;
+
+ uint64_t shadow_pass = 0;
+ uint64_t last_scene_pass = 0;
+ uint64_t last_scene_shadow_pass = 0;
+ uint64_t last_pass = 0;
+ uint32_t cull_mask = 0;
+ uint32_t light_directional_index = 0;
+
+ Rect2 directional_rect;
+
+ HashSet<RID> shadow_atlases; //shadow atlases where this light is registered
+
+ ForwardID forward_id = -1;
+
+ LightInstance() {}
+ };
+
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
+ /* OMNI/SPOT LIGHT DATA */
+
+ struct LightData {
+ float position[3];
+ float inv_radius;
+ float direction[3]; // in omni, x and y are used for dual paraboloid offset
+ float size;
+
+ float color[3];
+ float attenuation;
+
+ float inv_spot_attenuation;
+ float cos_spot_angle;
+ float specular_amount;
+ float shadow_opacity;
+
+ float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
+ float shadow_matrix[16];
+ float shadow_bias;
+ float shadow_normal_bias;
+ float transmittance_bias;
+ float soft_shadow_size;
+ float soft_shadow_scale;
+ uint32_t mask;
+ float volumetric_fog_energy;
+ uint32_t bake_mode;
+ float projector_rect[4];
+ };
+
+ struct LightInstanceDepthSort {
+ float depth;
+ LightInstance *light_instance;
+ Light *light;
+ bool operator<(const LightInstanceDepthSort &p_sort) const {
+ return depth < p_sort.depth;
+ }
+ };
+
+ uint32_t max_lights;
+ uint32_t omni_light_count = 0;
+ uint32_t spot_light_count = 0;
+ LightData *omni_lights = nullptr;
+ LightData *spot_lights = nullptr;
+ LightInstanceDepthSort *omni_light_sort = nullptr;
+ LightInstanceDepthSort *spot_light_sort = nullptr;
+ RID omni_light_buffer;
+ RID spot_light_buffer;
+
+ /* DIRECTIONAL LIGHT DATA */
+
+ struct DirectionalLightData {
+ float direction[3];
+ float energy;
+ float color[3];
+ float size;
+ float specular;
+ uint32_t mask;
+ float softshadow_angle;
+ float soft_shadow_scale;
+ uint32_t blend_splits;
+ float shadow_opacity;
+ float fade_from;
+ float fade_to;
+ uint32_t pad[2];
+ uint32_t bake_mode;
+ float volumetric_fog_energy;
+ float shadow_bias[4];
+ float shadow_normal_bias[4];
+ float shadow_transmittance_bias[4];
+ float shadow_z_range[4];
+ float shadow_range_begin[4];
+ float shadow_split_offsets[4];
+ float shadow_matrices[4][16];
+ float uv_scale1[2];
+ float uv_scale2[2];
+ float uv_scale3[2];
+ float uv_scale4[2];
+ };
+
+ uint32_t max_directional_lights;
+ DirectionalLightData *directional_lights = nullptr;
+ RID directional_light_buffer;
+
/* REFLECTION PROBE */
struct ReflectionProbe {
@@ -94,6 +238,89 @@ private:
};
mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
+ /* REFLECTION ATLAS */
+
+ struct ReflectionAtlas {
+ int count = 0;
+ int size = 0;
+
+ RID reflection;
+ RID depth_buffer;
+ RID depth_fb;
+
+ struct Reflection {
+ RID owner;
+ RendererRD::SkyRD::ReflectionData data;
+ RID fbs[6];
+ };
+
+ Vector<Reflection> reflections;
+
+ ClusterBuilderRD *cluster_builder = nullptr; // only used if cluster builder is supported by the renderer.
+ };
+
+ mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ struct ReflectionProbeInstance {
+ RID probe;
+ int atlas_index = -1;
+ RID atlas;
+
+ bool dirty = true;
+ bool rendering = false;
+ int processing_layer = 1;
+ int processing_side = 0;
+
+ uint32_t render_step = 0;
+ uint64_t last_pass = 0;
+ uint32_t cull_mask = 0;
+
+ RendererRD::ForwardID forward_id = -1;
+
+ Transform3D transform;
+ };
+
+ mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+
+ /* REFLECTION DATA */
+
+ enum {
+ REFLECTION_AMBIENT_DISABLED = 0,
+ REFLECTION_AMBIENT_ENVIRONMENT = 1,
+ REFLECTION_AMBIENT_COLOR = 2,
+ };
+
+ struct ReflectionData {
+ float box_extents[3];
+ float index;
+ float box_offset[3];
+ uint32_t mask;
+ float ambient[3]; // ambient color,
+ float intensity;
+ uint32_t exterior;
+ uint32_t box_project;
+ uint32_t ambient_mode;
+ float exposure_normalization;
+ float local_matrix[16]; // up to here for spot and omni, rest is for directional
+ };
+
+ struct ReflectionProbeInstanceSort {
+ float depth;
+ ReflectionProbeInstance *probe_instance;
+ bool operator<(const ReflectionProbeInstanceSort &p_sort) const {
+ return depth < p_sort.depth;
+ }
+ };
+
+ uint32_t max_reflections;
+ uint32_t reflection_count = 0;
+ // uint32_t max_reflection_probes_per_instance = 0; // seems unused
+ ReflectionData *reflections = nullptr;
+ ReflectionProbeInstanceSort *reflection_sort = nullptr;
+ RID reflection_buffer;
+
/* LIGHTMAP */
struct Lightmap {
@@ -124,12 +351,101 @@ private:
mutable RID_Owner<Lightmap, true> lightmap_owner;
+ /* LIGHTMAP INSTANCE */
+
+ struct LightmapInstance {
+ RID lightmap;
+ Transform3D transform;
+ };
+
+ mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
+
+ /* SHADOW ATLAS */
+
+ uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+
+ struct ShadowShrinkStage {
+ RID texture;
+ RID filter_texture;
+ uint32_t size = 0;
+ };
+
+ struct ShadowAtlas {
+ struct Quadrant {
+ uint32_t subdivision = 0;
+
+ struct Shadow {
+ RID owner;
+ uint64_t version = 0;
+ uint64_t fog_version = 0; // used for fog
+ uint64_t alloc_tick = 0;
+
+ Shadow() {}
+ };
+
+ Vector<Shadow> shadows;
+
+ Quadrant() {}
+ } quadrants[4];
+
+ int size_order[4] = { 0, 1, 2, 3 };
+ uint32_t smallest_subdiv = 0;
+
+ int size = 0;
+ bool use_16_bits = true;
+
+ RID depth;
+ RID fb; //for copying
+
+ HashMap<RID, uint32_t> shadow_owners;
+ };
+
+ RID_Owner<ShadowAtlas> shadow_atlas_owner;
+
+ void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
+
+ void _shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
+ bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+ bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+
+ /* DIRECTIONAL SHADOW */
+
+ struct DirectionalShadow {
+ RID depth;
+ RID fb; //when renderign direct
+
+ int light_count = 0;
+ int size = 0;
+ bool use_16_bits = true;
+ int current_light = 0;
+ } directional_shadow;
+
+ /* SHADOW CUBEMAPS */
+
+ struct ShadowCubemap {
+ RID cubemap;
+ RID side_fb[6];
+ };
+
+ HashMap<int, ShadowCubemap> shadow_cubemaps;
+ ShadowCubemap *_get_shadow_cubemap(int p_size);
+
public:
static LightStorage *get_singleton();
LightStorage();
virtual ~LightStorage();
+ bool free(RID p_rid);
+
+ /* Settings */
+ void set_max_cluster_elements(const uint32_t p_max_cluster_elements) {
+ max_cluster_elements = p_max_cluster_elements;
+ set_max_reflection_probes(p_max_cluster_elements);
+ set_max_lights(p_max_cluster_elements);
+ }
+ uint32_t get_max_cluster_elements() const { return max_cluster_elements; }
+
/* LIGHT */
bool owns_light(RID p_rid) { return light_owner.owns(p_rid); };
@@ -259,6 +575,205 @@ public:
Dependency *light_get_dependency(RID p_light) const;
+ /* LIGHT INSTANCE API */
+
+ bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+
+ virtual RID light_instance_create(RID p_light) override;
+ virtual void light_instance_free(RID p_light) override;
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+ virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
+ virtual void light_instance_mark_visible(RID p_light_instance) override;
+
+ _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->light;
+ }
+
+ _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->transform;
+ }
+
+ _FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->aabb;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ li->cull_mask = p_cull_mask;
+ }
+
+ _FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->cull_mask;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ uint32_t key = shadow_atlas->shadow_owners[li->self];
+
+ uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+ uint32_t shadow = key & SHADOW_INDEX_MASK;
+
+ ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size >> 1;
+
+ uint32_t x = (quadrant & 1) * quadrant_size;
+ uint32_t y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ if (key & OMNI_LIGHT_FLAG) {
+ if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
+ r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
+ r_omni_offset.y = 1;
+ } else {
+ r_omni_offset.x = 1;
+ r_omni_offset.y = 0;
+ }
+ }
+
+ uint32_t width = shadow_size;
+ uint32_t height = shadow_size;
+
+ return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
+ }
+
+ _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
+#ifdef DEBUG_ENABLED
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
+#endif
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+ ERR_FAIL_COND_V(!shadow_atlas, 0);
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
+#endif
+ uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+
+ uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+
+ uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+
+ return float(1.0) / shadow_size;
+ }
+
+ _FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].camera;
+ }
+
+ _FORCE_INLINE_ Transform3D
+ light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].transform;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].bias_scale;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].farplane;
+ }
+ _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].range_begin;
+ }
+
+ _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].uv_scale;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ li->shadow_transform[p_index].atlas_rect = p_atlas_rect;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].atlas_rect;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].split;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->shadow_transform[p_index].shadow_texel_size;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ li->last_pass = p_pass;
+ }
+
+ _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->last_pass;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ li->last_scene_shadow_pass = p_pass;
+ }
+
+ _FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->last_scene_shadow_pass;
+ }
+
+ _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->forward_id;
+ }
+
+ _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->light_type;
+ }
+
+ _FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ li->directional_rect = p_directional_rect;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) {
+ LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+ return li->directional_rect;
+ }
+
+ /* LIGHT DATA */
+
+ void free_light_data();
+ void set_max_lights(const uint32_t p_max_lights);
+ RID get_omni_light_buffer() { return omni_light_buffer; }
+ RID get_spot_light_buffer() { return spot_light_buffer; }
+ RID get_directional_light_buffer() { return directional_light_buffer; }
+ uint32_t get_max_directional_lights() { return max_directional_lights; }
+ bool has_directional_shadows(const uint32_t p_directional_light_count) {
+ for (uint32_t i = 0; i < p_directional_light_count; i++) {
+ if (directional_lights[i].shadow_opacity > 0.001) {
+ return true;
+ }
+ }
+ return false;
+ }
+ void update_light_buffers(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
+
/* REFLECTION PROBE */
bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); };
@@ -305,6 +820,94 @@ public:
Dependency *reflection_probe_get_dependency(RID p_probe) const;
+ /* REFLECTION ATLAS */
+
+ bool owns_reflection_atlas(RID p_rid) { return reflection_atlas_owner.owns(p_rid); }
+
+ virtual RID reflection_atlas_create() override;
+ virtual void reflection_atlas_free(RID p_ref_atlas) override;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
+
+ _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
+ ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->reflection;
+ }
+
+ /* REFLECTION PROBE INSTANCE */
+
+ bool owns_reflection_probe_instance(RID p_rid) { return reflection_probe_instance_owner.owns(p_rid); }
+
+ virtual RID reflection_probe_instance_create(RID p_probe) override;
+ virtual void reflection_probe_instance_free(RID p_instance) override;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
+
+ uint32_t reflection_probe_instance_get_resolution(RID p_instance);
+ RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
+ RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
+
+ _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, RID());
+
+ return rpi->probe;
+ }
+
+ _FORCE_INLINE_ RendererRD::ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ return rpi->forward_id;
+ }
+
+ _FORCE_INLINE_ void reflection_probe_instance_set_cull_mask(RID p_instance, uint32_t p_render_pass) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!rpi);
+ rpi->cull_mask = p_render_pass;
+ }
+
+ _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND(!rpi);
+ rpi->last_pass = p_render_pass;
+ }
+
+ _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, 0);
+
+ return rpi->last_pass;
+ }
+
+ _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, Transform3D());
+
+ return rpi->transform;
+ }
+
+ _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
+ ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+ ERR_FAIL_COND_V(!rpi, -1);
+
+ return rpi->atlas_index;
+ }
+
+ ClusterBuilderRD *reflection_probe_instance_get_cluster_builder(RID p_instance, ClusterBuilderSharedDataRD *p_cluster_builder_shared);
+
+ /* REFLECTION DATA */
+
+ void free_reflection_data();
+ void set_max_reflection_probes(const uint32_t p_max_reflection_probes);
+ RID get_reflection_probe_buffer() { return reflection_buffer; }
+ void update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
+
/* LIGHTMAP */
bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); };
@@ -366,6 +969,111 @@ public:
ERR_FAIL_COND_V(!using_lightmap_array, lightmap_textures); //only for arrays
return lightmap_textures;
}
+
+ /* LIGHTMAP INSTANCE */
+
+ bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); };
+
+ virtual RID lightmap_instance_create(RID p_lightmap) override;
+ virtual void lightmap_instance_free(RID p_lightmap) override;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
+ _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
+ return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr;
+ }
+
+ _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
+ return li->lightmap;
+ }
+ _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
+ LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
+ return li->transform;
+ }
+
+ /* SHADOW ATLAS API */
+
+ bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); };
+
+ virtual RID shadow_atlas_create() override;
+ virtual void shadow_atlas_free(RID p_atlas) override;
+
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
+ _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, false);
+ return atlas->shadow_owners.has(p_light_intance);
+ }
+ _FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, -1);
+ return atlas->shadow_owners[p_light_intance];
+ }
+
+ _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->depth;
+ }
+
+ _FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, 0);
+ return atlas->size;
+ }
+
+ _FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+ return atlas->quadrants[p_quadrant].shadows.size();
+ }
+
+ _FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, 0);
+ ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+ return atlas->quadrants[p_quadrant].subdivision;
+ }
+
+ _FORCE_INLINE_ RID shadow_atlas_get_fb(RID p_atlas) {
+ ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+ ERR_FAIL_COND_V(!atlas, RID());
+ return atlas->fb;
+ }
+
+ virtual void shadow_atlas_update(RID p_atlas) override;
+
+ /* DIRECTIONAL SHADOW */
+
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+ virtual void set_directional_shadow_count(int p_count) override;
+
+ Rect2i get_directional_shadow_rect();
+ void update_directional_shadow_atlas();
+
+ _FORCE_INLINE_ RID directional_shadow_get_texture() {
+ return directional_shadow.depth;
+ }
+
+ _FORCE_INLINE_ int directional_shadow_get_size() {
+ return directional_shadow.size;
+ }
+
+ _FORCE_INLINE_ RID direction_shadow_get_fb() {
+ return directional_shadow.fb;
+ }
+
+ _FORCE_INLINE_ void directional_shadow_increase_current_light() {
+ directional_shadow.current_light++;
+ }
+
+ /* SHADOW CUBEMAPS */
+
+ RID get_cubemap(int p_size);
+ RID get_cubemap_fb(int p_size, int p_pass);
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 70243a9275..6703d8e7d0 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -85,7 +85,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = v & 1 ? 1 : 0;
gui[1] = v & 2 ? 1 : 0;
}
@@ -112,7 +112,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
gui[j + 3] = 0; // ignored
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -141,7 +141,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
}
}
} else {
- int v = value;
+ uint32_t v = value;
gui[0] = (v & 1) ? 1 : 0;
gui[1] = (v & 2) ? 1 : 0;
gui[2] = (v & 4) ? 1 : 0;
@@ -720,7 +720,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
Projection v = value;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- gui[i * 4 + j] = v.matrix[i][j];
+ gui[i * 4 + j] = v.columns[i][j];
}
}
}
@@ -734,7 +734,7 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type,
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
- *gui = value[0].boolean ? 1 : 0;
+ gui[0] = value[0].boolean ? 1 : 0;
} break;
case ShaderLanguage::TYPE_BVEC2: {
uint32_t *gui = (uint32_t *)data;
@@ -903,7 +903,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
case ShaderLanguage::TYPE_UVEC3:
- case ShaderLanguage::TYPE_VEC3:
+ case ShaderLanguage::TYPE_VEC3: {
+ memset(data, 0, 12 * p_array_size);
+ } break;
case ShaderLanguage::TYPE_BVEC4:
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
@@ -1270,7 +1272,7 @@ void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_se
}
}
-bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) {
+bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier) {
if ((uint32_t)ubo_data.size() != p_ubo_size) {
p_uniform_dirty = true;
if (uniform_buffer.is_valid()) {
@@ -1294,7 +1296,7 @@ bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<
//check whether buffer changed
if (p_uniform_dirty && ubo_data.size()) {
- update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), true);
+ update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), p_use_linear_color);
RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier);
}
@@ -1528,6 +1530,18 @@ MaterialStorage::~MaterialStorage() {
singleton = nullptr;
}
+bool MaterialStorage::free(RID p_rid) {
+ if (owns_shader(p_rid)) {
+ shader_free(p_rid);
+ return true;
+ } else if (owns_material(p_rid)) {
+ material_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
/* Samplers */
void MaterialStorage::sampler_rd_configure_custom(float p_mipmap_bias) {
@@ -2099,7 +2113,7 @@ void MaterialStorage::global_shader_parameters_load_settings(bool p_load_texture
for (const PropertyInfo &E : settings) {
if (E.name.begins_with("shader_globals/")) {
StringName name = E.name.get_slice("/", 1);
- Dictionary d = ProjectSettings::get_singleton()->get(E.name);
+ Dictionary d = GLOBAL_GET(E.name);
ERR_CONTINUE(!d.has("type"));
ERR_CONTINUE(!d.has("value"));
@@ -2199,7 +2213,7 @@ void MaterialStorage::global_shader_parameters_instance_free(RID p_instance) {
global_shader_uniforms.instance_buffer_pos.erase(p_instance);
}
-void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) {
+void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count) {
if (!global_shader_uniforms.instance_buffer_pos.has(p_instance)) {
return; //just not allocated, ignore
}
@@ -2209,7 +2223,9 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
return; //again, not allocated, ignore
}
ERR_FAIL_INDEX(p_index, ShaderLanguage::MAX_INSTANCE_UNIFORM_INDICES);
- ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+
+ Variant::Type value_type = p_value.get_type();
+ ERR_FAIL_COND_MSG(p_value.get_type() > Variant::COLOR, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
const ShaderLanguage::DataType datatype_from_value[Variant::COLOR + 1] = {
ShaderLanguage::TYPE_MAX, //nil
@@ -2235,9 +2251,23 @@ void MaterialStorage::global_shader_parameters_instance_update(RID p_instance, i
ShaderLanguage::TYPE_VEC4 //color
};
- ShaderLanguage::DataType datatype = datatype_from_value[p_value.get_type()];
-
- ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(p_value.get_type())); //anything greater not supported
+ ShaderLanguage::DataType datatype = ShaderLanguage::TYPE_MAX;
+ if (value_type == Variant::INT && p_flags_count > 0) {
+ switch (p_flags_count) {
+ case 1:
+ datatype = ShaderLanguage::TYPE_BVEC2;
+ break;
+ case 2:
+ datatype = ShaderLanguage::TYPE_BVEC3;
+ break;
+ case 3:
+ datatype = ShaderLanguage::TYPE_BVEC4;
+ break;
+ }
+ } else {
+ datatype = datatype_from_value[value_type];
+ }
+ ERR_FAIL_COND_MSG(datatype == ShaderLanguage::TYPE_MAX, "Unsupported variant type for instance parameter: " + Variant::get_type_name(value_type)); //anything greater not supported
pos += p_index;
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index 2ce6550cc1..fb25e56ed3 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -79,7 +79,7 @@ public:
virtual ~MaterialData();
//to be used internally by update_parameters, in the most common configuration of material parameters
- bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, bool p_use_linear_color, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
void free_parameters_uniform_set(RID p_uniform_set);
private:
@@ -231,6 +231,8 @@ public:
MaterialStorage();
virtual ~MaterialStorage();
+ bool free(RID p_rid);
+
/* Helpers */
static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) {
@@ -300,7 +302,7 @@ public:
static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ p_array[i * 4 + j] = p_mtx.columns[i][j];
}
}
}
@@ -359,7 +361,7 @@ public:
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) override;
virtual void global_shader_parameters_instance_free(RID p_instance) override;
- virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) override;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override;
RID global_shader_uniforms_get_storage_buffer() const;
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index b089b96101..1e74d31383 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -197,6 +197,24 @@ MeshStorage::~MeshStorage() {
singleton = nullptr;
}
+bool MeshStorage::free(RID p_rid) {
+ if (owns_mesh(p_rid)) {
+ mesh_free(p_rid);
+ return true;
+ } else if (owns_mesh_instance(p_rid)) {
+ mesh_instance_free(p_rid);
+ return true;
+ } else if (owns_multimesh(p_rid)) {
+ multimesh_free(p_rid);
+ return true;
+ } else if (owns_skeleton(p_rid)) {
+ skeleton_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
/* MESH API */
RID MeshStorage::mesh_allocate() {
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 622f3911c7..6a7400631d 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -308,6 +308,8 @@ public:
MeshStorage();
virtual ~MeshStorage();
+ bool free(RID p_rid);
+
RID get_default_rd_storage_buffer() const { return default_rd_storage_buffer; }
/* MESH API */
@@ -396,13 +398,11 @@ public:
return s->index_count ? s->index_count : s->vertex_count;
}
- _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t *r_index_count = nullptr) const {
+ _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
int32_t current_lod = -1;
- if (r_index_count) {
- *r_index_count = s->index_count;
- }
+ r_index_count = s->index_count;
for (uint32_t i = 0; i < s->lod_count; i++) {
float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold;
if (screen_size > p_mesh_lod_threshold) {
@@ -413,9 +413,7 @@ public:
if (current_lod == -1) {
return 0;
} else {
- if (r_index_count) {
- *r_index_count = s->lods[current_lod].index_count;
- }
+ r_index_count = s->lods[current_lod].index_count;
return current_lod + 1;
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 4dca2233fe..240f743387 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "particles_storage.h"
+
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/rendering_server_globals.h"
#include "texture_storage.h"
@@ -208,6 +209,21 @@ ParticlesStorage::~ParticlesStorage() {
singleton = nullptr;
}
+bool ParticlesStorage::free(RID p_rid) {
+ if (owns_particles(p_rid)) {
+ particles_free(p_rid);
+ return true;
+ } else if (owns_particles_collision(p_rid)) {
+ particles_collision_free(p_rid);
+ return true;
+ } else if (owns_particles_collision_instance(p_rid)) {
+ particles_collision_instance_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
/* PARTICLES */
RID ParticlesStorage::particles_allocate() {
@@ -1319,10 +1335,7 @@ void ParticlesStorage::update_particles() {
}
}
-#ifndef _MSC_VER
-#warning Should use display refresh rate for all this
-#endif
-
+ // TODO: Should use display refresh rate for all this.
float screen_hz = 60;
int fixed_fps = 0;
@@ -1697,7 +1710,7 @@ MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() {
}
bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
- return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3);
+ return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3, true);
}
ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() {
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index af29f5022b..017844626f 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -405,6 +405,8 @@ public:
ParticlesStorage();
virtual ~ParticlesStorage();
+ bool free(RID p_rid);
+
/* PARTICLES */
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 16fdbc07f5..0c2092f03e 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -40,11 +40,6 @@ RenderSceneBuffersRD::~RenderSceneBuffersRD() {
cleanup();
data_buffers.clear();
-
- // need to investigate if we can remove these things.
- if (cluster_builder) {
- memdelete(cluster_builder);
- }
}
void RenderSceneBuffersRD::_bind_methods() {
@@ -121,21 +116,6 @@ void RenderSceneBuffersRD::cleanup() {
RD::get_singleton()->free(luminance.current);
luminance.current = RID();
}
-
- if (ss_effects.linear_depth.is_valid()) {
- RD::get_singleton()->free(ss_effects.linear_depth);
- ss_effects.linear_depth = RID();
- ss_effects.linear_depth_slices.clear();
- }
-
- if (ss_effects.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects.downsample_uniform_set)) {
- RD::get_singleton()->free(ss_effects.downsample_uniform_set);
- ss_effects.downsample_uniform_set = RID();
- }
-
- sse->ssao_free(ss_effects.ssao);
- sse->ssil_free(ss_effects.ssil);
- sse->ssr_free(ssr);
}
void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
@@ -179,14 +159,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
use_debanding = p_use_debanding;
view_count = p_view_count;
- /* may move this into our clustered renderer data object */
- if (can_be_storage) {
- if (cluster_builder == nullptr) {
- cluster_builder = memnew(ClusterBuilderRD);
- }
- cluster_builder->set_shared(RendererSceneRenderRD::get_singleton()->get_cluster_builder_shared());
- }
-
// cleanout any old buffers we had.
cleanup();
@@ -206,7 +178,7 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
// Create our depth buffer
{
- // TODO If we have depth buffer supplied externally, pick this up
+ // TODO Lazy create this in case we've got an external depth buffer
RD::DataFormat format;
uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
@@ -233,11 +205,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
E.value->configure(this);
}
-
- if (cluster_builder) {
- RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- cluster_builder->setup(internal_size, max_cluster_elements, get_depth_texture(), sampler, get_internal_texture());
- }
}
void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {
@@ -523,6 +490,28 @@ Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const String
return ret;
}
+// Depth texture
+
+RID RenderSceneBuffersRD::get_depth_texture() {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RID depth = texture_storage->render_target_get_override_depth(render_target);
+ if (depth.is_valid()) {
+ return depth;
+ } else {
+ return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH);
+ }
+}
+
+RID RenderSceneBuffersRD::get_depth_texture(const uint32_t p_layer) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RID depth_slice = texture_storage->render_target_get_override_depth_slice(render_target, p_layer);
+ if (depth_slice.is_valid()) {
+ return depth_slice;
+ } else {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0);
+ }
+}
+
// Velocity texture.
void RenderSceneBuffersRD::ensure_velocity() {
@@ -549,6 +538,20 @@ void RenderSceneBuffersRD::ensure_velocity() {
}
}
+bool RenderSceneBuffersRD::has_velocity_buffer(bool p_has_msaa) {
+ if (p_has_msaa) {
+ return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA);
+ } else {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RID velocity = texture_storage->render_target_get_override_velocity(render_target);
+ if (velocity.is_valid()) {
+ return true;
+ } else {
+ return has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY);
+ }
+ }
+}
+
RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) {
if (p_get_msaa) {
if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA)) {
@@ -557,10 +560,28 @@ RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa) {
return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA);
}
} else {
- if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RID velocity = texture_storage->render_target_get_override_velocity(render_target);
+ if (velocity.is_valid()) {
+ return velocity;
+ } else if (!has_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY)) {
return RID();
} else {
return get_texture(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY);
}
}
}
+
+RID RenderSceneBuffersRD::get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) {
+ if (p_get_msaa) {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY_MSAA, p_layer, 0);
+ } else {
+ RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+ RID velocity_slice = texture_storage->render_target_get_override_velocity_slice(render_target, p_layer);
+ if (velocity_slice.is_valid()) {
+ return velocity_slice;
+ } else {
+ return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_VELOCITY, p_layer, 0);
+ }
+ }
+}
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 1975eec7b0..6907f69b93 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
@@ -31,19 +31,14 @@
#ifndef RENDER_SCENE_BUFFERS_RD_H
#define RENDER_SCENE_BUFFERS_RD_H
+#include "../effects/vrs.h"
+#include "../framebuffer_cache_rd.h"
#include "core/templates/hash_map.h"
-#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 "render_buffer_custom_data_rd.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
-#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
-#include "servers/rendering/renderer_rd/effects/ss_effects.h"
-#include "servers/rendering/renderer_rd/environment/fog.h"
-
#define RB_SCOPE_BUFFERS SNAME("render_buffers")
#define RB_SCOPE_VRS SNAME("VRS")
@@ -68,7 +63,6 @@ private:
bool can_be_storage = true;
uint32_t max_cluster_elements = 512;
RD::DataFormat base_data_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- RendererRD::SSEffects *sse = nullptr;
RendererRD::VRS *vrs = nullptr;
uint64_t auto_exposure_version = 1;
@@ -139,9 +133,9 @@ public:
// info from our renderer
void set_can_be_storage(const bool p_can_be_storage) { can_be_storage = p_can_be_storage; }
void set_max_cluster_elements(const uint32_t p_max_elements) { max_cluster_elements = p_max_elements; }
+ uint32_t get_max_cluster_elements() { return max_cluster_elements; }
void set_base_data_format(const RD::DataFormat p_base_data_format) { base_data_format = p_base_data_format; }
RD::DataFormat get_base_data_format() const { return base_data_format; }
- void set_sseffects(RendererRD::SSEffects *p_ss_effects) { sse = p_ss_effects; }
void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
void cleanup();
@@ -195,12 +189,8 @@ public:
return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_COLOR, p_layer, 0);
}
- _FORCE_INLINE_ RID get_depth_texture() const {
- return get_texture(RB_SCOPE_BUFFERS, RB_TEX_DEPTH);
- }
- _FORCE_INLINE_ RID get_depth_texture(const uint32_t p_layer) {
- return get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_DEPTH, p_layer, 0);
- }
+ RID get_depth_texture();
+ RID get_depth_texture(const uint32_t p_layer);
// back buffer (color)
RID get_back_buffer_texture() const { return has_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) ? get_texture(RB_SCOPE_BUFFERS, RB_TEX_BLUR_0) : RID(); } // We (re)use our blur texture here.
@@ -208,15 +198,13 @@ public:
// Velocity, currently only used by TAA (Clustered) but we'll be using this in other places soon too.
void ensure_velocity();
- bool has_velocity_buffer(bool p_has_msaa) { return has_texture(RB_SCOPE_BUFFERS, p_has_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY); }
+ bool has_velocity_buffer(bool p_has_msaa);
RID get_velocity_buffer(bool p_get_msaa);
- RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer) { return get_texture_slice(RB_SCOPE_BUFFERS, p_get_msaa ? RB_TEX_VELOCITY_MSAA : RB_TEX_VELOCITY, p_layer, 0); }
+ RID get_velocity_buffer(bool p_get_msaa, uint32_t p_layer);
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Everything after this needs to be re-evaluated, this is all old implementation
- ClusterBuilderRD *cluster_builder = nullptr;
-
struct WeightBuffers {
RID weight;
RID fb; // FB with both texture and weight writing into one level lower
@@ -233,24 +221,6 @@ public:
Vector<RID> fb;
RID current_fb;
} luminance;
-
- struct SSEffects {
- RID linear_depth;
- Vector<RID> linear_depth_slices;
-
- RID downsample_uniform_set;
-
- Projection last_frame_projection;
- Transform3D last_frame_transform;
-
- RendererRD::SSEffects::SSAORenderBuffers ssao;
- RendererRD::SSEffects::SSILRenderBuffers ssil;
- } ss_effects;
-
- RendererRD::SSEffects::SSRRenderBuffers ssr;
-
- RID get_ao_texture() const { return ss_effects.ssao.ao_final; }
- RID get_ssil_texture() const { return ss_effects.ssil.ssil_final; }
};
#endif // RENDER_SCENE_BUFFERS_RD_H
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
index c2dc7d5f4c..9c031acc1e 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -61,7 +61,6 @@ public:
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;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 21811068cd..bc70c57b69 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -29,8 +29,11 @@
/*************************************************************************/
#include "texture_storage.h"
+
#include "../effects/copy_effects.h"
+#include "../framebuffer_cache_rd.h"
#include "material_storage.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
using namespace RendererRD;
@@ -457,6 +460,8 @@ TextureStorage::TextureStorage() {
TextureStorage::~TextureStorage() {
rt_sdf.shader.version_free(rt_sdf.shader_version);
+ free_decal_data();
+
if (decal_atlas.textures.size()) {
ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
}
@@ -475,6 +480,27 @@ TextureStorage::~TextureStorage() {
singleton = nullptr;
}
+bool TextureStorage::free(RID p_rid) {
+ if (owns_texture(p_rid)) {
+ texture_free(p_rid);
+ return true;
+ } else if (owns_canvas_texture(p_rid)) {
+ canvas_texture_free(p_rid);
+ return true;
+ } else if (owns_decal(p_rid)) {
+ decal_free(p_rid);
+ return true;
+ } else if (owns_decal_instance(p_rid)) {
+ decal_instance_free(p_rid);
+ return true;
+ } else if (owns_render_target(p_rid)) {
+ render_target_free(p_rid);
+ return true;
+ }
+
+ return false;
+}
+
bool TextureStorage::can_create_resources_async() const {
return true;
}
@@ -1098,9 +1124,7 @@ void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
texture_2d_initialize(p_texture, image);
@@ -1109,9 +1133,7 @@ void TextureStorage::texture_2d_placeholder_initialize(RID p_texture) {
void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RS::TextureLayeredType p_layered_type) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -1130,9 +1152,7 @@ void TextureStorage::texture_2d_layered_placeholder_initialize(RID p_texture, RS
void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
//this could be better optimized to reuse an existing image , done this way
//for now to get it working
- Ref<Image> image;
- image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ Ref<Image> image = Image::create_empty(4, 4, false, Image::FORMAT_RGBA8);
image->fill(Color(1, 0, 1, 1));
Vector<Ref<Image>> images;
@@ -1155,9 +1175,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
#endif
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image;
- image.instantiate();
- image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
+ Ref<Image> image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
image->convert(tex->format);
@@ -1178,9 +1196,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons
Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer);
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image;
- image.instantiate();
- image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
+ Ref<Image> image = Image::create_from_data(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
if (tex->format != tex->validated_format) {
image->convert(tex->format);
@@ -1206,9 +1222,7 @@ Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
ERR_FAIL_COND_V(bs.offset + bs.buffer_size > (uint32_t)all_data.size(), Vector<Ref<Image>>());
Vector<uint8_t> sub_region = all_data.slice(bs.offset, bs.offset + bs.buffer_size);
- Ref<Image> img;
- img.instantiate();
- img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region);
+ Ref<Image> img = Image::create_from_data(bs.size.width, bs.size.height, false, tex->validated_format, sub_region);
ERR_FAIL_COND_V(img->is_empty(), Vector<Ref<Image>>());
if (tex->format != tex->validated_format) {
img->convert(tex->format);
@@ -1471,9 +1485,7 @@ Ref<Image> TextureStorage::_validate_texture_format(const Ref<Image> &p_image, T
} break;
case Image::FORMAT_RGBE9995: {
r_format.format = RD::DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32;
-#ifndef _MSC_VER
-#warning TODO need to make a function in Image to swap bits for this
-#endif
+ // TODO: Need to make a function in Image to swap bits for this.
r_format.swizzle_r = RD::TEXTURE_SWIZZLE_IDENTITY;
r_format.swizzle_g = RD::TEXTURE_SWIZZLE_IDENTITY;
r_format.swizzle_b = RD::TEXTURE_SWIZZLE_IDENTITY;
@@ -1888,7 +1900,7 @@ Dependency *TextureStorage::decal_get_dependency(RID p_decal) {
}
void TextureStorage::update_decal_atlas() {
- RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+ CopyEffects *copy_effects = CopyEffects::get_singleton();
ERR_FAIL_NULL(copy_effects);
if (!decal_atlas.dirty) {
@@ -2112,12 +2124,249 @@ void TextureStorage::texture_remove_from_decal_atlas(RID p_texture, bool p_panor
}
}
+/* DECAL INSTANCE API */
+
+RID TextureStorage::decal_instance_create(RID p_decal) {
+ DecalInstance di;
+ di.decal = p_decal;
+ di.forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(FORWARD_ID_TYPE_DECAL);
+ return decal_instance_owner.make_rid(di);
+}
+
+void TextureStorage::decal_instance_free(RID p_decal_instance) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ ForwardIDStorage::get_singleton()->free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id);
+ decal_instance_owner.free(p_decal_instance);
+}
+
+void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ ERR_FAIL_COND(!di);
+ di->transform = p_transform;
+}
+
+/* DECAL DATA API */
+
+void TextureStorage::free_decal_data() {
+ if (decal_buffer.is_valid()) {
+ RD::get_singleton()->free(decal_buffer);
+ decal_buffer = RID();
+ }
+
+ if (decals != nullptr) {
+ memdelete_arr(decals);
+ decals = nullptr;
+ }
+
+ if (decal_sort != nullptr) {
+ memdelete_arr(decal_sort);
+ decal_sort = nullptr;
+ }
+}
+
+void TextureStorage::set_max_decals(const uint32_t p_max_decals) {
+ max_decals = p_max_decals;
+ uint32_t decal_buffer_size = max_decals * sizeof(DecalData);
+ decals = memnew_arr(DecalData, max_decals);
+ decal_sort = memnew_arr(DecalInstanceSort, max_decals);
+ decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
+}
+
+void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
+ ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton();
+
+ Transform3D uv_xform;
+ uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
+ uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
+
+ uint32_t decals_size = p_decals.size();
+
+ decal_count = 0;
+
+ for (uint32_t i = 0; i < decals_size; i++) {
+ if (decal_count == max_decals) {
+ break;
+ }
+
+ DecalInstance *decal_instance = decal_instance_owner.get_or_null(p_decals[i]);
+ if (!decal_instance) {
+ continue;
+ }
+ Decal *decal = decal_owner.get_or_null(decal_instance->decal);
+
+ Transform3D xform = decal_instance->transform;
+
+ real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+
+ if (decal->distance_fade) {
+ float fade_begin = decal->distance_fade_begin;
+ float fade_length = decal->distance_fade_length;
+
+ if (distance > fade_begin) {
+ if (distance > fade_begin + fade_length) {
+ continue; // do not use this decal, its invisible
+ }
+ }
+ }
+
+ decal_sort[decal_count].decal_instance = decal_instance;
+ decal_sort[decal_count].decal = decal;
+ decal_sort[decal_count].depth = distance;
+ decal_count++;
+ }
+
+ if (decal_count > 0) {
+ SortArray<DecalInstanceSort> sort_array;
+ sort_array.sort(decal_sort, decal_count);
+ }
+
+ bool using_forward_ids = forward_id_storage->uses_forward_ids();
+ for (uint32_t i = 0; i < decal_count; i++) {
+ DecalInstance *decal_instance = decal_sort[i].decal_instance;
+ Decal *decal = decal_sort[i].decal;
+
+ if (using_forward_ids) {
+ forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i);
+ }
+
+ decal_instance->cull_mask = decal->cull_mask;
+
+ Transform3D xform = decal_instance->transform;
+ float fade = 1.0;
+
+ if (decal->distance_fade) {
+ const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ const float fade_begin = decal->distance_fade_begin;
+ const float fade_length = decal->distance_fade_length;
+
+ if (distance > fade_begin) {
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+ fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+ }
+ }
+
+ DecalData &dd = decals[i];
+
+ Vector3 decal_extents = decal->extents;
+
+ Transform3D scale_xform;
+ scale_xform.basis.scale(decal_extents);
+ Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse();
+ MaterialStorage::store_transform(to_decal_xform, dd.xform);
+
+ Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized();
+ normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+
+ dd.normal[0] = normal.x;
+ dd.normal[1] = normal.y;
+ dd.normal[2] = normal.z;
+ dd.normal_fade = decal->normal_fade;
+
+ RID albedo_tex = decal->textures[RS::DECAL_TEXTURE_ALBEDO];
+ RID emission_tex = decal->textures[RS::DECAL_TEXTURE_EMISSION];
+ if (albedo_tex.is_valid()) {
+ Rect2 rect = decal_atlas_get_texture_rect(albedo_tex);
+ dd.albedo_rect[0] = rect.position.x;
+ dd.albedo_rect[1] = rect.position.y;
+ dd.albedo_rect[2] = rect.size.x;
+ dd.albedo_rect[3] = rect.size.y;
+ } else {
+ if (!emission_tex.is_valid()) {
+ continue; //no albedo, no emission, no decal.
+ }
+ dd.albedo_rect[0] = 0;
+ dd.albedo_rect[1] = 0;
+ dd.albedo_rect[2] = 0;
+ dd.albedo_rect[3] = 0;
+ }
+
+ RID normal_tex = decal->textures[RS::DECAL_TEXTURE_NORMAL];
+
+ if (normal_tex.is_valid()) {
+ Rect2 rect = decal_atlas_get_texture_rect(normal_tex);
+ dd.normal_rect[0] = rect.position.x;
+ dd.normal_rect[1] = rect.position.y;
+ dd.normal_rect[2] = rect.size.x;
+ dd.normal_rect[3] = rect.size.y;
+
+ Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+ MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform);
+ } else {
+ dd.normal_rect[0] = 0;
+ dd.normal_rect[1] = 0;
+ dd.normal_rect[2] = 0;
+ dd.normal_rect[3] = 0;
+ }
+
+ RID orm_tex = decal->textures[RS::DECAL_TEXTURE_ORM];
+ if (orm_tex.is_valid()) {
+ Rect2 rect = decal_atlas_get_texture_rect(orm_tex);
+ dd.orm_rect[0] = rect.position.x;
+ dd.orm_rect[1] = rect.position.y;
+ dd.orm_rect[2] = rect.size.x;
+ dd.orm_rect[3] = rect.size.y;
+ } else {
+ dd.orm_rect[0] = 0;
+ dd.orm_rect[1] = 0;
+ dd.orm_rect[2] = 0;
+ dd.orm_rect[3] = 0;
+ }
+
+ if (emission_tex.is_valid()) {
+ Rect2 rect = decal_atlas_get_texture_rect(emission_tex);
+ dd.emission_rect[0] = rect.position.x;
+ dd.emission_rect[1] = rect.position.y;
+ dd.emission_rect[2] = rect.size.x;
+ dd.emission_rect[3] = rect.size.y;
+ } else {
+ dd.emission_rect[0] = 0;
+ dd.emission_rect[1] = 0;
+ dd.emission_rect[2] = 0;
+ dd.emission_rect[3] = 0;
+ }
+
+ Color modulate = decal->modulate;
+ dd.modulate[0] = modulate.r;
+ dd.modulate[1] = modulate.g;
+ dd.modulate[2] = modulate.b;
+ dd.modulate[3] = modulate.a * fade;
+ dd.emission_energy = decal->emission_energy * fade;
+ dd.albedo_mix = decal->albedo_mix;
+ dd.mask = decal->cull_mask;
+ dd.upper_fade = decal->upper_fade;
+ dd.lower_fade = decal->lower_fade;
+
+ // hook for subclass to do further processing.
+ RendererSceneRenderRD::get_singleton()->setup_added_decal(xform, decal_extents);
+ }
+
+ if (decal_count > 0) {
+ RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+ }
+}
+
/* RENDER TARGET API */
+RID TextureStorage::RenderTarget::get_framebuffer() {
+ // Note that if we're using an overridden color buffer, we're likely cycling through a texture chain.
+ // this is where our framebuffer cache comes in clutch..
+
+ if (msaa != RS::VIEWPORT_MSAA_DISABLED) {
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(view_count, color_multisample, overridden.color.is_valid() ? overridden.color : color);
+ } else {
+ return FramebufferCacheRD::get_singleton()->get_cache_multiview(view_count, overridden.color.is_valid() ? overridden.color : color);
+ }
+}
+
void TextureStorage::_clear_render_target(RenderTarget *rt) {
- //free in reverse dependency order
- if (rt->framebuffer.is_valid()) {
- RD::get_singleton()->free(rt->framebuffer);
+ // clear overrides, we assume these are freed by the object that created them
+ rt->overridden.color = RID();
+ rt->overridden.depth = RID();
+ rt->overridden.velocity = RID();
+ rt->overridden.cached_slices.clear(); // these are automatically freed when their parent textures are freed so just clear
+
+ // free in reverse dependency order
+ if (rt->framebuffer_uniform_set.is_valid()) {
rt->framebuffer_uniform_set = RID(); //chain deleted
}
@@ -2139,7 +2388,6 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
_render_target_clear_sdf(rt);
- rt->framebuffer = RID();
rt->color = RID();
rt->color_multisample = RID();
}
@@ -2187,11 +2435,10 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
}
}
+ // TODO see if we can lazy create this once we actually use it as we may not need to create this if we have an overridden color buffer...
rt->color = RD::get_singleton()->texture_create(rd_color_attachment_format, rd_view);
ERR_FAIL_COND(rt->color.is_null());
- Vector<RID> fb_textures;
-
if (rt->msaa != RS::VIEWPORT_MSAA_DISABLED) {
// Use the texture format of the color attachment for the multisample color attachment.
RD::TextureFormat rd_color_multisample_format = rd_color_attachment_format;
@@ -2202,18 +2449,12 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
RD::TEXTURE_SAMPLES_8,
};
rd_color_multisample_format.samples = texture_samples[rt->msaa];
+ rd_color_multisample_format.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
RD::TextureView rd_view_multisample;
rd_color_multisample_format.is_resolve_buffer = false;
rt->color_multisample = RD::get_singleton()->texture_create(rd_color_multisample_format, rd_view_multisample);
- fb_textures.push_back(rt->color_multisample);
ERR_FAIL_COND(rt->color_multisample.is_null());
}
- fb_textures.push_back(rt->color);
- rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
- if (rt->framebuffer.is_null()) {
- _clear_render_target(rt);
- ERR_FAIL_COND(rt->framebuffer.is_null());
- }
{ //update texture
@@ -2323,6 +2564,11 @@ void TextureStorage::render_target_set_position(RID p_render_target, int p_x, in
//unused for this render target
}
+Point2i TextureStorage::render_target_get_position(RID p_render_target) const {
+ //unused for this render target
+ return Point2i();
+}
+
void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
@@ -2334,6 +2580,13 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
}
}
+Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, Size2i());
+
+ return rt->size;
+}
+
RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
@@ -2341,7 +2594,84 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
return rt->texture;
}
-void TextureStorage::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
+void TextureStorage::render_target_set_override_color(RID p_render_target, RID p_texture) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->overridden.color = p_texture;
+}
+
+RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.color;
+}
+
+void TextureStorage::render_target_set_override_depth(RID p_render_target, RID p_texture) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->overridden.depth = p_texture;
+}
+
+RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.depth;
+}
+
+RID TextureStorage::render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (rt->overridden.depth.is_null()) {
+ return RID();
+ } else if (rt->view_count == 1) {
+ return rt->overridden.depth;
+ } else {
+ RenderTarget::RTOverridden::SliceKey key(rt->overridden.depth, p_layer);
+
+ if (!rt->overridden.cached_slices.has(key)) {
+ rt->overridden.cached_slices[key] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->overridden.depth, p_layer, 0);
+ }
+
+ return rt->overridden.cached_slices[key];
+ }
+}
+
+void TextureStorage::render_target_set_override_velocity(RID p_render_target, RID p_texture) {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND(!rt);
+
+ rt->overridden.velocity = p_texture;
+}
+
+RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ return rt->overridden.velocity;
+}
+
+RID TextureStorage::render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, RID());
+
+ if (rt->overridden.velocity.is_null()) {
+ return RID();
+ } else if (rt->view_count == 1) {
+ return rt->overridden.velocity;
+ } else {
+ RenderTarget::RTOverridden::SliceKey key(rt->overridden.velocity, p_layer);
+
+ if (!rt->overridden.cached_slices.has(key)) {
+ rt->overridden.cached_slices[key] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rt->overridden.velocity, p_layer, 0);
+ }
+
+ return rt->overridden.cached_slices[key];
+ }
}
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_is_transparent) {
@@ -2351,10 +2681,21 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_i
_update_render_target(rt);
}
+bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
+ RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
+ ERR_FAIL_COND_V(!rt, false);
+
+ return rt->is_transparent;
+}
+
void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_value) {
}
-bool TextureStorage::render_target_was_used(RID p_render_target) {
+bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
+ return false;
+}
+
+bool TextureStorage::render_target_was_used(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, false);
return rt->was_used;
@@ -2377,25 +2718,29 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
_update_render_target(rt);
}
-Size2 TextureStorage::render_target_get_size(RID p_render_target) {
+RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2());
+ ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED);
- return rt->size;
+ return rt->msaa;
}
RID TextureStorage::render_target_get_rd_framebuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- return rt->framebuffer;
+ return rt->get_framebuffer();
}
RID TextureStorage::render_target_get_rd_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND_V(!rt, RID());
- return rt->color;
+ if (rt->overridden.color.is_valid()) {
+ return rt->overridden.color;
+ } else {
+ return rt->color;
+ }
}
RID TextureStorage::render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer) {
@@ -2466,7 +2811,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
}
Vector<Color> clear_colors;
clear_colors.push_back(rt->clear_color);
- RD::get_singleton()->draw_list_begin(rt->framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
+ RD::get_singleton()->draw_list_begin(rt->get_framebuffer(), RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, clear_colors);
RD::get_singleton()->draw_list_end();
rt->clear_requested = false;
}
@@ -2895,18 +3240,18 @@ void TextureStorage::render_target_set_vrs_mode(RID p_render_target, RS::Viewpor
rt->vrs_mode = p_mode;
}
-void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) {
+RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED);
- rt->vrs_texture = p_texture;
+ return rt->vrs_mode;
}
-RS::ViewportVRSMode TextureStorage::render_target_get_vrs_mode(RID p_render_target) const {
+void TextureStorage::render_target_set_vrs_texture(RID p_render_target, RID p_texture) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RS::VIEWPORT_VRS_DISABLED);
+ ERR_FAIL_COND(!rt);
- return rt->vrs_mode;
+ rt->vrs_texture = p_texture;
}
RID TextureStorage::render_target_get_vrs_texture(RID p_render_target) const {
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index a3acad30f3..00b4e50737 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -31,8 +31,12 @@
#ifndef TEXTURE_STORAGE_RD_H
#define TEXTURE_STORAGE_RD_H
+#include "core/templates/local_vector.h"
+#include "core/templates/paged_array.h"
#include "core/templates/rid_owner.h"
#include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
+#include "servers/rendering/rendering_server_default.h"
#include "servers/rendering/storage/texture_storage.h"
#include "servers/rendering/storage/utilities.h"
@@ -245,14 +249,58 @@ private:
};
mutable RID_Owner<Decal, true> decal_owner;
- Decal *get_decal(RID p_rid) const { return decal_owner.get_or_null(p_rid); };
+
+ /* DECAL INSTANCE */
+
+ struct DecalInstance {
+ RID decal;
+ Transform3D transform;
+ uint32_t cull_mask = 0;
+ RendererRD::ForwardID forward_id = -1;
+ };
+
+ mutable RID_Owner<DecalInstance> decal_instance_owner;
+
+ /* DECAL DATA (UBO) */
+
+ struct DecalData {
+ float xform[16];
+ float inv_extents[3];
+ float albedo_mix;
+ float albedo_rect[4];
+ float normal_rect[4];
+ float orm_rect[4];
+ float emission_rect[4];
+ float modulate[4];
+ float emission_energy;
+ uint32_t mask;
+ float upper_fade;
+ float lower_fade;
+ float normal_xform[12];
+ float normal[3];
+ float normal_fade;
+ };
+
+ struct DecalInstanceSort {
+ float depth;
+ DecalInstance *decal_instance;
+ Decal *decal;
+ bool operator<(const DecalInstanceSort &p_sort) const {
+ return depth < p_sort.depth;
+ }
+ };
+
+ uint32_t max_decals = 0;
+ uint32_t decal_count = 0;
+ DecalData *decals = nullptr;
+ DecalInstanceSort *decal_sort = nullptr;
+ RID decal_buffer;
/* RENDER TARGET API */
struct RenderTarget {
Size2i size;
uint32_t view_count;
- RID framebuffer;
RID color;
Vector<RID> color_slices;
RID color_multisample; // Needed when MSAA is enabled.
@@ -290,6 +338,43 @@ private:
RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED;
RID vrs_texture;
+ // overridden textures
+ struct RTOverridden {
+ RID color;
+ RID depth;
+ RID velocity;
+
+ // In a multiview scenario, which is the most likely where we
+ // override our destination textures, we need to obtain slices
+ // for each layer of these textures.
+ // These are likely changing every frame as we loop through
+ // texture chains hence we add a cache to manage these slices.
+ // For this we define a key using the RID of the texture and
+ // the layer for which we create a slice.
+ struct SliceKey {
+ RID rid;
+ uint32_t layer = 0;
+
+ bool operator==(const SliceKey &p_val) const {
+ return (rid == p_val.rid) && (layer == p_val.layer);
+ }
+
+ static uint32_t hash(const SliceKey &p_val) {
+ uint32_t h = hash_one_uint64(p_val.rid.get_id());
+ h = hash_murmur3_one_32(p_val.layer, h);
+ return hash_fmix32(h);
+ }
+
+ SliceKey() {}
+ SliceKey(RID p_rid, uint32_t p_layer) {
+ rid = p_rid;
+ layer = p_layer;
+ }
+ };
+
+ mutable HashMap<SliceKey, RID, SliceKey> cached_slices;
+ } overridden;
+
//texture generated for this owner (nor RD).
RID texture;
bool was_used;
@@ -297,6 +382,8 @@ private:
//clear request
bool clear_requested;
Color clear_color;
+
+ RID get_framebuffer();
};
mutable RID_Owner<RenderTarget> render_target_owner;
@@ -343,6 +430,8 @@ public:
TextureStorage();
virtual ~TextureStorage();
+ bool free(RID p_rid);
+
/* Canvas Texture API */
bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); };
@@ -545,6 +634,46 @@ public:
virtual AABB decal_get_aabb(RID p_decal) const override;
Dependency *decal_get_dependency(RID p_decal);
+ /* DECAL INSTANCE API */
+
+ bool owns_decal_instance(RID p_rid) const { return decal_instance_owner.owns(p_rid); }
+
+ virtual RID decal_instance_create(RID p_decal) override;
+ virtual void decal_instance_free(RID p_decal_instance) override;
+ virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override;
+
+ _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ return di->decal;
+ }
+
+ _FORCE_INLINE_ RendererRD::ForwardID decal_instance_get_forward_id(RID p_decal_instance) const {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ return di->forward_id;
+ }
+
+ _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal_instance) const {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ return di->transform;
+ }
+
+ _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal_instance) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ return di->forward_id;
+ }
+
+ _FORCE_INLINE_ void decal_instance_set_cullmask(RID p_decal_instance, uint32_t p_cull_mask) const {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ di->cull_mask = p_cull_mask;
+ }
+
+ /* DECAL DATA API */
+
+ void free_decal_data();
+ void set_max_decals(const uint32_t p_max_decals);
+ RID get_decal_buffer() { return decal_buffer; }
+ void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
+
/* RENDER TARGET API */
bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); };
@@ -553,14 +682,17 @@ public:
virtual void render_target_free(RID p_rid) override;
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
+ virtual Point2i render_target_get_position(RID p_render_target) const override;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
- virtual RID render_target_get_texture(RID p_render_target) override;
- virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
+ virtual Size2i render_target_get_size(RID p_render_target) const override;
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) override;
+ virtual bool render_target_get_transparent(RID p_render_target) const override;
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) override;
- virtual bool render_target_was_used(RID p_render_target) override;
+ virtual bool render_target_get_direct_to_screen(RID p_render_target) const override;
+ virtual bool render_target_was_used(RID p_render_target) const override;
virtual void render_target_set_as_unused(RID p_render_target) override;
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) override;
+ virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const override;
void render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps);
void render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color);
@@ -582,12 +714,21 @@ public:
bool render_target_is_sdf_enabled(RID p_render_target) const;
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) override;
+ virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const override;
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) override;
+ virtual RID render_target_get_vrs_texture(RID p_render_target) const override;
- RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const;
- RID render_target_get_vrs_texture(RID p_render_target) const;
+ virtual void render_target_set_override_color(RID p_render_target, RID p_texture) override;
+ virtual RID render_target_get_override_color(RID p_render_target) const override;
+ virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) override;
+ virtual RID render_target_get_override_depth(RID p_render_target) const override;
+ RID render_target_get_override_depth_slice(RID p_render_target, const uint32_t p_layer) const;
+ virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) override;
+ virtual RID render_target_get_override_velocity(RID p_render_target) const override;
+ RID render_target_get_override_velocity_slice(RID p_render_target, const uint32_t p_layer) const;
+
+ virtual RID render_target_get_texture(RID p_render_target) override;
- Size2 render_target_get_size(RID p_render_target);
RID render_target_get_rd_framebuffer(RID p_render_target);
RID render_target_get_rd_texture(RID p_render_target);
RID render_target_get_rd_texture_slice(RID p_render_target, uint32_t p_layer);
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
index b80bcd514f..4048c46d28 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
@@ -89,49 +89,28 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
}
bool Utilities::free(RID p_rid) {
- if (RendererRD::TextureStorage::get_singleton()->owns_texture(p_rid)) {
- RendererRD::TextureStorage::get_singleton()->texture_free(p_rid);
- } else if (RendererRD::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) {
- RendererRD::TextureStorage::get_singleton()->canvas_texture_free(p_rid);
- } else if (RendererRD::MaterialStorage::get_singleton()->owns_shader(p_rid)) {
- RendererRD::MaterialStorage::get_singleton()->shader_free(p_rid);
- } else if (RendererRD::MaterialStorage::get_singleton()->owns_material(p_rid)) {
- RendererRD::MaterialStorage::get_singleton()->material_free(p_rid);
- } else if (RendererRD::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
- RendererRD::MeshStorage::get_singleton()->mesh_free(p_rid);
- } else if (RendererRD::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
- RendererRD::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
- } else if (RendererRD::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
- RendererRD::MeshStorage::get_singleton()->multimesh_free(p_rid);
- } else if (RendererRD::MeshStorage::get_singleton()->owns_skeleton(p_rid)) {
- RendererRD::MeshStorage::get_singleton()->skeleton_free(p_rid);
- } else if (RendererRD::LightStorage::get_singleton()->owns_reflection_probe(p_rid)) {
- RendererRD::LightStorage::get_singleton()->reflection_probe_free(p_rid);
- } else if (RendererRD::TextureStorage::get_singleton()->owns_decal(p_rid)) {
- RendererRD::TextureStorage::get_singleton()->decal_free(p_rid);
+ if (RendererRD::LightStorage::get_singleton()->free(p_rid)) {
+ return true;
+ } else if (RendererRD::MaterialStorage::get_singleton()->free(p_rid)) {
+ return true;
+ } else if (RendererRD::MeshStorage::get_singleton()->free(p_rid)) {
+ return true;
+ } else if (RendererRD::ParticlesStorage::get_singleton()->free(p_rid)) {
+ return true;
+ } else if (RendererRD::TextureStorage::get_singleton()->free(p_rid)) {
+ return true;
} else if (RendererRD::GI::get_singleton()->owns_voxel_gi(p_rid)) {
RendererRD::GI::get_singleton()->voxel_gi_free(p_rid);
- } else if (RendererRD::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
- RendererRD::LightStorage::get_singleton()->lightmap_free(p_rid);
- } else if (RendererRD::LightStorage::get_singleton()->owns_light(p_rid)) {
- RendererRD::LightStorage::get_singleton()->light_free(p_rid);
- } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
- RendererRD::ParticlesStorage::get_singleton()->particles_free(p_rid);
- } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
- RendererRD::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
+ return true;
+ } else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) {
+ RendererRD::Fog::get_singleton()->fog_volume_free(p_rid);
+ return true;
} else if (owns_visibility_notifier(p_rid)) {
visibility_notifier_free(p_rid);
- } else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
- RendererRD::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
- } else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) {
- RendererRD::Fog::get_singleton()->fog_free(p_rid);
- } else if (RendererRD::TextureStorage::get_singleton()->owns_render_target(p_rid)) {
- RendererRD::TextureStorage::get_singleton()->render_target_free(p_rid);
+ return true;
} else {
return false;
}
-
- return true;
}
/* DEPENDENCIES */
@@ -170,8 +149,8 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance
Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
p_instance->update_dependency(dependency);
} else if (Fog::get_singleton()->owns_fog_volume(p_base)) {
- Fog::FogVolume *fv = Fog::get_singleton()->get_fog_volume(p_base);
- p_instance->update_dependency(&fv->dependency);
+ Dependency *dependency = Fog::get_singleton()->fog_volume_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (owns_visibility_notifier(p_base)) {
VisibilityNotifier *vn = get_visibility_notifier(p_base);
p_instance->update_dependency(&vn->dependency);
@@ -342,3 +321,11 @@ RenderingDevice::DeviceType Utilities::get_video_adapter_type() const {
String Utilities::get_video_adapter_api_version() const {
return RenderingDevice::get_singleton()->get_device_api_version();
}
+
+Size2i Utilities::get_maximum_viewport_size() const {
+ RenderingDevice *device = RenderingDevice::get_singleton();
+
+ int max_x = device->limit_get(RenderingDevice::LIMIT_MAX_VIEWPORT_DIMENSIONS_X);
+ int max_y = device->limit_get(RenderingDevice::LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);
+ return Size2i(max_x, max_y);
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.h b/servers/rendering/renderer_rd/storage_rd/utilities.h
index a80eb8510e..dda656c380 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.h
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.h
@@ -115,6 +115,8 @@ public:
virtual String get_video_adapter_vendor() const override;
virtual RenderingDevice::DeviceType get_video_adapter_type() const override;
virtual String get_video_adapter_api_version() const override;
+
+ virtual Size2i get_maximum_viewport_size() const override;
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index c2dece8b46..348f6e4695 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -357,13 +357,14 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
Scenario *scenario = scenario_owner.get_or_null(p_rid);
scenario->self = p_rid;
- scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create();
- scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
- scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
- scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
- scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
- scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
- scenario->reflection_atlas = scene_render->reflection_atlas_create();
+ scenario->reflection_probe_shadow_atlas = RSG::light_storage->shadow_atlas_create();
+ RSG::light_storage->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
+
+ scenario->reflection_atlas = RSG::light_storage->reflection_atlas_create();
scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
scenario->instance_data.set_page_pool(&instance_data_page_pool);
@@ -393,7 +394,7 @@ void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_
void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
ERR_FAIL_COND(!scenario);
- scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
+ RSG::light_storage->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
}
bool RendererSceneCull::is_scenario(RID p_scenario) const {
@@ -534,7 +535,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
scenario->directional_lights.erase(light->D);
light->D = nullptr;
}
- scene_render->free(light->instance);
+ RSG::light_storage->light_instance_free(light->instance);
} break;
case RS::INSTANCE_PARTICLES_COLLISION: {
InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
@@ -549,14 +550,14 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
} break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
- scene_render->free(reflection_probe->instance);
+ RSG::light_storage->reflection_probe_instance_free(reflection_probe->instance);
if (reflection_probe->update_list.in_list()) {
reflection_probe_render_list.remove(&reflection_probe->update_list);
}
} break;
case RS::INSTANCE_DECAL: {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data);
- scene_render->free(decal->instance);
+ RSG::texture_storage->decal_instance_free(decal->instance);
} break;
case RS::INSTANCE_LIGHTMAP: {
@@ -565,7 +566,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
while (lightmap_data->users.begin()) {
instance_geometry_set_lightmap((*lightmap_data->users.begin())->self, RID(), Rect2(), 0);
}
- scene_render->free(lightmap_data->instance);
+ RSG::light_storage->lightmap_instance_free(lightmap_data->instance);
} break;
case RS::INSTANCE_VOXEL_GI: {
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
@@ -626,7 +627,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
light->D = scenario->directional_lights.push_back(instance);
}
- light->instance = scene_render->light_instance_create(p_base);
+ light->instance = RSG::light_storage->light_instance_create(p_base);
instance->base_data = light;
} break;
@@ -684,19 +685,19 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
reflection_probe->owner = instance;
instance->base_data = reflection_probe;
- reflection_probe->instance = scene_render->reflection_probe_instance_create(p_base);
+ reflection_probe->instance = RSG::light_storage->reflection_probe_instance_create(p_base);
} break;
case RS::INSTANCE_DECAL: {
InstanceDecalData *decal = memnew(InstanceDecalData);
decal->owner = instance;
instance->base_data = decal;
- decal->instance = scene_render->decal_instance_create(p_base);
+ decal->instance = RSG::texture_storage->decal_instance_create(p_base);
} break;
case RS::INSTANCE_LIGHTMAP: {
InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData);
instance->base_data = lightmap_data;
- lightmap_data->instance = scene_render->lightmap_instance_create(p_base);
+ lightmap_data->instance = RSG::light_storage->lightmap_instance_create(p_base);
} break;
case RS::INSTANCE_VOXEL_GI: {
InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData);
@@ -758,7 +759,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
} break;
case RS::INSTANCE_REFLECTION_PROBE: {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
- scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
+ RSG::light_storage->reflection_probe_release_atlas_index(reflection_probe->instance);
} break;
case RS::INSTANCE_PARTICLES_COLLISION: {
@@ -868,12 +869,7 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D
for (int i = 0; i < 4; i++) {
const Vector3 &v = i < 3 ? p_transform.basis.rows[i] : p_transform.origin;
- ERR_FAIL_COND(Math::is_inf(v.x));
- ERR_FAIL_COND(Math::is_nan(v.x));
- ERR_FAIL_COND(Math::is_inf(v.y));
- ERR_FAIL_COND(Math::is_nan(v.y));
- ERR_FAIL_COND(Math::is_inf(v.z));
- ERR_FAIL_COND(Math::is_nan(v.z));
+ ERR_FAIL_COND(!v.is_finite());
}
#endif
@@ -1453,8 +1449,23 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c
} else {
E->value.value = p_value;
if (E->value.index >= 0 && instance->instance_allocated_shader_uniforms) {
+ int flags_count = 0;
+ if (E->value.info.hint == PROPERTY_HINT_FLAGS) {
+ // A small hack to detect boolean flags count and prevent overhead.
+ switch (E->value.info.hint_string.length()) {
+ case 3: // "x,y"
+ flags_count = 1;
+ break;
+ case 5: // "x,y,z"
+ flags_count = 2;
+ break;
+ case 7: // "x,y,z,w"
+ flags_count = 3;
+ break;
+ }
+ }
//update directly
- RSG::material_storage->global_shader_parameters_instance_update(p_instance, E->value.index, p_value);
+ RSG::material_storage->global_shader_parameters_instance_update(p_instance, E->value.index, p_value, flags_count);
}
}
}
@@ -1502,8 +1513,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
if (p_instance->base_type == RS::INSTANCE_LIGHT) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
- scene_render->light_instance_set_transform(light->instance, p_instance->transform);
- scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
+ RSG::light_storage->light_instance_set_transform(light->instance, p_instance->transform);
+ RSG::light_storage->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
light->shadow_dirty = true;
RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
@@ -1526,7 +1537,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
- scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
+ RSG::light_storage->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
if (p_instance->scenario && p_instance->array_index >= 0) {
InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index];
@@ -1535,11 +1546,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
} else if (p_instance->base_type == RS::INSTANCE_DECAL) {
InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data);
- scene_render->decal_instance_set_transform(decal->instance, p_instance->transform);
+ RSG::texture_storage->decal_instance_set_transform(decal->instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
- scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
+ RSG::light_storage->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
} else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data);
@@ -2050,7 +2061,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
distances[splits] = max_distance;
- real_t texture_size = scene_render->get_directional_light_shadow_size(light->instance);
+ real_t texture_size = RSG::light_storage->get_directional_light_shadow_size(light->instance);
bool overlap = RSG::light_storage->light_directional_get_blend_splits(p_instance->base);
@@ -2241,7 +2252,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
case RS::LIGHT_OMNI: {
RS::LightOmniShadowMode shadow_mode = RSG::light_storage->light_omni_get_shadow_mode(p_instance->base);
- if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !scene_render->light_instances_can_render_shadow_cube()) {
+ if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !RSG::light_storage->light_instances_can_render_shadow_cube()) {
if (max_shadows_used + 2 > MAX_UPDATE_SHADOWS) {
return true;
}
@@ -2300,7 +2311,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
RSG::mesh_storage->update_mesh_instances();
- scene_render->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, i, 0);
+ RSG::light_storage->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, i, 0);
shadow_data.light = light->instance;
shadow_data.pass = i;
}
@@ -2376,14 +2387,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
}
RSG::mesh_storage->update_mesh_instances();
- scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
+ RSG::light_storage->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
shadow_data.light = light->instance;
shadow_data.pass = i;
}
//restore the regular DP matrix
- //scene_render->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, 0, 0);
+ //RSG::light_storage->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, 0, 0);
}
} break;
@@ -2440,7 +2451,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
RSG::mesh_storage->update_mesh_instances();
- scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
+ RSG::light_storage->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
shadow_data.light = light->instance;
shadow_data.pass = 0;
@@ -2680,14 +2691,14 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
cull_result.lights.push_back(idata.instance);
cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
if (cull_data.shadow_atlas.is_valid() && RSG::light_storage->light_has_shadow(idata.base_rid)) {
- scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
+ RSG::light_storage->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
}
} else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
if (cull_data.render_reflection_probe != idata.instance) {
//avoid entering The Matrix
- if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
+ if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || RSG::light_storage->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
cull_data.cull->lock.lock();
if (!reflection_probe->update_list.in_list()) {
@@ -2699,7 +2710,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
}
- if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
+ if (RSG::light_storage->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
}
}
@@ -2991,7 +3002,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
}
- scene_render->set_directional_shadow_count(lights_with_shadow.size());
+ RSG::light_storage->set_directional_shadow_count(lights_with_shadow.size());
for (int i = 0; i < lights_with_shadow.size(); i++) {
_light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect);
@@ -3091,7 +3102,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) {
const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j];
// print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size()));
- scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale);
+ RSG::light_storage->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale);
if (max_shadows_used == MAX_UPDATE_SHADOWS) {
continue;
}
@@ -3187,7 +3198,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
light->shadow_dirty = false;
}
- bool redraw = scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
+ bool redraw = RSG::light_storage->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
//must redraw!
@@ -3320,7 +3331,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
RenderingServerDefault::redraw_request(); //update, so it updates in editor
if (p_step == 0) {
- if (!scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
+ if (!RSG::light_storage->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
return true; //all full
}
}
@@ -3346,7 +3357,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
Vector3 extents = RSG::light_storage->reflection_probe_get_extents(p_instance->base);
Vector3 origin_offset = RSG::light_storage->reflection_probe_get_origin_offset(p_instance->base);
float max_distance = RSG::light_storage->reflection_probe_get_origin_max_distance(p_instance->base);
- float size = scene_render->reflection_atlas_get_size(scenario->reflection_atlas);
+ float size = RSG::light_storage->reflection_atlas_get_size(scenario->reflection_atlas);
float mesh_lod_threshold = RSG::light_storage->reflection_probe_get_mesh_lod_threshold(p_instance->base) / size;
Vector3 edge = view_normals[p_step] * extents;
@@ -3387,7 +3398,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
} else {
//do roughness postprocess step until it believes it's done
RENDER_TIMESTAMP("Post-Process ReflectionProbe, Step " + itos(p_step));
- return scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance);
+ return RSG::light_storage->reflection_probe_instance_postprocess_step(reflection_probe->instance);
}
return false;
@@ -3861,7 +3872,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
}
if (p_instance->material_overlay.is_valid()) {
- can_cast_shadows = can_cast_shadows || RSG::material_storage->material_casts_shadows(p_instance->material_overlay);
+ can_cast_shadows = can_cast_shadows && RSG::material_storage->material_casts_shadows(p_instance->material_overlay);
is_animated = is_animated || RSG::material_storage->material_is_animated(p_instance->material_overlay);
_update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, p_instance->material_overlay);
}
@@ -3888,7 +3899,22 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_uniforms) {
if (E.value.value.get_type() != Variant::NIL) {
- RSG::material_storage->global_shader_parameters_instance_update(p_instance->self, E.value.index, E.value.value);
+ int flags_count = 0;
+ if (E.value.info.hint == PROPERTY_HINT_FLAGS) {
+ // A small hack to detect boolean flags count and prevent overhead.
+ switch (E.value.info.hint_string.length()) {
+ case 3: // "x,y"
+ flags_count = 1;
+ break;
+ case 5: // "x,y,z"
+ flags_count = 2;
+ break;
+ case 7: // "x,y,z,w"
+ flags_count = 3;
+ break;
+ }
+ }
+ RSG::material_storage->global_shader_parameters_instance_update(p_instance->self, E.value.index, E.value.value, flags_count);
}
}
} else {
@@ -3967,8 +3993,8 @@ bool RendererSceneCull::free(RID p_rid) {
scenario->instance_data.reset();
scenario->instance_visibility.reset();
- scene_render->free(scenario->reflection_probe_shadow_atlas);
- scene_render->free(scenario->reflection_atlas);
+ RSG::light_storage->shadow_atlas_free(scenario->reflection_probe_shadow_atlas);
+ RSG::light_storage->reflection_atlas_free(scenario->reflection_atlas);
scenario_owner.free(p_rid);
RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index fedaac99b1..d085b84a8c 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -1076,7 +1076,6 @@ public:
#define PASSBASE scene_render
- PASS2(directional_shadow_atlas_set_size, int, bool)
PASS1(voxel_gi_set_quality, RS::VoxelGIQuality)
/* SKY API */
@@ -1258,11 +1257,7 @@ public:
PASS0R(Ref<RenderSceneBuffers>, render_buffers_create)
PASS1(gi_set_use_half_resolution, bool)
- /* Shadow Atlas */
- PASS0R(RID, shadow_atlas_create)
- PASS3(shadow_atlas_set_size, RID, int, bool)
- PASS3(shadow_atlas_set_quadrant_subdivision, RID, int, int)
-
+ /* Misc */
PASS1(set_debug_draw_mode, RS::ViewportDebugDraw)
PASS1(decals_set_filter, RS::DecalFilter)
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
index bda0950097..e1ca5a7103 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.cpp
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -180,7 +180,7 @@ RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() {
ptrw[i] = MIN(mips[0][i] / debug_tex_range, 1.0) * 255;
}
- debug_image->create(sizes[0].x, sizes[0].y, false, Image::FORMAT_L8, debug_data);
+ debug_image->set_data(sizes[0].x, sizes[0].y, false, Image::FORMAT_L8, debug_data);
if (debug_texture.is_null()) {
debug_texture = RS::get_singleton()->texture_2d_create(debug_image);
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 34f4980f05..a8df897077 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -56,17 +56,6 @@ public:
virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) = 0;
virtual uint32_t geometry_instance_get_pair_mask() = 0;
- /* SHADOW ATLAS API */
-
- virtual RID shadow_atlas_create() = 0;
- virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) = 0;
- virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
- virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0;
-
- virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
- virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
- virtual void set_directional_shadow_count(int p_count) = 0;
-
/* SDFGI UPDATE */
virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0;
@@ -240,39 +229,12 @@ public:
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
- virtual RID light_instance_create(RID p_light) = 0;
- virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
- virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0;
- virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
- virtual void light_instance_mark_visible(RID p_light_instance) = 0;
- virtual bool light_instances_can_render_shadow_cube() const {
- return true;
- }
-
virtual RID fog_volume_instance_create(RID p_fog_volume) = 0;
virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0;
virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) = 0;
virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const = 0;
virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const = 0;
- virtual RID reflection_atlas_create() = 0;
- virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
- virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
-
- virtual RID reflection_probe_instance_create(RID p_probe) = 0;
- virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
- virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
- virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
- virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
- virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
- virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
-
- virtual RID decal_instance_create(RID p_decal) = 0;
- virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) = 0;
-
- virtual RID lightmap_instance_create(RID p_lightmap) = 0;
- virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0;
-
virtual RID voxel_gi_instance_create(RID p_voxel_gi) = 0;
virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) = 0;
virtual bool voxel_gi_needs_update(RID p_probe) const = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 2b05e23a96..f887264696 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -530,7 +530,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
ptr = ptr->filter_next_ptr;
}
- RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel);
+ RSG::canvas->render_canvas(p_viewport->render_target, canvas, xform, canvas_lights, canvas_directional_lights, clip_rect, p_viewport->texture_filter, p_viewport->texture_repeat, p_viewport->snap_2d_transforms_to_pixel, p_viewport->snap_2d_vertices_to_pixel, p_viewport->canvas_cull_mask);
if (RSG::canvas->was_sdf_used()) {
p_viewport->sdf_active = true;
}
@@ -614,32 +614,32 @@ void RendererViewport::draw_viewports() {
if (vp->use_xr) {
if (xr_interface.is_valid()) {
+ // Ignore update mode we have to commit frames to our XR interface
+ visible = true;
+
// 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();
_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);
} else {
// don't render anything
visible = false;
vp->size = Size2();
}
- }
-
- if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
- visible = true;
- }
-
- if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::texture_storage->render_target_was_used(vp->render_target)) {
- visible = true;
- }
+ } else {
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) {
+ visible = true;
+ }
- if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
- Viewport *parent = viewport_owner.get_or_null(vp->parent);
- if (parent && parent->last_pass == draw_viewports_pass) {
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_VISIBLE && RSG::texture_storage->render_target_was_used(vp->render_target)) {
visible = true;
}
+
+ if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) {
+ Viewport *parent = viewport_owner.get_or_null(vp->parent);
+ if (parent && parent->last_pass == draw_viewports_pass) {
+ visible = true;
+ }
+ }
}
visible = visible && vp->size.x > 1 && vp->size.y > 1;
@@ -664,36 +664,44 @@ void RendererViewport::draw_viewports() {
RSG::texture_storage->render_target_set_as_unused(vp->render_target);
if (vp->use_xr && xr_interface.is_valid()) {
- // check for an external texture destination (disabled for now, not yet supported)
- // RSG::texture_storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
- RSG::texture_storage->render_target_set_external_texture(vp->render_target, 0);
-
- // render...
- RSG::scene->set_debug_draw_mode(vp->debug_draw);
-
- // and draw viewport
- _draw_viewport(vp);
-
- // measure
-
- // 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 (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>();
- }
+ // Inform XR interface we're about to render its viewport,
+ // if this returns false we don't render.
+ // This usually is a result of the player taking off their headset and OpenXR telling us to skip
+ // rendering frames.
+ if (xr_interface->pre_draw_viewport(vp->render_target)) {
+ RSG::texture_storage->render_target_set_override_color(vp->render_target, xr_interface->get_color_texture());
+ RSG::texture_storage->render_target_set_override_depth(vp->render_target, xr_interface->get_depth_texture());
+ RSG::texture_storage->render_target_set_override_velocity(vp->render_target, xr_interface->get_velocity_texture());
+
+ // render...
+ RSG::scene->set_debug_draw_mode(vp->debug_draw);
+
+ // and draw viewport
+ _draw_viewport(vp);
+
+ // 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) {
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (blits.size() > 0) {
+ RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
+ }
+ RSG::rasterizer->end_frame(true);
+ } else if (blits.size() > 0) {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- 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 {
- RSG::texture_storage->render_target_set_external_texture(vp->render_target, 0);
+ RSG::texture_storage->render_target_set_override_color(vp->render_target, RID()); // TODO if fullscreen output, we can set this to our texture chain
+ RSG::texture_storage->render_target_set_override_depth(vp->render_target, RID());
+ RSG::texture_storage->render_target_set_override_velocity(vp->render_target, RID());
RSG::scene->set_debug_draw_mode(vp->debug_draw);
@@ -760,7 +768,7 @@ void RendererViewport::viewport_initialize(RID p_rid) {
Viewport *viewport = viewport_owner.get_or_null(p_rid);
viewport->self = p_rid;
viewport->render_target = RSG::texture_storage->render_target_create();
- viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
+ viewport->shadow_atlas = RSG::light_storage->shadow_atlas_create();
viewport->viewport_render_direct_to_screen = false;
viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
@@ -1076,14 +1084,14 @@ void RendererViewport::viewport_set_positional_shadow_atlas_size(RID p_viewport,
viewport->shadow_atlas_size = p_size;
viewport->shadow_atlas_16_bits = p_16_bits;
- RSG::scene->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
+ RSG::light_storage->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
}
void RendererViewport::viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
- RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
+ RSG::light_storage->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
}
void RendererViewport::viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa) {
@@ -1294,7 +1302,7 @@ bool RendererViewport::free(RID p_rid) {
Viewport *viewport = viewport_owner.get_or_null(p_rid);
RSG::texture_storage->render_target_free(viewport->render_target);
- RSG::scene->free(viewport->shadow_atlas);
+ RSG::light_storage->shadow_atlas_free(viewport->shadow_atlas);
if (viewport->render_buffers.is_valid()) {
viewport->render_buffers.unref();
}
@@ -1345,6 +1353,12 @@ void RendererViewport::set_default_clear_color(const Color &p_color) {
RSG::texture_storage->set_default_clear_color(p_color);
}
+void RendererViewport::viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+ viewport->canvas_cull_mask = p_canvas_cull_mask;
+}
+
// Workaround for setting this on thread.
void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) {
DisplayServer::get_singleton()->window_set_vsync_mode(p_mode, p_window);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 55058a30b8..5e0c090ec0 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -117,6 +117,8 @@ public:
bool transparent_bg = false;
+ uint32_t canvas_cull_mask = 0xffffffff;
+
struct CanvasKey {
int64_t stacking;
RID canvas;
@@ -249,6 +251,8 @@ public:
void viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform);
void viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer);
+ void viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask);
+
void viewport_set_positional_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits = true);
void viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index dd190437a3..93118f39e7 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -974,6 +974,8 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X);
BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y);
BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z);
+ BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_X);
+ BIND_ENUM_CONSTANT(LIMIT_MAX_VIEWPORT_DIMENSIONS_Y);
BIND_ENUM_CONSTANT(MEMORY_TEXTURES);
BIND_ENUM_CONSTANT(MEMORY_BUFFERS);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 29e5c9cd77..d0b85d8220 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -958,7 +958,7 @@ public:
bool wireframe;
PolygonCullMode cull_mode;
PolygonFrontFace front_face;
- bool depth_bias_enable;
+ bool depth_bias_enabled;
float depth_bias_constant_factor;
float depth_bias_clamp;
float depth_bias_slope_factor;
@@ -970,7 +970,7 @@ public:
wireframe = false;
cull_mode = POLYGON_CULL_DISABLED;
front_face = POLYGON_FRONT_FACE_CLOCKWISE;
- depth_bias_enable = false;
+ depth_bias_enabled = false;
depth_bias_constant_factor = 0;
depth_bias_clamp = 0;
depth_bias_slope_factor = 0;
@@ -1252,6 +1252,8 @@ public:
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X,
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y,
LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z,
+ LIMIT_MAX_VIEWPORT_DIMENSIONS_X,
+ LIMIT_MAX_VIEWPORT_DIMENSIONS_Y,
LIMIT_SUBGROUP_SIZE,
LIMIT_SUBGROUP_IN_SHADERS, // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
LIMIT_SUBGROUP_OPERATIONS,
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index a56b7eb241..c710bd0a10 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -407,10 +407,10 @@ protected:
List<Variant> keys;
p_versions.get_key_list(&keys);
for (const Variant &E : keys) {
- StringName name = E;
+ StringName vname = E;
Ref<RDShaderSPIRV> bc = p_versions[E];
ERR_CONTINUE(bc.is_null());
- versions[name] = bc;
+ versions[vname] = bc;
}
emit_changed();
@@ -517,7 +517,7 @@ public:
RD_SETGET(bool, wireframe)
RD_SETGET(RD::PolygonCullMode, cull_mode)
RD_SETGET(RD::PolygonFrontFace, front_face)
- RD_SETGET(bool, depth_bias_enable)
+ RD_SETGET(bool, depth_bias_enabled)
RD_SETGET(float, depth_bias_constant_factor)
RD_SETGET(float, depth_bias_clamp)
RD_SETGET(float, depth_bias_slope_factor)
@@ -531,7 +531,7 @@ protected:
RD_BIND(Variant::BOOL, RDPipelineRasterizationState, wireframe);
RD_BIND(Variant::INT, RDPipelineRasterizationState, cull_mode);
RD_BIND(Variant::INT, RDPipelineRasterizationState, front_face);
- RD_BIND(Variant::BOOL, RDPipelineRasterizationState, depth_bias_enable);
+ RD_BIND(Variant::BOOL, RDPipelineRasterizationState, depth_bias_enabled);
RD_BIND(Variant::FLOAT, RDPipelineRasterizationState, depth_bias_constant_factor);
RD_BIND(Variant::FLOAT, RDPipelineRasterizationState, depth_bias_clamp);
RD_BIND(Variant::FLOAT, RDPipelineRasterizationState, depth_bias_slope_factor);
diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h
index a178b00424..c4d9e25ecd 100644
--- a/servers/rendering/rendering_method.h
+++ b/servers/rendering/rendering_method.h
@@ -106,8 +106,6 @@ public:
virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0;
virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0;
- virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
-
/* SKY API */
virtual RID sky_allocate() = 0;
@@ -284,10 +282,6 @@ public:
virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
- virtual RID shadow_atlas_create() = 0;
- virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
- virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
-
/* Render Buffers */
virtual Ref<RenderSceneBuffers> render_buffers_create() = 0;
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 9103b0cf56..c0cd564308 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -331,6 +331,14 @@ bool RenderingServerDefault::is_low_end() const {
return RendererCompositor::is_low_end();
}
+Size2i RenderingServerDefault::get_maximum_viewport_size() const {
+ if (RSG::utilities) {
+ return RSG::utilities->get_maximum_viewport_size();
+ } else {
+ return Size2i();
+ }
+}
+
void RenderingServerDefault::_thread_exit() {
exit.set();
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 5ee29d5e2a..6d2d0d9906 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -410,6 +410,13 @@ public:
FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
FUNC1(lightmap_set_probe_capture_update_speed, float)
+ /* Shadow Atlas */
+ FUNC0R(RID, shadow_atlas_create)
+ FUNC3(shadow_atlas_set_size, RID, int, bool)
+ FUNC3(shadow_atlas_set_quadrant_subdivision, RID, int, int)
+
+ FUNC2(directional_shadow_atlas_set_size, int, bool)
+
/* DECAL API */
#undef ServerName
@@ -603,6 +610,8 @@ public:
FUNC2(viewport_set_disable_environment, RID, bool)
FUNC2(viewport_set_disable_3d, RID, bool)
+ FUNC2(viewport_set_canvas_cull_mask, RID, uint32_t)
+
FUNC2(viewport_attach_camera, RID, RID)
FUNC2(viewport_set_scenario, RID, RID)
FUNC2(viewport_attach_canvas, RID, RID)
@@ -652,7 +661,6 @@ public:
#define ServerName RenderingMethod
#define server_name RSG::scene
- FUNC2(directional_shadow_atlas_set_size, int, bool)
FUNC1(voxel_gi_set_quality, VoxelGIQuality)
/* SKY API */
@@ -822,6 +830,8 @@ public:
FUNC2(canvas_item_set_visible, RID, bool)
FUNC2(canvas_item_set_light_mask, RID, int)
+ FUNC2(canvas_item_set_visibility_layer, RID, uint32_t)
+
FUNC2(canvas_item_set_update_when_visible, RID, bool)
FUNC2(canvas_item_set_transform, RID, const Transform2D &)
@@ -988,6 +998,8 @@ public:
virtual void set_print_gpu_profile(bool p_enable) override;
+ virtual Size2i get_maximum_viewport_size() const override;
+
RenderingServerDefault(bool p_create_thread = false);
~RenderingServerDefault();
};
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 1d83cc9de7..fc644fcae6 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -373,16 +373,16 @@ void ShaderCompiler::_dump_function_deps(const SL::ShaderNode *p_node, const Str
static String _get_global_shader_uniform_from_type_and_index(const String &p_buffer, const String &p_index, ShaderLanguage::DataType p_type) {
switch (p_type) {
case ShaderLanguage::TYPE_BOOL: {
- return "(" + p_buffer + "[" + p_index + "].x != 0.0)";
+ return "bool(floatBitsToUint(" + p_buffer + "[" + p_index + "].x))";
}
case ShaderLanguage::TYPE_BVEC2: {
- return "(notEqual(" + p_buffer + "[" + p_index + "].xy, vec2(0.0)))";
+ return "bvec2(floatBitsToUint(" + p_buffer + "[" + p_index + "].xy))";
}
case ShaderLanguage::TYPE_BVEC3: {
- return "(notEqual(" + p_buffer + "[" + p_index + "].xyz, vec3(0.0)))";
+ return "bvec3(floatBitsToUint(" + p_buffer + "[" + p_index + "].xyz))";
}
case ShaderLanguage::TYPE_BVEC4: {
- return "(notEqual(" + p_buffer + "[" + p_index + "].xyzw, vec4(0.0)))";
+ return "bvec4(floatBitsToUint(" + p_buffer + "[" + p_index + "].xyzw))";
}
case ShaderLanguage::TYPE_INT: {
return "floatBitsToInt(" + p_buffer + "[" + p_index + "].x)";
@@ -1369,11 +1369,11 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
HashMap<String, Vector<String>> includes;
includes[""] = Vector<String>();
Vector<String> include_stack;
- Vector<String> shader = p_code.split("\n");
+ Vector<String> shader_lines = p_code.split("\n");
// Reconstruct the files.
- for (int i = 0; i < shader.size(); i++) {
- String l = shader[i];
+ for (int i = 0; i < shader_lines.size(); i++) {
+ String l = shader_lines[i];
if (l.begins_with("@@>")) {
String inc_path = l.replace_first("@@>", "");
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index a92292209f..2f5846f520 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -1251,7 +1251,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (is_shader_inc) {
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
for (const KeyValue<StringName, FunctionInfo> &E : ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(i))) {
- if ((current_function == E.key || E.key == "global") && E.value.built_ins.has(p_identifier)) {
+ if ((current_function == E.key || E.key == "global" || E.key == "constants") && E.value.built_ins.has(p_identifier)) {
if (r_data_type) {
*r_data_type = E.value.built_ins[p_identifier].type;
}
@@ -8635,12 +8635,15 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
} break;
case TK_HINT_SCREEN_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_SCREEN_TEXTURE;
+ --texture_uniforms;
} break;
case TK_HINT_NORMAL_ROUGHNESS_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE;
+ --texture_uniforms;
} break;
case TK_HINT_DEPTH_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE;
+ --texture_uniforms;
} break;
case TK_FILTER_NEAREST: {
new_filter = FILTER_NEAREST;
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index b04bc671ee..df5b893cd5 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -84,6 +84,18 @@ public:
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0;
virtual uint64_t light_get_version(RID p_light) const = 0;
+ /* LIGHT INSTANCE API */
+
+ virtual RID light_instance_create(RID p_light) = 0;
+ virtual void light_instance_free(RID p_light_instance) = 0;
+ virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
+ virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0;
+ virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
+ virtual void light_instance_mark_visible(RID p_light_instance) = 0;
+ virtual bool light_instances_can_render_shadow_cube() const {
+ return true;
+ }
+
/* PROBE API */
virtual RID reflection_probe_allocate() = 0;
@@ -114,6 +126,24 @@ public:
virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const = 0;
+ /* REFLECTION ATLAS */
+
+ virtual RID reflection_atlas_create() = 0;
+ virtual void reflection_atlas_free(RID p_ref_atlas) = 0;
+ virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
+ virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
+
+ /* REFLECTION PROBE INSTANCE */
+
+ virtual RID reflection_probe_instance_create(RID p_probe) = 0;
+ virtual void reflection_probe_instance_free(RID p_instance) = 0;
+ virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
+ virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
+ virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
+ virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
+
/* LIGHTMAP */
virtual RID lightmap_allocate() = 0;
@@ -134,6 +164,27 @@ public:
virtual bool lightmap_is_interior(RID p_lightmap) const = 0;
virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
virtual float lightmap_get_probe_capture_update_speed() const = 0;
+
+ /* LIGHTMAP INSTANCE */
+
+ virtual RID lightmap_instance_create(RID p_lightmap) = 0;
+ virtual void lightmap_instance_free(RID p_lightmap) = 0;
+ virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0;
+
+ /* SHADOW ATLAS */
+
+ virtual RID shadow_atlas_create() = 0;
+ virtual void shadow_atlas_free(RID p_atlas) = 0;
+
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
+ virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0;
+
+ virtual void shadow_atlas_update(RID p_atlas) = 0;
+
+ virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
+ virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
+ virtual void set_directional_shadow_count(int p_count) = 0;
};
#endif // LIGHT_STORAGE_H
diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h
index 396668c9ed..a3de6343e5 100644
--- a/servers/rendering/storage/material_storage.h
+++ b/servers/rendering/storage/material_storage.h
@@ -53,7 +53,7 @@ public:
virtual int32_t global_shader_parameters_instance_allocate(RID p_instance) = 0;
virtual void global_shader_parameters_instance_free(RID p_instance) = 0;
- virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value) = 0;
+ virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) = 0;
/* SHADER API */
virtual RID shader_allocate() = 0;
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 08ff88d4a5..635f44786c 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -120,20 +120,29 @@ public:
virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
+ /* DECAL INSTANCE */
+
+ virtual RID decal_instance_create(RID p_decal) = 0;
+ virtual void decal_instance_free(RID p_decal_instance) = 0;
+ virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) = 0;
+
/* RENDER TARGET */
virtual RID render_target_create() = 0;
virtual void render_target_free(RID p_rid) = 0;
- virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0;
- virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0;
- virtual RID render_target_get_texture(RID p_render_target) = 0;
- virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
+ virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; // Q change input to const Point2i &p_position ?
+ virtual Point2i render_target_get_position(RID p_render_target) const = 0;
+ virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0; // Q change input to const Size2i &p_size ?
+ virtual Size2i render_target_get_size(RID p_render_target) const = 0;
virtual void render_target_set_transparent(RID p_render_target, bool p_is_transparent) = 0;
+ virtual bool render_target_get_transparent(RID p_render_target) const = 0;
virtual void render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) = 0;
- virtual bool render_target_was_used(RID p_render_target) = 0;
+ virtual bool render_target_get_direct_to_screen(RID p_render_target) const = 0;
+ virtual bool render_target_was_used(RID p_render_target) const = 0;
virtual void render_target_set_as_unused(RID p_render_target) = 0;
virtual void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) = 0;
+ virtual RS::ViewportMSAA render_target_get_msaa(RID p_render_target) const = 0;
virtual void render_target_request_clear(RID p_render_target, const Color &p_clear_color) = 0;
virtual bool render_target_is_clear_requested(RID p_render_target) = 0;
@@ -146,7 +155,20 @@ public:
virtual void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) = 0;
virtual void render_target_set_vrs_mode(RID p_render_target, RS::ViewportVRSMode p_mode) = 0;
+ virtual RS::ViewportVRSMode render_target_get_vrs_mode(RID p_render_target) const = 0;
virtual void render_target_set_vrs_texture(RID p_render_target, RID p_texture) = 0;
+ virtual RID render_target_get_vrs_texture(RID p_render_target) const = 0;
+
+ // override color, depth and velocity buffers (depth and velocity only for 3D)
+ virtual void render_target_set_override_color(RID p_render_target, RID p_texture) = 0;
+ virtual RID render_target_get_override_color(RID p_render_target) const = 0;
+ virtual void render_target_set_override_depth(RID p_render_target, RID p_texture) = 0;
+ virtual RID render_target_get_override_depth(RID p_render_target) const = 0;
+ virtual void render_target_set_override_velocity(RID p_render_target, RID p_texture) = 0;
+ virtual RID render_target_get_override_velocity(RID p_render_target) const = 0;
+
+ // get textures
+ virtual RID render_target_get_texture(RID p_render_target) = 0;
};
#endif // TEXTURE_STORAGE_H
diff --git a/servers/rendering/storage/utilities.h b/servers/rendering/storage/utilities.h
index d240d58917..23a782c14a 100644
--- a/servers/rendering/storage/utilities.h
+++ b/servers/rendering/storage/utilities.h
@@ -181,6 +181,8 @@ public:
virtual String get_video_adapter_vendor() const = 0;
virtual RenderingDevice::DeviceType get_video_adapter_type() const = 0;
virtual String get_video_adapter_api_version() const = 0;
+
+ virtual Size2i get_maximum_viewport_size() const = 0;
};
#endif // RENDERER_UTILITIES_H
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 57378708ba..cf30d377b7 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -701,6 +701,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
}
uint32_t RenderingServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_array_index) const {
+ ERR_FAIL_INDEX_V(p_array_index, ARRAY_MAX, 0);
p_format &= ~ARRAY_FORMAT_INDEX;
uint32_t offsets[ARRAY_MAX];
uint32_t vstr;
@@ -2181,6 +2182,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport);
ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &RenderingServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(DisplayServer::MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &RenderingServer::viewport_set_render_direct_to_screen);
+ ClassDB::bind_method(D_METHOD("viewport_set_canvas_cull_mask", "viewport", "canvas_cull_mask"), &RenderingServer::viewport_set_canvas_cull_mask);
ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_mode", "viewport", "scaling_3d_mode"), &RenderingServer::viewport_set_scaling_3d_mode);
ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_scale", "viewport", "scale"), &RenderingServer::viewport_set_scaling_3d_scale);
@@ -2574,6 +2576,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_set_default_texture_repeat", "item", "repeat"), &RenderingServer::canvas_item_set_default_texture_repeat);
ClassDB::bind_method(D_METHOD("canvas_item_set_visible", "item", "visible"), &RenderingServer::canvas_item_set_visible);
ClassDB::bind_method(D_METHOD("canvas_item_set_light_mask", "item", "mask"), &RenderingServer::canvas_item_set_light_mask);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_visibility_layer", "item", "visibility_layer"), &RenderingServer::canvas_item_set_visibility_layer);
ClassDB::bind_method(D_METHOD("canvas_item_set_transform", "item", "transform"), &RenderingServer::canvas_item_set_transform);
ClassDB::bind_method(D_METHOD("canvas_item_set_clip", "item", "clip"), &RenderingServer::canvas_item_set_clip);
ClassDB::bind_method(D_METHOD("canvas_item_set_distance_field_mode", "item", "enabled"), &RenderingServer::canvas_item_set_distance_field_mode);
@@ -2635,7 +2638,8 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(CANVAS_ITEM_TEXTURE_REPEAT_MAX);
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_DISABLED);
- BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_OPAQUE);
+ BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_CLIP_ONLY);
+ BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_CLIP_AND_DRAW);
BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_TRANSPARENT);
/* CANVAS LIGHT */
@@ -2790,10 +2794,10 @@ void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry
Vector<Vector3> vertices;
Vector<Vector3> normals;
- for (int i = 0; i < p_mesh_data.faces.size(); i++) {
+ for (uint32_t i = 0; i < p_mesh_data.faces.size(); i++) {
const Geometry3D::MeshData::Face &f = p_mesh_data.faces[i];
- for (int j = 2; j < f.indices.size(); j++) {
+ for (uint32_t j = 2; j < f.indices.size(); j++) {
vertices.push_back(p_mesh_data.vertices[f.indices[0]]);
normals.push_back(f.plane.normal);
@@ -2867,12 +2871,17 @@ void RenderingServer::init() {
GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048);
- // Already defined in RenderingDeviceVulkan::initialize which runs before this code.
+ // Already defined in some RenderingDevice*::initialize, which run before this code.
// We re-define them here just for doctool's sake. Make sure to keep default values in sync.
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);
+ // Vulkan-specific.
+ GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+
+ // Number of commands that can be drawn per frame.
+ GLOBAL_DEF_RST("rendering/gl_compatibility/item_buffer_size", 16384);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/gl_compatibility/item_buffer_size", PropertyInfo(Variant::INT, "rendering/gl_compatibility/item_buffer_size", PROPERTY_HINT_RANGE, "1024,1048576,1"));
GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 67ba407775..97fafd1b14 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -485,6 +485,12 @@ public:
virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
virtual void light_directional_set_sky_mode(RID p_light, LightDirectionalSkyMode p_mode) = 0;
+ // Shadow atlas
+
+ virtual RID shadow_atlas_create() = 0;
+ virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
+ virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
+
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
enum ShadowQuality {
@@ -801,6 +807,7 @@ public:
virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0;
virtual void viewport_set_active(RID p_viewport, bool p_active) = 0;
virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0;
+ virtual void viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask) = 0;
virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) = 0;
virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0;
@@ -1314,6 +1321,7 @@ public:
virtual void canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect = Rect2()) = 0;
virtual void canvas_item_set_modulate(RID p_item, const Color &p_color) = 0;
virtual void canvas_item_set_self_modulate(RID p_item, const Color &p_color) = 0;
+ virtual void canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) = 0;
virtual void canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) = 0;
@@ -1361,7 +1369,8 @@ public:
enum CanvasGroupMode {
CANVAS_GROUP_MODE_DISABLED,
- CANVAS_GROUP_MODE_OPAQUE,
+ CANVAS_GROUP_MODE_CLIP_ONLY,
+ CANVAS_GROUP_MODE_CLIP_AND_DRAW,
CANVAS_GROUP_MODE_TRANSPARENT,
};
@@ -1568,6 +1577,8 @@ public:
virtual void set_print_gpu_profile(bool p_enable) = 0;
+ virtual Size2i get_maximum_viewport_size() const = 0;
+
RenderingDevice *get_rendering_device() const;
RenderingDevice *create_local_rendering_device() const;
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 0e1069dcf4..dd4cb5accb 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -311,27 +311,21 @@ void TextServerExtension::_bind_methods() {
}
bool TextServerExtension::has_feature(Feature p_feature) const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_feature, p_feature, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_has_feature, p_feature, ret);
+ return ret;
}
String TextServerExtension::get_name() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_name, ret)) {
- return ret;
- }
- return "Unknown";
+ String ret = "Unknown";
+ GDVIRTUAL_CALL(_get_name, ret);
+ return ret;
}
int64_t TextServerExtension::get_features() const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_get_features, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_get_features, ret);
+ return ret;
}
void TextServerExtension::free_rid(const RID &p_rid) {
@@ -339,67 +333,51 @@ void TextServerExtension::free_rid(const RID &p_rid) {
}
bool TextServerExtension::has(const RID &p_rid) {
- bool ret;
- if (GDVIRTUAL_CALL(_has, p_rid, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_has, p_rid, ret);
+ return ret;
}
bool TextServerExtension::load_support_data(const String &p_filename) {
- bool ret;
- if (GDVIRTUAL_CALL(_load_support_data, p_filename, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_load_support_data, p_filename, ret);
+ return ret;
}
String TextServerExtension::get_support_data_filename() const {
String ret;
- if (GDVIRTUAL_CALL(_get_support_data_filename, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_get_support_data_filename, ret);
+ return ret;
}
String TextServerExtension::get_support_data_info() const {
String ret;
- if (GDVIRTUAL_CALL(_get_support_data_info, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_get_support_data_info, ret);
+ return ret;
}
bool TextServerExtension::save_support_data(const String &p_filename) const {
- bool ret;
- if (GDVIRTUAL_CALL(_save_support_data, p_filename, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_save_support_data, p_filename, ret);
+ return ret;
}
bool TextServerExtension::is_locale_right_to_left(const String &p_locale) const {
- bool ret;
- if (GDVIRTUAL_CALL(_is_locale_right_to_left, p_locale, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_is_locale_right_to_left, p_locale, ret);
+ return ret;
}
int64_t TextServerExtension::name_to_tag(const String &p_name) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_name_to_tag, p_name, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_name_to_tag, p_name, ret);
+ return ret;
}
String TextServerExtension::tag_to_name(int64_t p_tag) const {
String ret;
- if (GDVIRTUAL_CALL(_tag_to_name, p_tag, ret)) {
- return ret;
- }
- return "";
+ GDVIRTUAL_CALL(_tag_to_name, p_tag, ret);
+ return ret;
}
/*************************************************************************/
@@ -408,10 +386,8 @@ String TextServerExtension::tag_to_name(int64_t p_tag) const {
RID TextServerExtension::create_font() {
RID ret;
- if (GDVIRTUAL_CALL(_create_font, ret)) {
- return ret;
- }
- return RID();
+ GDVIRTUAL_CALL(_create_font, ret);
+ return ret;
}
void TextServerExtension::font_set_data(const RID &p_font_rid, const PackedByteArray &p_data) {
@@ -427,19 +403,15 @@ void TextServerExtension::font_set_face_index(const RID &p_font_rid, int64_t p_i
}
int64_t TextServerExtension::font_get_face_index(const RID &p_font_rid) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_face_index, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_face_index, p_font_rid, ret);
+ return ret;
}
int64_t TextServerExtension::font_get_face_count(const RID &p_font_rid) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_face_count, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_face_count, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_style(const RID &p_font_rid, BitField<TextServer::FontStyle> p_style) {
@@ -448,10 +420,8 @@ void TextServerExtension::font_set_style(const RID &p_font_rid, BitField<TextSer
BitField<TextServer::FontStyle> TextServerExtension::font_get_style(const RID &p_font_rid) const {
BitField<TextServer::FontStyle> ret = 0;
- if (GDVIRTUAL_CALL(_font_get_style, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ GDVIRTUAL_CALL(_font_get_style, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_style_name(const RID &p_font_rid, const String &p_name) {
@@ -460,10 +430,8 @@ void TextServerExtension::font_set_style_name(const RID &p_font_rid, const Strin
String TextServerExtension::font_get_style_name(const RID &p_font_rid) const {
String ret;
- if (GDVIRTUAL_CALL(_font_get_style_name, p_font_rid, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_font_get_style_name, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_name(const RID &p_font_rid, const String &p_name) {
@@ -472,10 +440,8 @@ void TextServerExtension::font_set_name(const RID &p_font_rid, const String &p_n
String TextServerExtension::font_get_name(const RID &p_font_rid) const {
String ret;
- if (GDVIRTUAL_CALL(_font_get_name, p_font_rid, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_font_get_name, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_antialiasing(const RID &p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
@@ -483,11 +449,9 @@ void TextServerExtension::font_set_antialiasing(const RID &p_font_rid, TextServe
}
TextServer::FontAntialiasing TextServerExtension::font_get_antialiasing(const RID &p_font_rid) const {
- TextServer::FontAntialiasing ret;
- if (GDVIRTUAL_CALL(_font_get_antialiasing, p_font_rid, ret)) {
- return ret;
- }
- return TextServer::FONT_ANTIALIASING_NONE;
+ TextServer::FontAntialiasing ret = TextServer::FONT_ANTIALIASING_NONE;
+ GDVIRTUAL_CALL(_font_get_antialiasing, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
@@ -495,11 +459,9 @@ void TextServerExtension::font_set_generate_mipmaps(const RID &p_font_rid, bool
}
bool TextServerExtension::font_get_generate_mipmaps(const RID &p_font_rid) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_get_generate_mipmaps, p_font_rid, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_get_generate_mipmaps, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
@@ -507,11 +469,9 @@ void TextServerExtension::font_set_multichannel_signed_distance_field(const RID
}
bool TextServerExtension::font_is_multichannel_signed_distance_field(const RID &p_font_rid) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_is_multichannel_signed_distance_field, p_font_rid, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_is_multichannel_signed_distance_field, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_msdf_pixel_range(const RID &p_font_rid, int64_t p_msdf_pixel_range) {
@@ -519,11 +479,9 @@ void TextServerExtension::font_set_msdf_pixel_range(const RID &p_font_rid, int64
}
int64_t TextServerExtension::font_get_msdf_pixel_range(const RID &p_font_rid) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_msdf_pixel_range, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_msdf_pixel_range, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_msdf_size(const RID &p_font_rid, int64_t p_msdf_size) {
@@ -531,11 +489,9 @@ void TextServerExtension::font_set_msdf_size(const RID &p_font_rid, int64_t p_ms
}
int64_t TextServerExtension::font_get_msdf_size(const RID &p_font_rid) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_msdf_size, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_msdf_size, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) {
@@ -543,11 +499,9 @@ void TextServerExtension::font_set_fixed_size(const RID &p_font_rid, int64_t p_f
}
int64_t TextServerExtension::font_get_fixed_size(const RID &p_font_rid) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_force_autohinter(const RID &p_font_rid, bool p_force_autohinter) {
@@ -555,11 +509,9 @@ void TextServerExtension::font_set_force_autohinter(const RID &p_font_rid, bool
}
bool TextServerExtension::font_is_force_autohinter(const RID &p_font_rid) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_is_force_autohinter, p_font_rid, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_is_force_autohinter, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_hinting(const RID &p_font_rid, TextServer::Hinting p_hinting) {
@@ -567,11 +519,9 @@ void TextServerExtension::font_set_hinting(const RID &p_font_rid, TextServer::Hi
}
TextServer::Hinting TextServerExtension::font_get_hinting(const RID &p_font_rid) const {
- TextServer::Hinting ret;
- if (GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret)) {
- return (TextServer::Hinting)ret;
- }
- return TextServer::Hinting::HINTING_NONE;
+ TextServer::Hinting ret = TextServer::HINTING_NONE;
+ GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_subpixel_positioning(const RID &p_font_rid, TextServer::SubpixelPositioning p_subpixel) {
@@ -579,11 +529,9 @@ void TextServerExtension::font_set_subpixel_positioning(const RID &p_font_rid, T
}
TextServer::SubpixelPositioning TextServerExtension::font_get_subpixel_positioning(const RID &p_font_rid) const {
- TextServer::SubpixelPositioning ret;
- if (GDVIRTUAL_CALL(_font_get_subpixel_positioning, p_font_rid, ret)) {
- return (TextServer::SubpixelPositioning)ret;
- }
- return TextServer::SubpixelPositioning::SUBPIXEL_POSITIONING_DISABLED;
+ TextServer::SubpixelPositioning ret = TextServer::SUBPIXEL_POSITIONING_DISABLED;
+ GDVIRTUAL_CALL(_font_get_subpixel_positioning, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_embolden(const RID &p_font_rid, double p_strength) {
@@ -591,11 +539,9 @@ void TextServerExtension::font_set_embolden(const RID &p_font_rid, double p_stre
}
double TextServerExtension::font_get_embolden(const RID &p_font_rid) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_embolden, p_font_rid, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_embolden, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_transform(const RID &p_font_rid, const Transform2D &p_transform) {
@@ -604,10 +550,8 @@ void TextServerExtension::font_set_transform(const RID &p_font_rid, const Transf
Transform2D TextServerExtension::font_get_transform(const RID &p_font_rid) const {
Transform2D ret;
- if (GDVIRTUAL_CALL(_font_get_transform, p_font_rid, ret)) {
- return ret;
- }
- return Transform2D();
+ GDVIRTUAL_CALL(_font_get_transform, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_variation_coordinates(const RID &p_font_rid, const Dictionary &p_variation_coordinates) {
@@ -616,10 +560,8 @@ void TextServerExtension::font_set_variation_coordinates(const RID &p_font_rid,
Dictionary TextServerExtension::font_get_variation_coordinates(const RID &p_font_rid) const {
Dictionary ret;
- if (GDVIRTUAL_CALL(_font_get_variation_coordinates, p_font_rid, ret)) {
- return ret;
- }
- return Dictionary();
+ GDVIRTUAL_CALL(_font_get_variation_coordinates, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_oversampling(const RID &p_font_rid, double p_oversampling) {
@@ -627,19 +569,15 @@ void TextServerExtension::font_set_oversampling(const RID &p_font_rid, double p_
}
double TextServerExtension::font_get_oversampling(const RID &p_font_rid) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_oversampling, p_font_rid, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_oversampling, p_font_rid, ret);
+ return ret;
}
TypedArray<Vector2i> TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const {
TypedArray<Vector2i> ret;
- if (GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret)) {
- return ret;
- }
- return TypedArray<Vector2i>();
+ GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_clear_size_cache(const RID &p_font_rid) {
@@ -655,11 +593,9 @@ void TextServerExtension::font_set_ascent(const RID &p_font_rid, int64_t p_size,
}
double TextServerExtension::font_get_ascent(const RID &p_font_rid, int64_t p_size) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) {
@@ -667,11 +603,9 @@ void TextServerExtension::font_set_descent(const RID &p_font_rid, int64_t p_size
}
double TextServerExtension::font_get_descent(const RID &p_font_rid, int64_t p_size) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) {
@@ -679,11 +613,9 @@ void TextServerExtension::font_set_underline_position(const RID &p_font_rid, int
}
double TextServerExtension::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) {
@@ -691,11 +623,9 @@ void TextServerExtension::font_set_underline_thickness(const RID &p_font_rid, in
}
double TextServerExtension::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) {
@@ -703,19 +633,15 @@ void TextServerExtension::font_set_scale(const RID &p_font_rid, int64_t p_size,
}
double TextServerExtension::font_get_scale(const RID &p_font_rid, int64_t p_size) const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret);
+ return ret;
}
int64_t TextServerExtension::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) {
@@ -732,10 +658,8 @@ void TextServerExtension::font_set_texture_image(const RID &p_font_rid, const Ve
Ref<Image> TextServerExtension::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
Ref<Image> ret;
- if (GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret)) {
- return ret;
- }
- return Ref<Image>();
+ GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret);
+ return ret;
}
void TextServerExtension::font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) {
@@ -744,18 +668,14 @@ void TextServerExtension::font_set_texture_offsets(const RID &p_font_rid, const
PackedInt32Array TextServerExtension::font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
PackedInt32Array ret;
- if (GDVIRTUAL_CALL(_font_get_texture_offsets, p_font_rid, p_size, p_texture_index, ret)) {
- return ret;
- }
- return PackedInt32Array();
+ GDVIRTUAL_CALL(_font_get_texture_offsets, p_font_rid, p_size, p_texture_index, ret);
+ return ret;
}
PackedInt32Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
PackedInt32Array ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret)) {
- return ret;
- }
- return PackedInt32Array();
+ GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
@@ -768,10 +688,8 @@ void TextServerExtension::font_remove_glyph(const RID &p_font_rid, const Vector2
Vector2 TextServerExtension::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const {
Vector2 ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
void TextServerExtension::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) {
@@ -780,10 +698,8 @@ void TextServerExtension::font_set_glyph_advance(const RID &p_font_rid, int64_t
Vector2 TextServerExtension::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Vector2 ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
void TextServerExtension::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) {
@@ -792,10 +708,8 @@ void TextServerExtension::font_set_glyph_offset(const RID &p_font_rid, const Vec
Vector2 TextServerExtension::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Vector2 ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
void TextServerExtension::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) {
@@ -804,10 +718,8 @@ void TextServerExtension::font_set_glyph_size(const RID &p_font_rid, const Vecto
Rect2 TextServerExtension::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Rect2 ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return Rect2();
+ GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
void TextServerExtension::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) {
@@ -815,11 +727,9 @@ void TextServerExtension::font_set_glyph_uv_rect(const RID &p_font_rid, const Ve
}
int64_t TextServerExtension::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
void TextServerExtension::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) {
@@ -828,34 +738,26 @@ void TextServerExtension::font_set_glyph_texture_idx(const RID &p_font_rid, cons
RID TextServerExtension::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
RID ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return RID();
+ GDVIRTUAL_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
Size2 TextServerExtension::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
Size2 ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret)) {
- return ret;
- }
- return Size2();
+ GDVIRTUAL_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret);
+ return ret;
}
Dictionary TextServerExtension::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
Dictionary ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_contours, p_font_rid, p_size, p_index, ret)) {
- return ret;
- }
- return Dictionary();
+ GDVIRTUAL_CALL(_font_get_glyph_contours, p_font_rid, p_size, p_index, ret);
+ return ret;
}
TypedArray<Vector2i> TextServerExtension::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
TypedArray<Vector2i> ret;
- if (GDVIRTUAL_CALL(_font_get_kerning_list, p_font_rid, p_size, ret)) {
- return ret;
- }
- return TypedArray<Vector2i>();
+ GDVIRTUAL_CALL(_font_get_kerning_list, p_font_rid, p_size, ret);
+ return ret;
}
void TextServerExtension::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
@@ -872,34 +774,26 @@ void TextServerExtension::font_set_kerning(const RID &p_font_rid, int64_t p_size
Vector2 TextServerExtension::font_get_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) const {
Vector2 ret;
- if (GDVIRTUAL_CALL(_font_get_kerning, p_font_rid, p_size, p_glyph_pair, ret)) {
- return ret;
- }
- return Vector2();
+ GDVIRTUAL_CALL(_font_get_kerning, p_font_rid, p_size, p_glyph_pair, ret);
+ return ret;
}
int64_t TextServerExtension::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret);
+ return ret;
}
bool TextServerExtension::font_has_char(const RID &p_font_rid, int64_t p_char) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret);
+ return ret;
}
String TextServerExtension::font_get_supported_chars(const RID &p_font_rid) const {
String ret;
- if (GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_render_range(const RID &p_font_rid, const Vector2i &p_size, int64_t p_start, int64_t p_end) {
@@ -919,11 +813,9 @@ void TextServerExtension::font_draw_glyph_outline(const RID &p_font_rid, const R
}
bool TextServerExtension::font_is_language_supported(const RID &p_font_rid, const String &p_language) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_is_language_supported, p_font_rid, p_language, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_is_language_supported, p_font_rid, p_language, ret);
+ return ret;
}
void TextServerExtension::font_set_language_support_override(const RID &p_font_rid, const String &p_language, bool p_supported) {
@@ -931,11 +823,9 @@ void TextServerExtension::font_set_language_support_override(const RID &p_font_r
}
bool TextServerExtension::font_get_language_support_override(const RID &p_font_rid, const String &p_language) {
- bool ret;
- if (GDVIRTUAL_CALL(_font_get_language_support_override, p_font_rid, p_language, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_get_language_support_override, p_font_rid, p_language, ret);
+ return ret;
}
void TextServerExtension::font_remove_language_support_override(const RID &p_font_rid, const String &p_language) {
@@ -944,18 +834,14 @@ void TextServerExtension::font_remove_language_support_override(const RID &p_fon
PackedStringArray TextServerExtension::font_get_language_support_overrides(const RID &p_font_rid) {
PackedStringArray ret;
- if (GDVIRTUAL_CALL(_font_get_language_support_overrides, p_font_rid, ret)) {
- return ret;
- }
- return PackedStringArray();
+ GDVIRTUAL_CALL(_font_get_language_support_overrides, p_font_rid, ret);
+ return ret;
}
bool TextServerExtension::font_is_script_supported(const RID &p_font_rid, const String &p_script) const {
- bool ret;
- if (GDVIRTUAL_CALL(_font_is_script_supported, p_font_rid, p_script, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_is_script_supported, p_font_rid, p_script, ret);
+ return ret;
}
void TextServerExtension::font_set_script_support_override(const RID &p_font_rid, const String &p_script, bool p_supported) {
@@ -963,11 +849,9 @@ void TextServerExtension::font_set_script_support_override(const RID &p_font_rid
}
bool TextServerExtension::font_get_script_support_override(const RID &p_font_rid, const String &p_script) {
- bool ret;
- if (GDVIRTUAL_CALL(_font_get_script_support_override, p_font_rid, p_script, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_font_get_script_support_override, p_font_rid, p_script, ret);
+ return ret;
}
void TextServerExtension::font_remove_script_support_override(const RID &p_font_rid, const String &p_script) {
@@ -976,10 +860,8 @@ void TextServerExtension::font_remove_script_support_override(const RID &p_font_
PackedStringArray TextServerExtension::font_get_script_support_overrides(const RID &p_font_rid) {
PackedStringArray ret;
- if (GDVIRTUAL_CALL(_font_get_script_support_overrides, p_font_rid, ret)) {
- return ret;
- }
- return PackedStringArray();
+ GDVIRTUAL_CALL(_font_get_script_support_overrides, p_font_rid, ret);
+ return ret;
}
void TextServerExtension::font_set_opentype_feature_overrides(const RID &p_font_rid, const Dictionary &p_overrides) {
@@ -988,34 +870,26 @@ void TextServerExtension::font_set_opentype_feature_overrides(const RID &p_font_
Dictionary TextServerExtension::font_get_opentype_feature_overrides(const RID &p_font_rid) const {
Dictionary ret;
- if (GDVIRTUAL_CALL(_font_get_opentype_feature_overrides, p_font_rid, ret)) {
- return ret;
- }
- return Dictionary();
+ GDVIRTUAL_CALL(_font_get_opentype_feature_overrides, p_font_rid, ret);
+ return ret;
}
Dictionary TextServerExtension::font_supported_feature_list(const RID &p_font_rid) const {
Dictionary ret;
- if (GDVIRTUAL_CALL(_font_supported_feature_list, p_font_rid, ret)) {
- return ret;
- }
- return Dictionary();
+ GDVIRTUAL_CALL(_font_supported_feature_list, p_font_rid, ret);
+ return ret;
}
Dictionary TextServerExtension::font_supported_variation_list(const RID &p_font_rid) const {
Dictionary ret;
- if (GDVIRTUAL_CALL(_font_supported_variation_list, p_font_rid, ret)) {
- return ret;
- }
- return Dictionary();
+ GDVIRTUAL_CALL(_font_supported_variation_list, p_font_rid, ret);
+ return ret;
}
double TextServerExtension::font_get_global_oversampling() const {
- double ret;
- if (GDVIRTUAL_CALL(_font_get_global_oversampling, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_font_get_global_oversampling, ret);
+ return ret;
}
void TextServerExtension::font_set_global_oversampling(double p_oversampling) {
@@ -1042,10 +916,8 @@ void TextServerExtension::draw_hex_code_box(const RID &p_canvas, int64_t p_size,
RID TextServerExtension::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
RID ret;
- if (GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret)) {
- return ret;
- }
- return RID();
+ GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret);
+ return ret;
}
void TextServerExtension::shaped_text_clear(const RID &p_shaped) {
@@ -1057,19 +929,15 @@ void TextServerExtension::shaped_text_set_direction(const RID &p_shaped, TextSer
}
TextServer::Direction TextServerExtension::shaped_text_get_direction(const RID &p_shaped) const {
- TextServer::Direction ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret)) {
- return (TextServer::Direction)ret;
- }
- return TextServer::Direction::DIRECTION_AUTO;
+ TextServer::Direction ret = TextServer::DIRECTION_AUTO;
+ GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret);
+ return ret;
}
TextServer::Direction TextServerExtension::shaped_text_get_inferred_direction(const RID &p_shaped) const {
- TextServer::Direction ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_inferred_direction, p_shaped, ret)) {
- return (TextServer::Direction)ret;
- }
- return TextServer::Direction::DIRECTION_LTR;
+ TextServer::Direction ret = TextServer::DIRECTION_LTR;
+ GDVIRTUAL_CALL(_shaped_text_get_inferred_direction, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_set_orientation(const RID &p_shaped, TextServer::Orientation p_orientation) {
@@ -1077,11 +945,9 @@ void TextServerExtension::shaped_text_set_orientation(const RID &p_shaped, TextS
}
TextServer::Orientation TextServerExtension::shaped_text_get_orientation(const RID &p_shaped) const {
- TextServer::Orientation ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret)) {
- return (TextServer::Orientation)ret;
- }
- return TextServer::Orientation::ORIENTATION_HORIZONTAL;
+ TextServer::Orientation ret = TextServer::ORIENTATION_HORIZONTAL;
+ GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_set_bidi_override(const RID &p_shaped, const Array &p_override) {
@@ -1094,10 +960,8 @@ void TextServerExtension::shaped_text_set_custom_punctuation(const RID &p_shaped
String TextServerExtension::shaped_text_get_custom_punctuation(const RID &p_shaped) const {
String ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_custom_punctuation, p_shaped, ret)) {
- return ret;
- }
- return String();
+ GDVIRTUAL_CALL(_shaped_text_get_custom_punctuation, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_set_preserve_invalid(const RID &p_shaped, bool p_enabled) {
@@ -1105,11 +969,9 @@ void TextServerExtension::shaped_text_set_preserve_invalid(const RID &p_shaped,
}
bool TextServerExtension::shaped_text_get_preserve_invalid(const RID &p_shaped) const {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_preserve_invalid, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_get_preserve_invalid, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_set_preserve_control(const RID &p_shaped, bool p_enabled) {
@@ -1117,11 +979,9 @@ void TextServerExtension::shaped_text_set_preserve_control(const RID &p_shaped,
}
bool TextServerExtension::shaped_text_get_preserve_control(const RID &p_shaped) const {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_preserve_control, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_get_preserve_control, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_set_spacing(const RID &p_shaped, TextServer::SpacingType p_spacing, int64_t p_value) {
@@ -1129,51 +989,39 @@ void TextServerExtension::shaped_text_set_spacing(const RID &p_shaped, TextServe
}
int64_t TextServerExtension::shaped_text_get_spacing(const RID &p_shaped, TextServer::SpacingType p_spacing) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_spacing, p_shaped, p_spacing, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_spacing, p_shaped, p_spacing, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, ret);
+ return ret;
}
int64_t TextServerExtension::shaped_get_span_count(const RID &p_shaped) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret);
+ return ret;
}
Variant TextServerExtension::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const {
- Variant ret;
- if (GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret)) {
- return ret;
- }
- return false;
+ Variant ret = false;
+ GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret);
+ return ret;
}
void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) {
@@ -1182,98 +1030,74 @@ void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64
RID TextServerExtension::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const {
RID ret;
- if (GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret)) {
- return ret;
- }
- return RID();
+ GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret);
+ return ret;
}
RID TextServerExtension::shaped_text_get_parent(const RID &p_shaped) const {
RID ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret)) {
- return ret;
- }
- return RID();
+ GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_fit_to_width(const RID &p_shaped, double p_width, BitField<TextServer::JustificationFlag> p_jst_flags) {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_fit_to_width, p_shaped, p_width, p_jst_flags, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_fit_to_width, p_shaped, p_width, p_jst_flags, ret);
+ return ret;
}
double TextServerExtension::shaped_text_tab_align(const RID &p_shaped, const PackedFloat32Array &p_tab_stops) {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_tab_align, p_shaped, p_tab_stops, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_tab_align, p_shaped, p_tab_stops, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_shape(const RID &p_shaped) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_update_breaks(const RID &p_shaped) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_update_breaks, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_update_breaks, p_shaped, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_update_justification_ops(const RID &p_shaped) {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_update_justification_ops, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_update_justification_ops, p_shaped, ret);
+ return ret;
}
bool TextServerExtension::shaped_text_is_ready(const RID &p_shaped) const {
- bool ret;
- if (GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret)) {
- return ret;
- }
- return false;
+ bool ret = false;
+ GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret);
+ return ret;
}
const Glyph *TextServerExtension::shaped_text_get_glyphs(const RID &p_shaped) const {
GDNativeConstPtr<const Glyph> ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret)) {
- return ret;
- }
- return nullptr;
+ GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret);
+ return ret;
}
const Glyph *TextServerExtension::shaped_text_sort_logical(const RID &p_shaped) {
GDNativeConstPtr<const Glyph> ret;
- if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret)) {
- return ret;
- }
- return nullptr;
+ GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret);
+ return ret;
}
int64_t TextServerExtension::shaped_text_get_glyph_count(const RID &p_shaped) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret)) {
- return ret;
- }
- return 0;
+ int64_t ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret);
+ return ret;
}
Vector2i TextServerExtension::shaped_text_get_range(const RID &p_shaped) const {
Vector2i ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret)) {
- return ret;
- }
- return Vector2i();
+ GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret);
+ return ret;
}
PackedInt32Array TextServerExtension::shaped_text_get_line_breaks_adv(const RID &p_shaped, const PackedFloat32Array &p_width, int64_t p_start, bool p_once, BitField<TextServer::LineBreakFlag> p_break_flags) const {
@@ -1301,35 +1125,27 @@ PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(const RID &p_s
}
int64_t TextServerExtension::shaped_text_get_trim_pos(const RID &p_shaped) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret)) {
- return ret;
- }
- return -1;
+ int64_t ret = -1;
+ GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret);
+ return ret;
}
int64_t TextServerExtension::shaped_text_get_ellipsis_pos(const RID &p_shaped) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret)) {
- return ret;
- }
- return -1;
+ int64_t ret = -1;
+ GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret);
+ return ret;
}
const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const {
GDNativeConstPtr<const Glyph> ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret)) {
- return ret;
- }
- return nullptr;
+ GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret);
+ return ret;
}
int64_t TextServerExtension::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const {
- int64_t ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret)) {
- return ret;
- }
- return -1;
+ int64_t ret = -1;
+ GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret);
+ return ret;
}
void TextServerExtension::shaped_text_overrun_trim_to_width(const RID &p_shaped_line, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) {
@@ -1338,66 +1154,50 @@ void TextServerExtension::shaped_text_overrun_trim_to_width(const RID &p_shaped_
Array TextServerExtension::shaped_text_get_objects(const RID &p_shaped) const {
Array ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret)) {
- return ret;
- }
- return Array();
+ GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret);
+ return ret;
}
Rect2 TextServerExtension::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const {
Rect2 ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret)) {
- return ret;
- }
- return Rect2();
+ GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret);
+ return ret;
}
Size2 TextServerExtension::shaped_text_get_size(const RID &p_shaped) const {
Size2 ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret)) {
- return ret;
- }
- return Size2();
+ GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_get_ascent(const RID &p_shaped) const {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_get_descent(const RID &p_shaped) const {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_get_width(const RID &p_shaped) const {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_get_underline_position(const RID &p_shaped) const {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret);
+ return ret;
}
double TextServerExtension::shaped_text_get_underline_thickness(const RID &p_shaped) const {
- double ret;
- if (GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret)) {
- return ret;
- }
- return 0.0;
+ double ret = 0;
+ GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret);
+ return ret;
}
TextServer::Direction TextServerExtension::shaped_text_get_dominant_direction_in_range(const RID &p_shaped, int64_t p_start, int64_t p_end) const {
@@ -1495,11 +1295,9 @@ String TextServerExtension::parse_number(const String &p_string, const String &p
}
String TextServerExtension::percent_sign(const String &p_language) const {
- String ret;
- if (GDVIRTUAL_CALL(_percent_sign, p_language, ret)) {
- return ret;
- }
- return "%";
+ String ret = "%";
+ GDVIRTUAL_CALL(_percent_sign, p_language, ret);
+ return ret;
}
bool TextServerExtension::is_valid_identifier(const String &p_string) const {
@@ -1536,18 +1334,14 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
TypedArray<Vector2i> ret;
- if (GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret)) {
- return ret;
- }
- return TypedArray<Vector2i>();
+ GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
+ return ret;
}
PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language) const {
PackedInt32Array ret;
- if (GDVIRTUAL_CALL(_string_get_word_breaks, p_string, p_language, ret)) {
- return ret;
- }
- return PackedInt32Array();
+ GDVIRTUAL_CALL(_string_get_word_breaks, p_string, p_language, ret);
+ return ret;
}
int64_t TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 588c837a40..dfeb5cb70c 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -956,6 +956,11 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
if (glyphs[i].count > 0) {
// Caret before grapheme (top / left).
if (p_position == glyphs[i].start && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
+ real_t advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start);
Rect2 cr;
if (orientation == ORIENTATION_HORIZONTAL) {
if (glyphs[i].start == range.x) {
@@ -967,15 +972,11 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
cr.position.x = off;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
caret.t_dir = DIRECTION_RTL;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
- cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.position.x += advance;
+ cr.size.x = -char_adv;
} else {
caret.t_dir = DIRECTION_LTR;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.size.x = char_adv;
}
} else {
if (glyphs[i].start == range.x) {
@@ -987,21 +988,22 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
cr.position.y = off;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
caret.t_dir = DIRECTION_RTL;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
- cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.position.y += advance;
+ cr.size.y = -char_adv;
} else {
caret.t_dir = DIRECTION_LTR;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.size.y = char_adv;
}
}
caret.t_caret = cr;
}
// Caret after grapheme (bottom / right).
if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) {
+ real_t advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance * glyphs[i + j].repeat;
+ }
+ real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start);
Rect2 cr;
if (orientation == ORIENTATION_HORIZONTAL) {
if (glyphs[i].end == range.y) {
@@ -1014,15 +1016,11 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
cr.position.x = off;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
caret.l_dir = DIRECTION_LTR;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat;
- cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.position.x += advance;
+ cr.size.x = -char_adv;
} else {
caret.l_dir = DIRECTION_RTL;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.size.x = char_adv;
}
} else {
cr.size.y = 1.0f;
@@ -1036,15 +1034,12 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
cr.position.y = off;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) {
caret.l_dir = DIRECTION_LTR;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat;
- cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.position.y += advance;
+ cr.size.y = -char_adv;
} else {
caret.l_dir = DIRECTION_RTL;
- for (int j = 0; j < glyphs[i].count; j++) {
- cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat;
- }
+ cr.position.x += advance;
+ cr.size.y = char_adv;
}
}
caret.l_caret = cr;
@@ -1058,22 +1053,24 @@ CaretInfo TextServer::shaped_text_get_carets(const RID &p_shaped, int64_t p_posi
real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start);
Rect2 cr;
if (orientation == ORIENTATION_HORIZONTAL) {
- cr.size.x = 1.0f;
cr.size.y = height * 2;
cr.position.y = -ascent;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
cr.position.x = off + char_adv * (glyphs[i].end - p_position);
+ cr.size.x = -char_adv;
} else {
cr.position.x = off + char_adv * (p_position - glyphs[i].start);
+ cr.size.x = char_adv;
}
} else {
- cr.size.y = 1.0f;
cr.size.x = height * 2;
cr.position.x = -ascent;
if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) {
cr.position.y = off + char_adv * (glyphs[i].end - p_position);
+ cr.size.y = -char_adv;
} else {
cr.position.y = off + char_adv * (p_position - glyphs[i].start);
+ cr.size.y = char_adv;
}
}
caret.t_caret = cr;
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index 430a5bfd16..a5ee1d5726 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -222,12 +222,7 @@ RID XRInterface::get_vrs_texture() {
data_ptr[d++] = density;
}
}
-
- Ref<Image> image;
- image.instantiate();
- image->create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_R8, data);
-
- images.push_back(image);
+ images.push_back(Image::create_from_data(vrs_sizei.x, vrs_sizei.y, false, Image::FORMAT_R8, data));
}
if (images.size() == 1) {
@@ -241,6 +236,19 @@ RID XRInterface::get_vrs_texture() {
}
/** these are optional, so we want dummies **/
+
+RID XRInterface::get_color_texture() {
+ return RID();
+}
+
+RID XRInterface::get_depth_texture() {
+ return RID();
+}
+
+RID XRInterface::get_velocity_texture() {
+ return RID();
+}
+
PackedStringArray XRInterface::get_suggested_tracker_names() const {
PackedStringArray arr;
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index 17ff5f8add..86d328d41c 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -121,8 +121,9 @@ public:
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */
virtual RID get_vrs_texture(); /* obtain VRS texture */
-
- // note, external color/depth/vrs texture support will be added here soon.
+ virtual RID get_color_texture(); /* obtain color output texture (if applicable) */
+ virtual RID get_depth_texture(); /* obtain depth output texture (if applicable, used for reprojection) */
+ virtual RID get_velocity_texture(); /* obtain velocity output texture (if applicable, used for spacewarp) */
virtual void process() = 0;
virtual void pre_render(){};
diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp
index 7024a25528..f90e32a987 100644
--- a/servers/xr/xr_interface_extension.cpp
+++ b/servers/xr/xr_interface_extension.cpp
@@ -74,6 +74,15 @@ void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_set_anchor_detection_is_enabled, "enabled");
GDVIRTUAL_BIND(_get_camera_feed_id);
+ // override output methods
+ GDVIRTUAL_BIND(_get_color_texture);
+ GDVIRTUAL_BIND(_get_depth_texture);
+ GDVIRTUAL_BIND(_get_velocity_texture);
+
+ ClassDB::bind_method(D_METHOD("get_color_texture"), &XRInterfaceExtension::get_color_texture);
+ ClassDB::bind_method(D_METHOD("get_depth_texture"), &XRInterfaceExtension::get_depth_texture);
+ ClassDB::bind_method(D_METHOD("get_velocity_texture"), &XRInterfaceExtension::get_velocity_texture);
+
// helper methods
ClassDB::bind_method(D_METHOD("add_blit", "render_target", "src_rect", "dst_rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit);
ClassDB::bind_method(D_METHOD("get_render_target_texture", "render_target"), &XRInterfaceExtension::get_render_target_texture);
@@ -91,33 +100,21 @@ StringName XRInterfaceExtension::get_name() const {
}
uint32_t XRInterfaceExtension::get_capabilities() const {
- uint32_t capabilities;
-
- if (GDVIRTUAL_CALL(_get_capabilities, capabilities)) {
- return capabilities;
- }
-
- return 0;
+ uint32_t capabilities = 0;
+ GDVIRTUAL_CALL(_get_capabilities, capabilities);
+ return capabilities;
}
bool XRInterfaceExtension::is_initialized() const {
bool initialised = false;
-
- if (GDVIRTUAL_CALL(_is_initialized, initialised)) {
- return initialised;
- }
-
- return false;
+ GDVIRTUAL_CALL(_is_initialized, initialised);
+ return initialised;
}
bool XRInterfaceExtension::initialize() {
bool initialised = false;
-
- if (GDVIRTUAL_CALL(_initialize, initialised)) {
- return initialised;
- }
-
- return false;
+ GDVIRTUAL_CALL(_initialize, initialised);
+ return initialised;
}
void XRInterfaceExtension::uninitialize() {
@@ -141,13 +138,9 @@ PackedStringArray XRInterfaceExtension::get_suggested_pose_names(const StringNam
}
XRInterface::TrackingStatus XRInterfaceExtension::get_tracking_status() const {
- uint32_t status;
-
- if (GDVIRTUAL_CALL(_get_tracking_status, status)) {
- return TrackingStatus(status);
- }
-
- return XR_UNKNOWN_TRACKING;
+ uint32_t status = XR_UNKNOWN_TRACKING;
+ GDVIRTUAL_CALL(_get_tracking_status, status);
+ return TrackingStatus(status);
}
void XRInterfaceExtension::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
@@ -155,52 +148,34 @@ void XRInterfaceExtension::trigger_haptic_pulse(const String &p_action_name, con
}
bool XRInterfaceExtension::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
- bool is_supported;
-
- if (GDVIRTUAL_CALL(_supports_play_area_mode, p_mode, is_supported)) {
- return is_supported;
- }
-
- return false;
+ bool is_supported = false;
+ GDVIRTUAL_CALL(_supports_play_area_mode, p_mode, is_supported);
+ return is_supported;
}
XRInterface::PlayAreaMode XRInterfaceExtension::get_play_area_mode() const {
- uint32_t mode;
-
- if (GDVIRTUAL_CALL(_get_play_area_mode, mode)) {
- return XRInterface::PlayAreaMode(mode);
- }
-
- return XRInterface::XR_PLAY_AREA_UNKNOWN;
+ uint32_t mode = XR_PLAY_AREA_UNKNOWN;
+ GDVIRTUAL_CALL(_get_play_area_mode, mode);
+ return XRInterface::PlayAreaMode(mode);
}
bool XRInterfaceExtension::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
- bool success;
-
- if (GDVIRTUAL_CALL(_set_play_area_mode, p_mode, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_set_play_area_mode, p_mode, success);
+ return success;
}
PackedVector3Array XRInterfaceExtension::get_play_area() const {
PackedVector3Array arr;
-
GDVIRTUAL_CALL(_get_play_area, arr);
-
return arr;
}
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool XRInterfaceExtension::get_anchor_detection_is_enabled() const {
- bool enabled;
-
- if (GDVIRTUAL_CALL(_get_anchor_detection_is_enabled, enabled)) {
- return enabled;
- }
-
- return false;
+ bool enabled = false;
+ GDVIRTUAL_CALL(_get_anchor_detection_is_enabled, enabled);
+ return enabled;
}
void XRInterfaceExtension::set_anchor_detection_is_enabled(bool p_enable) {
@@ -209,53 +184,33 @@ void XRInterfaceExtension::set_anchor_detection_is_enabled(bool p_enable) {
}
int XRInterfaceExtension::get_camera_feed_id() {
- int feed_id;
-
- if (GDVIRTUAL_CALL(_get_camera_feed_id, feed_id)) {
- return feed_id;
- }
-
- return 0;
+ int feed_id = 0;
+ GDVIRTUAL_CALL(_get_camera_feed_id, feed_id);
+ return feed_id;
}
Size2 XRInterfaceExtension::get_render_target_size() {
Size2 size;
-
- if (GDVIRTUAL_CALL(_get_render_target_size, size)) {
- return size;
- }
-
- return Size2(0, 0);
+ GDVIRTUAL_CALL(_get_render_target_size, size);
+ return size;
}
uint32_t XRInterfaceExtension::get_view_count() {
- uint32_t view_count;
-
- if (GDVIRTUAL_CALL(_get_view_count, view_count)) {
- return view_count;
- }
-
- return 1;
+ uint32_t view_count = 1;
+ GDVIRTUAL_CALL(_get_view_count, view_count);
+ return view_count;
}
Transform3D XRInterfaceExtension::get_camera_transform() {
Transform3D transform;
-
- if (GDVIRTUAL_CALL(_get_camera_transform, transform)) {
- return transform;
- }
-
- return Transform3D();
+ GDVIRTUAL_CALL(_get_camera_transform, transform);
+ return transform;
}
Transform3D XRInterfaceExtension::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
Transform3D transform;
-
- if (GDVIRTUAL_CALL(_get_transform_for_view, p_view, p_cam_transform, transform)) {
- return transform;
- }
-
- return Transform3D();
+ GDVIRTUAL_CALL(_get_transform_for_view, p_view, p_cam_transform, transform);
+ return transform;
}
Projection XRInterfaceExtension::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
@@ -264,7 +219,7 @@ Projection XRInterfaceExtension::get_projection_for_view(uint32_t p_view, double
if (GDVIRTUAL_CALL(_get_projection_for_view, p_view, p_aspect, p_z_near, p_z_far, arr)) {
ERR_FAIL_COND_V_MSG(arr.size() != 16, Projection(), "Projection matrix must contain 16 floats");
- real_t *m = (real_t *)cm.matrix;
+ real_t *m = (real_t *)cm.columns;
for (int i = 0; i < 16; i++) {
m[i] = arr[i];
}
@@ -283,6 +238,24 @@ RID XRInterfaceExtension::get_vrs_texture() {
}
}
+RID XRInterfaceExtension::get_color_texture() {
+ RID texture;
+ GDVIRTUAL_CALL(_get_color_texture, texture);
+ return texture;
+}
+
+RID XRInterfaceExtension::get_depth_texture() {
+ RID texture;
+ GDVIRTUAL_CALL(_get_depth_texture, texture);
+ return texture;
+}
+
+RID XRInterfaceExtension::get_velocity_texture() {
+ RID texture;
+ GDVIRTUAL_CALL(_get_velocity_texture, texture);
+ return texture;
+}
+
void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) {
BlitToScreen blit;
@@ -315,13 +288,8 @@ void XRInterfaceExtension::pre_render() {
bool XRInterfaceExtension::pre_draw_viewport(RID p_render_target) {
bool do_render = true;
-
- if (GDVIRTUAL_CALL(_pre_draw_viewport, p_render_target, do_render)) {
- return do_render;
- } else {
- // if not implemented we're returning true
- return true;
- }
+ GDVIRTUAL_CALL(_pre_draw_viewport, p_render_target, do_render);
+ return do_render; // If not implemented we're returning true.
}
Vector<BlitToScreen> XRInterfaceExtension::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) {
diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h
index 65b474425e..2235b57cb3 100644
--- a/servers/xr/xr_interface_extension.h
+++ b/servers/xr/xr_interface_extension.h
@@ -102,6 +102,9 @@ public:
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
virtual Projection get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
virtual RID get_vrs_texture() override;
+ virtual RID get_color_texture() override;
+ virtual RID get_depth_texture() override;
+ virtual RID get_velocity_texture() override;
GDVIRTUAL0R(Size2, _get_render_target_size);
GDVIRTUAL0R(uint32_t, _get_view_count);
@@ -109,6 +112,9 @@ public:
GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double);
GDVIRTUAL0R(RID, _get_vrs_texture);
+ GDVIRTUAL0R(RID, _get_color_texture);
+ GDVIRTUAL0R(RID, _get_depth_texture);
+ GDVIRTUAL0R(RID, _get_velocity_texture);
void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0);
diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h
index 38b616cda0..181d9a8a54 100644
--- a/tests/core/io/test_image.h
+++ b/tests/core/io/test_image.h
@@ -124,7 +124,7 @@ TEST_CASE("[Image] Saving and loading") {
image_jpg->load_jpg_from_buffer(data_jpg) == OK,
"The JPG image should load successfully.");
- // Load WEBP
+ // Load WebP
Ref<Image> image_webp = memnew(Image());
Ref<FileAccess> f_webp = FileAccess::open(TestUtils::get_data_path("images/icon.webp"), FileAccess::READ, &err);
PackedByteArray data_webp;
@@ -132,7 +132,7 @@ TEST_CASE("[Image] Saving and loading") {
f_webp->get_buffer(data_webp.ptrw(), f_webp->get_length());
CHECK_MESSAGE(
image_webp->load_webp_from_buffer(data_webp) == OK,
- "The WEBP image should load successfully.");
+ "The WebP image should load successfully.");
// Load PNG
Ref<Image> image_png = memnew(Image());
diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h
index d5f54a139e..ebaf441abf 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -389,6 +389,27 @@ TEST_CASE("[AABB] Expanding") {
aabb.expand(Vector3(-20, 0, 0)).is_equal_approx(AABB(Vector3(-20, 0, -2.5), Vector3(22.5, 7, 6))),
"expand() with non-contained point should return the expected AABB.");
}
+
+TEST_CASE("[AABB] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite(NAN, NAN, NAN);
+
+ CHECK_MESSAGE(
+ AABB(x, x).is_finite(),
+ "AABB with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ AABB(infinite, x).is_finite(),
+ "AABB with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ AABB(x, infinite).is_finite(),
+ "AABB with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ AABB(infinite, infinite).is_finite(),
+ "AABB with two components infinite should not be finite.");
+}
+
} // namespace TestAABB
#endif // TEST_AABB_H
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index b6493c5726..f52b715cd7 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -38,15 +38,6 @@
namespace TestBasis {
-enum RotOrder {
- EulerXYZ,
- EulerXZY,
- EulerYZX,
- EulerYXZ,
- EulerZXY,
- EulerZYX
-};
-
Vector3 deg_to_rad(const Vector3 &p_rotation) {
return p_rotation / 180.0 * Math_PI;
}
@@ -55,88 +46,26 @@ Vector3 rad2deg(const Vector3 &p_rotation) {
return p_rotation / Math_PI * 180.0;
}
-Basis EulerToBasis(RotOrder mode, const Vector3 &p_rotation) {
- Basis ret;
- switch (mode) {
- case EulerXYZ:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ);
- break;
-
- case EulerXZY:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY);
- break;
-
- case EulerYZX:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX);
- break;
-
- case EulerYXZ:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ);
- break;
-
- case EulerZXY:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY);
- break;
-
- case EulerZYX:
- ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX);
- break;
-
- default:
- // If you land here, Please integrate all rotation orders.
- FAIL("This is not unreachable.");
- }
-
- return ret;
-}
-
-Vector3 BasisToEuler(RotOrder mode, const Basis &p_rotation) {
- switch (mode) {
- case EulerXYZ:
- return p_rotation.get_euler(Basis::EULER_ORDER_XYZ);
-
- case EulerXZY:
- return p_rotation.get_euler(Basis::EULER_ORDER_XZY);
-
- case EulerYZX:
- return p_rotation.get_euler(Basis::EULER_ORDER_YZX);
-
- case EulerYXZ:
- return p_rotation.get_euler(Basis::EULER_ORDER_YXZ);
-
- case EulerZXY:
- return p_rotation.get_euler(Basis::EULER_ORDER_ZXY);
-
- case EulerZYX:
- return p_rotation.get_euler(Basis::EULER_ORDER_ZYX);
-
- default:
- // If you land here, Please integrate all rotation orders.
- FAIL("This is not unreachable.");
- return Vector3();
- }
-}
-
-String get_rot_order_name(RotOrder ro) {
+String get_rot_order_name(Basis::EulerOrder ro) {
switch (ro) {
- case EulerXYZ:
+ case Basis::EULER_ORDER_XYZ:
return "XYZ";
- case EulerXZY:
+ case Basis::EULER_ORDER_XZY:
return "XZY";
- case EulerYZX:
+ case Basis::EULER_ORDER_YZX:
return "YZX";
- case EulerYXZ:
+ case Basis::EULER_ORDER_YXZ:
return "YXZ";
- case EulerZXY:
+ case Basis::EULER_ORDER_ZXY:
return "ZXY";
- case EulerZYX:
+ case Basis::EULER_ORDER_ZYX:
return "ZYX";
default:
return "[Not supported]";
}
}
-void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
+void test_rotation(Vector3 deg_original_euler, Basis::EulerOrder rot_order) {
// This test:
// 1. Converts the rotation vector from deg to rad.
// 2. Converts euler to basis.
@@ -156,11 +85,11 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
// Euler to rotation
const Vector3 original_euler = deg_to_rad(deg_original_euler);
- const Basis to_rotation = EulerToBasis(rot_order, original_euler);
+ const Basis to_rotation = Basis::from_euler(original_euler, rot_order);
// Euler from rotation
- const Vector3 euler_from_rotation = BasisToEuler(rot_order, to_rotation);
- const Basis rotation_from_computed_euler = EulerToBasis(rot_order, euler_from_rotation);
+ const Vector3 euler_from_rotation = to_rotation.get_euler(rot_order);
+ const Basis rotation_from_computed_euler = Basis::from_euler(euler_from_rotation, rot_order);
Basis res = to_rotation.inverse() * rotation_from_computed_euler;
@@ -170,8 +99,7 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
// Double check `to_rotation` decomposing with XYZ rotation order.
const Vector3 euler_xyz_from_rotation = to_rotation.get_euler(Basis::EULER_ORDER_XYZ);
- Basis rotation_from_xyz_computed_euler;
- rotation_from_xyz_computed_euler.set_euler(euler_xyz_from_rotation, Basis::EULER_ORDER_XYZ);
+ Basis rotation_from_xyz_computed_euler = Basis::from_euler(euler_xyz_from_rotation, Basis::EULER_ORDER_XYZ);
res = to_rotation.inverse() * rotation_from_xyz_computed_euler;
@@ -185,13 +113,13 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
}
TEST_CASE("[Basis] Euler conversions") {
- Vector<RotOrder> rotorder_to_test;
- rotorder_to_test.push_back(EulerXYZ);
- rotorder_to_test.push_back(EulerXZY);
- rotorder_to_test.push_back(EulerYZX);
- rotorder_to_test.push_back(EulerYXZ);
- rotorder_to_test.push_back(EulerZXY);
- rotorder_to_test.push_back(EulerZYX);
+ Vector<Basis::EulerOrder> euler_order_to_test;
+ euler_order_to_test.push_back(Basis::EULER_ORDER_XYZ);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_XZY);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_YZX);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_YXZ);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_ZXY);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_ZYX);
Vector<Vector3> vectors_to_test;
@@ -249,21 +177,21 @@ TEST_CASE("[Basis] Euler conversions") {
vectors_to_test.push_back(Vector3(120.0, 150.0, -130.0));
vectors_to_test.push_back(Vector3(120.0, 150.0, 130.0));
- for (int h = 0; h < rotorder_to_test.size(); h += 1) {
+ for (int h = 0; h < euler_order_to_test.size(); h += 1) {
for (int i = 0; i < vectors_to_test.size(); i += 1) {
- test_rotation(vectors_to_test[i], rotorder_to_test[h]);
+ test_rotation(vectors_to_test[i], euler_order_to_test[h]);
}
}
}
TEST_CASE("[Stress][Basis] Euler conversions") {
- Vector<RotOrder> rotorder_to_test;
- rotorder_to_test.push_back(EulerXYZ);
- rotorder_to_test.push_back(EulerXZY);
- rotorder_to_test.push_back(EulerYZX);
- rotorder_to_test.push_back(EulerYXZ);
- rotorder_to_test.push_back(EulerZXY);
- rotorder_to_test.push_back(EulerZYX);
+ Vector<Basis::EulerOrder> euler_order_to_test;
+ euler_order_to_test.push_back(Basis::EULER_ORDER_XYZ);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_XZY);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_YZX);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_YXZ);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_ZXY);
+ euler_order_to_test.push_back(Basis::EULER_ORDER_ZYX);
Vector<Vector3> vectors_to_test;
// Add 1000 random vectors with weirds numbers.
@@ -275,9 +203,9 @@ TEST_CASE("[Stress][Basis] Euler conversions") {
rng.randf_range(-1800, 1800)));
}
- for (int h = 0; h < rotorder_to_test.size(); h += 1) {
+ for (int h = 0; h < euler_order_to_test.size(); h += 1) {
for (int i = 0; i < vectors_to_test.size(); i += 1) {
- test_rotation(vectors_to_test[i], rotorder_to_test[h]);
+ test_rotation(vectors_to_test[i], euler_order_to_test[h]);
}
}
}
@@ -334,6 +262,40 @@ TEST_CASE("[Basis] Set axis angle") {
bugNan.get_axis_angle(axis, angle);
CHECK(!Math::is_nan(angle));
}
+
+TEST_CASE("[Basis] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite(NAN, NAN, NAN);
+
+ CHECK_MESSAGE(
+ Basis(x, x, x).is_finite(),
+ "Basis with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, x, x).is_finite(),
+ "Basis with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, infinite, x).is_finite(),
+ "Basis with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, x, infinite).is_finite(),
+ "Basis with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, infinite, x).is_finite(),
+ "Basis with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, x, infinite).is_finite(),
+ "Basis with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Basis(x, infinite, infinite).is_finite(),
+ "Basis with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Basis(infinite, infinite, infinite).is_finite(),
+ "Basis with three components infinite should not be finite.");
+}
+
} // namespace TestBasis
#endif // TEST_BASIS_H
diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h
index d81a5af1ce..84d9a0ff7d 100644
--- a/tests/core/math/test_plane.h
+++ b/tests/core/math/test_plane.h
@@ -167,6 +167,29 @@ TEST_CASE("[Plane] Intersection") {
vec_out.is_equal_approx(Vector3(1, 1, 1)),
"intersects_segment() should modify vec_out to the expected result.");
}
+
+TEST_CASE("[Plane] Finite number checks") {
+ const Vector3 x(0, 1, 2);
+ const Vector3 infinite_vec(NAN, NAN, NAN);
+ const real_t y = 0;
+ const real_t infinite_y = NAN;
+
+ CHECK_MESSAGE(
+ Plane(x, y).is_finite(),
+ "Plane with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Plane(x, infinite_y).is_finite(),
+ "Plane with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Plane(infinite_vec, y).is_finite(),
+ "Plane with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Plane(infinite_vec, infinite_y).is_finite(),
+ "Plane with two components infinite should not be finite.");
+}
+
} // namespace TestPlane
#endif // TEST_PLANE_H
diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h
index 63d30759bb..909fc2499f 100644
--- a/tests/core/math/test_quaternion.h
+++ b/tests/core/math/test_quaternion.h
@@ -47,9 +47,9 @@ Quaternion quat_euler_yxz_deg(Vector3 angle) {
// Generate YXZ (Z-then-X-then-Y) Quaternion using single-axis Euler
// constructor and quaternion product, both tested separately.
- Quaternion q_y(Vector3(0.0, yaw, 0.0));
- Quaternion q_p(Vector3(pitch, 0.0, 0.0));
- Quaternion q_r(Vector3(0.0, 0.0, roll));
+ Quaternion q_y = Quaternion::from_euler(Vector3(0.0, yaw, 0.0));
+ Quaternion q_p = Quaternion::from_euler(Vector3(pitch, 0.0, 0.0));
+ Quaternion q_r = Quaternion::from_euler(Vector3(0.0, 0.0, roll));
// Roll-Z is followed by Pitch-X, then Yaw-Y.
Quaternion q_yxz = q_y * q_p * q_r;
@@ -134,21 +134,21 @@ TEST_CASE("[Quaternion] Construct Euler SingleAxis") {
double roll = Math::deg_to_rad(10.0);
Vector3 euler_y(0.0, yaw, 0.0);
- Quaternion q_y(euler_y);
+ Quaternion q_y = Quaternion::from_euler(euler_y);
CHECK(q_y[0] == doctest::Approx(0.0));
CHECK(q_y[1] == doctest::Approx(0.382684));
CHECK(q_y[2] == doctest::Approx(0.0));
CHECK(q_y[3] == doctest::Approx(0.923879));
Vector3 euler_p(pitch, 0.0, 0.0);
- Quaternion q_p(euler_p);
+ Quaternion q_p = Quaternion::from_euler(euler_p);
CHECK(q_p[0] == doctest::Approx(0.258819));
CHECK(q_p[1] == doctest::Approx(0.0));
CHECK(q_p[2] == doctest::Approx(0.0));
CHECK(q_p[3] == doctest::Approx(0.965926));
Vector3 euler_r(0.0, 0.0, roll);
- Quaternion q_r(euler_r);
+ Quaternion q_r = Quaternion::from_euler(euler_r);
CHECK(q_r[0] == doctest::Approx(0.0));
CHECK(q_r[1] == doctest::Approx(0.0));
CHECK(q_r[2] == doctest::Approx(0.0871558));
@@ -163,11 +163,11 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
// Generate YXZ comparison data (Z-then-X-then-Y) using single-axis Euler
// constructor and quaternion product, both tested separately.
Vector3 euler_y(0.0, yaw, 0.0);
- Quaternion q_y(euler_y);
+ Quaternion q_y = Quaternion::from_euler(euler_y);
Vector3 euler_p(pitch, 0.0, 0.0);
- Quaternion q_p(euler_p);
+ Quaternion q_p = Quaternion::from_euler(euler_p);
Vector3 euler_r(0.0, 0.0, roll);
- Quaternion q_r(euler_r);
+ Quaternion q_r = Quaternion::from_euler(euler_r);
// Roll-Z is followed by Pitch-X.
Quaternion check_xz = q_p * q_r;
@@ -176,7 +176,7 @@ TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
// Test construction from YXZ Euler angles.
Vector3 euler_yxz(pitch, yaw, roll);
- Quaternion q(euler_yxz);
+ Quaternion q = Quaternion::from_euler(euler_yxz);
CHECK(q[0] == doctest::Approx(check_yxz[0]));
CHECK(q[1] == doctest::Approx(check_yxz[1]));
CHECK(q[2] == doctest::Approx(check_yxz[2]));
@@ -191,8 +191,8 @@ TEST_CASE("[Quaternion] Construct Basis Euler") {
double pitch = Math::deg_to_rad(30.0);
double roll = Math::deg_to_rad(10.0);
Vector3 euler_yxz(pitch, yaw, roll);
- Quaternion q_yxz(euler_yxz);
- Basis basis_axes(euler_yxz);
+ Quaternion q_yxz = Quaternion::from_euler(euler_yxz);
+ Basis basis_axes = Basis::from_euler(euler_yxz);
Quaternion q(basis_axes);
CHECK(q.is_equal_approx(q_yxz));
}
@@ -209,7 +209,7 @@ TEST_CASE("[Quaternion] Construct Basis Axes") {
// Quaternion from local calculation.
Quaternion q_local = quat_euler_yxz_deg(Vector3(31.41, -49.16, 12.34));
// Quaternion from Euler angles constructor.
- Quaternion q_euler(euler_yxz);
+ Quaternion q_euler = Quaternion::from_euler(euler_yxz);
CHECK(q_calc.is_equal_approx(q_local));
CHECK(q_local.is_equal_approx(q_euler));
@@ -218,7 +218,7 @@ TEST_CASE("[Quaternion] Construct Basis Axes") {
// This is by design, but may be subject to change.
// Workaround by constructing Basis from Euler angles.
// basis_axes = Basis(i_unit, j_unit, k_unit);
- Basis basis_axes(euler_yxz);
+ Basis basis_axes = Basis::from_euler(euler_yxz);
Quaternion q(basis_axes);
CHECK(basis_axes.get_column(0).is_equal_approx(i_unit));
@@ -253,21 +253,21 @@ TEST_CASE("[Quaternion] Product") {
double roll = Math::deg_to_rad(10.0);
Vector3 euler_y(0.0, yaw, 0.0);
- Quaternion q_y(euler_y);
+ Quaternion q_y = Quaternion::from_euler(euler_y);
CHECK(q_y[0] == doctest::Approx(0.0));
CHECK(q_y[1] == doctest::Approx(0.382684));
CHECK(q_y[2] == doctest::Approx(0.0));
CHECK(q_y[3] == doctest::Approx(0.923879));
Vector3 euler_p(pitch, 0.0, 0.0);
- Quaternion q_p(euler_p);
+ Quaternion q_p = Quaternion::from_euler(euler_p);
CHECK(q_p[0] == doctest::Approx(0.258819));
CHECK(q_p[1] == doctest::Approx(0.0));
CHECK(q_p[2] == doctest::Approx(0.0));
CHECK(q_p[3] == doctest::Approx(0.965926));
Vector3 euler_r(0.0, 0.0, roll);
- Quaternion q_r(euler_r);
+ Quaternion q_r = Quaternion::from_euler(euler_r);
CHECK(q_r[0] == doctest::Approx(0.0));
CHECK(q_r[1] == doctest::Approx(0.0));
CHECK(q_r[2] == doctest::Approx(0.0871558));
@@ -334,7 +334,7 @@ TEST_CASE("[Quaternion] xform unit vectors") {
TEST_CASE("[Quaternion] xform vector") {
// Arbitrary quaternion rotates an arbitrary vector.
Vector3 euler_yzx(Math::deg_to_rad(31.41), Math::deg_to_rad(-49.16), Math::deg_to_rad(12.34));
- Basis basis_axes(euler_yzx);
+ Basis basis_axes = Basis::from_euler(euler_yzx);
Quaternion q(basis_axes);
Vector3 v_arb(3.0, 4.0, 5.0);
@@ -347,7 +347,7 @@ TEST_CASE("[Quaternion] xform vector") {
// Test vector xform for a single combination of Quaternion and Vector.
void test_quat_vec_rotate(Vector3 euler_yzx, Vector3 v_in) {
- Basis basis_axes(euler_yzx);
+ Basis basis_axes = Basis::from_euler(euler_yzx);
Quaternion q(basis_axes);
Vector3 v_rot = q.xform(v_in);
@@ -384,6 +384,63 @@ TEST_CASE("[Stress][Quaternion] Many vector xforms") {
}
}
+TEST_CASE("[Quaternion] Finite number checks") {
+ const real_t x = NAN;
+
+ CHECK_MESSAGE(
+ Quaternion(0, 1, 2, 3).is_finite(),
+ "Quaternion with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, 2, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, 2, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, x, 3).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, 2, x).is_finite(),
+ "Quaternion with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, 2, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, x, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, 2, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, x, 3).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, 2, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, 1, x, x).is_finite(),
+ "Quaternion with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(0, x, x, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, 1, x, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, 2, x).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, x, 3).is_finite(),
+ "Quaternion with three components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Quaternion(x, x, x, x).is_finite(),
+ "Quaternion with four components infinite should not be finite.");
+}
+
} // namespace TestQuaternion
#endif // TEST_QUATERNION_H
diff --git a/tests/core/math/test_rect2.h b/tests/core/math/test_rect2.h
index 6323b214db..d784875c1c 100644
--- a/tests/core/math/test_rect2.h
+++ b/tests/core/math/test_rect2.h
@@ -300,6 +300,27 @@ TEST_CASE("[Rect2] Merging") {
Rect2(0, 100, 1280, 720).merge(Rect2(-4000, -4000, 100, 100)).is_equal_approx(Rect2(-4000, -4000, 5280, 4820)),
"merge() with non-enclosed Rect2 should return the expected result.");
}
+
+TEST_CASE("[Rect2] Finite number checks") {
+ const Vector2 x(0, 1);
+ const Vector2 infinite(NAN, NAN);
+
+ CHECK_MESSAGE(
+ Rect2(x, x).is_finite(),
+ "Rect2 with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Rect2(infinite, x).is_finite(),
+ "Rect2 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Rect2(x, infinite).is_finite(),
+ "Rect2 with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Rect2(infinite, infinite).is_finite(),
+ "Rect2 with two components infinite should not be finite.");
+}
+
} // namespace TestRect2
#endif // TEST_RECT2_H
diff --git a/tests/core/math/test_transform_2d.h b/tests/core/math/test_transform_2d.h
index 697bf63fc5..ab51bcd7da 100644
--- a/tests/core/math/test_transform_2d.h
+++ b/tests/core/math/test_transform_2d.h
@@ -83,6 +83,40 @@ TEST_CASE("[Transform2D] rotation") {
CHECK(orig.rotated(phi) == R * orig);
CHECK(orig.rotated_local(phi) == orig * R);
}
+
+TEST_CASE("[Transform2D] Finite number checks") {
+ const Vector2 x(0, 1);
+ const Vector2 infinite(NAN, NAN);
+
+ CHECK_MESSAGE(
+ Transform2D(x, x, x).is_finite(),
+ "Transform2D with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, x, x).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, infinite, x).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, x, infinite).is_finite(),
+ "Transform2D with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, infinite, x).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, x, infinite).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform2D(x, infinite, infinite).is_finite(),
+ "Transform2D with two components infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform2D(infinite, infinite, infinite).is_finite(),
+ "Transform2D with three components infinite should not be finite.");
+}
+
} // namespace TestTransform2D
#endif // TEST_TRANSFORM_2D_H
diff --git a/tests/core/math/test_transform_3d.h b/tests/core/math/test_transform_3d.h
index da166b43f7..d2730f3577 100644
--- a/tests/core/math/test_transform_3d.h
+++ b/tests/core/math/test_transform_3d.h
@@ -84,6 +84,29 @@ TEST_CASE("[Transform3D] rotation") {
CHECK(orig.rotated(axis, phi) == R * orig);
CHECK(orig.rotated_local(axis, phi) == orig * R);
}
+
+TEST_CASE("[Transform3D] Finite number checks") {
+ const Vector3 y(0, 1, 2);
+ const Vector3 infinite_vec(NAN, NAN, NAN);
+ const Basis x(y, y, y);
+ const Basis infinite_basis(infinite_vec, infinite_vec, infinite_vec);
+
+ CHECK_MESSAGE(
+ Transform3D(x, y).is_finite(),
+ "Transform3D with all components finite should be finite");
+
+ CHECK_FALSE_MESSAGE(
+ Transform3D(x, infinite_vec).is_finite(),
+ "Transform3D with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Transform3D(infinite_basis, y).is_finite(),
+ "Transform3D with one component infinite should not be finite.");
+
+ CHECK_FALSE_MESSAGE(
+ Transform3D(infinite_basis, infinite_vec).is_finite(),
+ "Transform3D with two components infinite should not be finite.");
+}
+
} // namespace TestTransform3D
#endif // TEST_TRANSFORM_3D_H
diff --git a/tests/core/math/test_vector2.h b/tests/core/math/test_vector2.h
index 0d7f1163e4..a87b9ffc02 100644
--- a/tests/core/math/test_vector2.h
+++ b/tests/core/math/test_vector2.h
@@ -465,6 +465,32 @@ TEST_CASE("[Vector2] Linear algebra methods") {
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.");
}
+
+TEST_CASE("[Vector2] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector2(0, 1).is_finite(),
+ "Vector2(0, 1) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector2(x, 1).is_finite(),
+ "Vector2 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector2(0, x).is_finite(),
+ "Vector2 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector2(x, y).is_finite(),
+ "Vector2 with two components infinite should not be finite.");
+ }
+ }
+}
+
} // namespace TestVector2
#endif // TEST_VECTOR2_H
diff --git a/tests/core/math/test_vector3.h b/tests/core/math/test_vector3.h
index be271bad1f..4932cd04db 100644
--- a/tests/core/math/test_vector3.h
+++ b/tests/core/math/test_vector3.h
@@ -479,6 +479,51 @@ TEST_CASE("[Vector3] Linear algebra methods") {
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.");
}
+
+TEST_CASE("[Vector3] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector3(0, 1, 2).is_finite(),
+ "Vector3(0, 1, 2) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, 1, 2).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, x, 2).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, 1, x).is_finite(),
+ "Vector3 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, y, 2).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, 1, y).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector3(0, x, y).is_finite(),
+ "Vector3 with two components infinite should not be finite.");
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector3(x, y, z).is_finite(),
+ "Vector3 with three components infinite should not be finite.");
+ }
+ }
+ }
+}
+
} // namespace TestVector3
#endif // TEST_VECTOR3_H
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
index 3f50f16635..b31db56f67 100644
--- a/tests/core/math/test_vector4.h
+++ b/tests/core/math/test_vector4.h
@@ -314,6 +314,84 @@ TEST_CASE("[Vector4] Linear algebra methods") {
Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8),
"Vector4 dot product should work as expected.");
}
+
+TEST_CASE("[Vector4] Finite number checks") {
+ const double infinite[] = { NAN, INFINITY, -INFINITY };
+
+ CHECK_MESSAGE(
+ Vector4(0, 1, 2, 3).is_finite(),
+ "Vector4(0, 1, 2, 3) should be finite");
+
+ for (double x : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, 2, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, 2, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, x, 3).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, 2, x).is_finite(),
+ "Vector4 with one component infinite should not be finite.");
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, 2, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, y, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, 2, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, y, 3).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, 2, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, 1, x, y).is_finite(),
+ "Vector4 with two components infinite should not be finite.");
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(0, x, y, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, 1, y, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, 2, z).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, z, 3).is_finite(),
+ "Vector4 with three components infinite should not be finite.");
+ }
+ }
+ }
+
+ for (double x : infinite) {
+ for (double y : infinite) {
+ for (double z : infinite) {
+ for (double w : infinite) {
+ CHECK_FALSE_MESSAGE(
+ Vector4(x, y, z, w).is_finite(),
+ "Vector4 with four components infinite should not be finite.");
+ }
+ }
+ }
+ }
+}
+
} // namespace TestVector4
#endif // TEST_VECTOR4_H
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 969f5fc096..cd1b421ce8 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -411,9 +411,13 @@ TEST_CASE("[String] Number to string") {
CHECK(String::num_real(3.141593) == "3.141593");
CHECK(String::num_real(3.141) == "3.141"); // No trailing zeros.
#ifdef REAL_T_IS_DOUBLE
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.456789", "Prints the appropriate amount of digits for real_t = double.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.456789", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.14159265358979", "Prints the appropriate amount of digits for real_t = double.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1414999961853", "Prints more digits of 32-bit float when real_t = double (ones that would be reliable for double) and no trailing zero.");
#else
+ CHECK_MESSAGE(String::num_real(123.456789) == "123.4568", "Prints the appropriate amount of digits for real_t = float.");
+ CHECK_MESSAGE(String::num_real(-123.456789) == "-123.4568", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(Math_PI) == "3.141593", "Prints the appropriate amount of digits for real_t = float.");
CHECK_MESSAGE(String::num_real(3.1415f) == "3.1415", "Prints only reliable digits of 32-bit float when real_t = float.");
#endif // REAL_T_IS_DOUBLE
@@ -1424,20 +1428,22 @@ TEST_CASE("[String] dedent") {
}
TEST_CASE("[String] Path functions") {
- static const char *path[7] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc", "C:\\test.", "res://test", "/.test" };
- static const char *base_dir[7] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot", "C:\\", "res://", "/" };
- static const char *base_name[7] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test", "C:\\test", "res://test", "/" };
- static const char *ext[7] = { "tscn", "xscn", "scn", "doc", "", "", "test" };
- static const char *file[7] = { "test.tscn", "test.xscn", "test.scn", "test.doc", "test.", "test", ".test" };
- static const bool abs[7] = { true, true, false, false, true, true, true };
-
- for (int i = 0; i < 7; i++) {
+ static const char *path[8] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc", "C:\\test.", "res://test", "user://test", "/.test" };
+ static const char *base_dir[8] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot", "C:\\", "res://", "user://", "/" };
+ static const char *base_name[8] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test", "C:\\test", "res://test", "user://test", "/" };
+ static const char *ext[8] = { "tscn", "xscn", "scn", "doc", "", "", "", "test" };
+ static const char *file[8] = { "test.tscn", "test.xscn", "test.scn", "test.doc", "test.", "test", "test", ".test" };
+ static const char *simplified[8] = { "C:/Godot/project/test.tscn", "/Godot/project/test.xscn", "Godot/project/test.scn", "Godot/test.doc", "C:/test.", "res://test", "user://test", "/.test" };
+ static const bool abs[8] = { true, true, false, false, true, true, true, true };
+
+ for (int i = 0; i < 8; i++) {
CHECK(String(path[i]).get_base_dir() == base_dir[i]);
CHECK(String(path[i]).get_basename() == base_name[i]);
CHECK(String(path[i]).get_extension() == ext[i]);
CHECK(String(path[i]).get_file() == file[i]);
CHECK(String(path[i]).is_absolute_path() == abs[i]);
CHECK(String(path[i]).is_relative_path() != abs[i]);
+ CHECK(String(path[i]).simplify_path() == String(simplified[i]));
CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path());
}
diff --git a/tests/scene/test_animation.h b/tests/scene/test_animation.h
index 9199713fd9..ca80f0ecab 100644
--- a/tests/scene/test_animation.h
+++ b/tests/scene/test_animation.h
@@ -140,13 +140,13 @@ TEST_CASE("[Animation] Create 3D rotation track") {
Ref<Animation> animation = memnew(Animation);
const int track_index = animation->add_track(Animation::TYPE_ROTATION_3D);
animation->track_set_path(track_index, NodePath("Enemy:rotation"));
- animation->rotation_track_insert_key(track_index, 0.0, Quaternion(Vector3(0, 1, 2)));
- animation->rotation_track_insert_key(track_index, 0.5, Quaternion(Vector3(3.5, 4, 5)));
+ animation->rotation_track_insert_key(track_index, 0.0, Quaternion::from_euler(Vector3(0, 1, 2)));
+ animation->rotation_track_insert_key(track_index, 0.5, Quaternion::from_euler(Vector3(3.5, 4, 5)));
CHECK(animation->get_track_count() == 1);
CHECK(!animation->track_is_compressed(0));
- CHECK(Quaternion(animation->track_get_key_value(0, 0)).is_equal_approx(Quaternion(Vector3(0, 1, 2))));
- CHECK(Quaternion(animation->track_get_key_value(0, 1)).is_equal_approx(Quaternion(Vector3(3.5, 4, 5))));
+ CHECK(Quaternion(animation->track_get_key_value(0, 0)).is_equal_approx(Quaternion::from_euler(Vector3(0, 1, 2))));
+ CHECK(Quaternion(animation->track_get_key_value(0, 1)).is_equal_approx(Quaternion::from_euler(Vector3(3.5, 4, 5))));
Quaternion r_interpolation;
diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h
new file mode 100644
index 0000000000..fc23adcd06
--- /dev/null
+++ b/tests/scene/test_arraymesh.h
@@ -0,0 +1,321 @@
+/*************************************************************************/
+/* test_arraymesh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_ARRAYMESH_H
+#define TEST_ARRAYMESH_H
+
+#include "scene/resources/mesh.h"
+#include "scene/resources/primitive_meshes.h"
+
+#include "tests/test_macros.h"
+
+namespace TestArrayMesh {
+
+TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ StringName name_a{ "ShapeA" };
+ StringName name_b{ "ShapeB" };
+
+ SUBCASE("Adding a blend shape to the mesh before a surface is added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+
+ CHECK(mesh->get_blend_shape_name(0) == name_a);
+ CHECK(mesh->get_blend_shape_name(1) == name_b);
+ }
+
+ SUBCASE("Add same blend shape multiple times appends name with number.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+
+ CHECK(mesh->get_blend_shape_name(0) == "ShapeA");
+ bool all_different = (static_cast<String>(mesh->get_blend_shape_name(0)) != static_cast<String>(mesh->get_blend_shape_name(1))) &&
+ (static_cast<String>(mesh->get_blend_shape_name(1)) != static_cast<String>(mesh->get_blend_shape_name(2))) &&
+ (static_cast<String>(mesh->get_blend_shape_name(0)) != static_cast<String>(mesh->get_blend_shape_name(2)));
+ bool all_have_name = static_cast<String>(mesh->get_blend_shape_name(1)).contains("ShapeA") &&
+ static_cast<String>(mesh->get_blend_shape_name(2)).contains("ShapeA");
+ CHECK((all_different && all_have_name));
+ }
+
+ SUBCASE("ArrayMesh keeps correct count of number of blend shapes") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ mesh->add_blend_shape(name_b);
+ mesh->add_blend_shape(name_b);
+
+ REQUIRE(mesh->get_blend_shape_count() == 5);
+ }
+
+ SUBCASE("Adding blend shape after surface is added causes error") {
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ mesh->add_blend_shape(name_a);
+ CHECK(mesh->get_blend_shape_count() == 0);
+ }
+
+ SUBCASE("Change blend shape name after adding.") {
+ mesh->add_blend_shape(name_a);
+ mesh->set_blend_shape_name(0, name_b);
+
+ CHECK(mesh->get_blend_shape_name(0) == name_b);
+ }
+
+ SUBCASE("Change blend shape name to the name of one already there, should append number to end") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ mesh->set_blend_shape_name(0, name_b);
+
+ String name_string = mesh->get_blend_shape_name(0);
+ CHECK(name_string.contains("ShapeB"));
+ CHECK(name_string.length() > static_cast<String>(name_b).size());
+ }
+
+ SUBCASE("Clear all blend shapes before surface has been added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ CHECK(mesh->get_blend_shape_count() == 2);
+
+ mesh->clear_blend_shapes();
+ CHECK(mesh->get_blend_shape_count() == 0);
+ }
+
+ SUBCASE("Can't clear blend shapes after surface had been added.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ mesh->clear_blend_shapes();
+ CHECK(mesh->get_blend_shape_count() == 2);
+ }
+
+ SUBCASE("Set the blend shape mode of ArrayMesh and underlying mesh RID.") {
+ mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_RELATIVE);
+ CHECK(mesh->get_blend_shape_mode() == Mesh::BLEND_SHAPE_MODE_RELATIVE);
+ }
+}
+
+TEST_CASE("[SceneTree][ArrayMesh] Surface meta data tests.") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ Ref<BoxMesh> box = memnew(BoxMesh);
+ Array box_array{};
+ box_array.resize(Mesh::ARRAY_MAX);
+ box->create_mesh_array(box_array, Vector3(2.f, 1.2f, 1.6f));
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+
+ SUBCASE("Add 2 surfaces and count the number of surfaces in the mesh.") {
+ REQUIRE(mesh->get_surface_count() == 2);
+ }
+
+ SUBCASE("Get the surface array from mesh.") {
+ REQUIRE(mesh->surface_get_arrays(0)[0] == cylinder_array[0]);
+ REQUIRE(mesh->surface_get_arrays(1)[0] == box_array[0]);
+ }
+
+ SUBCASE("Get the array length of a particular surface.") {
+ CHECK(mesh->surface_get_array_len(0) == static_cast<Vector<Vector3>>(cylinder_array[RenderingServer::ARRAY_VERTEX]).size());
+ CHECK(mesh->surface_get_array_len(1) == static_cast<Vector<Vector3>>(box_array[RenderingServer::ARRAY_VERTEX]).size());
+ }
+
+ SUBCASE("Get the index array length of a particular surface.") {
+ CHECK(mesh->surface_get_array_index_len(0) == static_cast<Vector<Vector3>>(cylinder_array[RenderingServer::ARRAY_INDEX]).size());
+ CHECK(mesh->surface_get_array_index_len(1) == static_cast<Vector<Vector3>>(box_array[RenderingServer::ARRAY_INDEX]).size());
+ }
+
+ SUBCASE("Get correct primitive type") {
+ CHECK(mesh->surface_get_primitive_type(0) == Mesh::PRIMITIVE_TRIANGLES);
+ CHECK(mesh->surface_get_primitive_type(1) == Mesh::PRIMITIVE_TRIANGLES);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, box_array);
+ CHECK(mesh->surface_get_primitive_type(2) == Mesh::PRIMITIVE_TRIANGLE_STRIP);
+ }
+
+ SUBCASE("Returns correct format for the mesh") {
+ auto format = RS::ARRAY_FORMAT_BLEND_SHAPE_MASK | RS::ARRAY_FORMAT_TEX_UV | RS::ARRAY_FORMAT_INDEX;
+ CHECK((mesh->surface_get_format(0) & format) != 0);
+ CHECK((mesh->surface_get_format(1) & format) != 0);
+ }
+
+ SUBCASE("Set a surface name and retrieve it by name.") {
+ mesh->surface_set_name(0, "surf1");
+ CHECK(mesh->surface_find_by_name("surf1") == 0);
+ CHECK(mesh->surface_get_name(0) == "surf1");
+ }
+
+ SUBCASE("Set material to two different surfaces.") {
+ Ref<Material> mat = memnew(Material);
+ mesh->surface_set_material(0, mat);
+ CHECK(mesh->surface_get_material(0) == mat);
+ mesh->surface_set_material(1, mat);
+ CHECK(mesh->surface_get_material(1) == mat);
+ }
+
+ SUBCASE("Set same material multiple times doesn't change material of surface.") {
+ Ref<Material> mat = memnew(Material);
+ mesh->surface_set_material(0, mat);
+ mesh->surface_set_material(0, mat);
+ mesh->surface_set_material(0, mat);
+ CHECK(mesh->surface_get_material(0) == mat);
+ }
+
+ SUBCASE("Set material of surface then change to different material.") {
+ Ref<Material> mat1 = memnew(Material);
+ Ref<Material> mat2 = memnew(Material);
+ mesh->surface_set_material(1, mat1);
+ CHECK(mesh->surface_get_material(1) == mat1);
+ mesh->surface_set_material(1, mat2);
+ CHECK(mesh->surface_get_material(1) == mat2);
+ }
+
+ SUBCASE("Get the LOD of the mesh.") {
+ Dictionary lod{};
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, TypedArray<Array>{}, lod);
+ CHECK(mesh->surface_get_lods(2) == lod);
+ }
+
+ SUBCASE("Get the blend shape arrays from the mesh.") {
+ TypedArray<Array> blend{};
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend);
+ CHECK(mesh->surface_get_blend_shape_arrays(2) == blend);
+ }
+}
+
+TEST_CASE("[SceneTree][ArrayMesh] Get/Set mesh metadata and actions") {
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ cylinder_array.resize(Mesh::ARRAY_MAX);
+ cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+
+ Ref<BoxMesh> box = memnew(BoxMesh);
+ Array box_array{};
+ box_array.resize(Mesh::ARRAY_MAX);
+ box->create_mesh_array(box_array, Vector3(2.f, 1.2f, 1.6f));
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+
+ SUBCASE("Set the shadow mesh.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the shadow mesh multiple times.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the same shadow mesh on multiple meshes.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ Ref<ArrayMesh> mesh2 = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ mesh2->set_shadow_mesh(shadow);
+
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ CHECK(mesh2->get_shadow_mesh() == shadow);
+ }
+
+ SUBCASE("Set the shadow mesh and then change it.") {
+ Ref<ArrayMesh> shadow = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow);
+ CHECK(mesh->get_shadow_mesh() == shadow);
+ Ref<ArrayMesh> shadow2 = memnew(ArrayMesh);
+ mesh->set_shadow_mesh(shadow2);
+ CHECK(mesh->get_shadow_mesh() == shadow2);
+ }
+
+ SUBCASE("Set custom AABB.") {
+ AABB bound{};
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ }
+
+ SUBCASE("Set custom AABB multiple times.") {
+ AABB bound{};
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ }
+
+ SUBCASE("Set custom AABB then change to another AABB.") {
+ AABB bound{};
+ AABB bound2{};
+ mesh->set_custom_aabb(bound);
+ CHECK(mesh->get_custom_aabb() == bound);
+ mesh->set_custom_aabb(bound2);
+ CHECK(mesh->get_custom_aabb() == bound2);
+ }
+
+ SUBCASE("Clear all surfaces should leave zero count.") {
+ mesh->clear_surfaces();
+ CHECK(mesh->get_surface_count() == 0);
+ }
+
+ SUBCASE("Able to get correct mesh RID.") {
+ RID rid = mesh->get_rid();
+ CHECK(RS::get_singleton()->mesh_get_surface_count(rid) == 2);
+ }
+
+ SUBCASE("Create surface from raw SurfaceData data.") {
+ RID mesh_rid = mesh->get_rid();
+ RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh_rid, 0);
+ Ref<ArrayMesh> mesh2 = memnew(ArrayMesh);
+ mesh2->add_surface(surface_data.format, Mesh::PRIMITIVE_TRIANGLES, surface_data.vertex_data, surface_data.attribute_data,
+ surface_data.skin_data, surface_data.vertex_count, surface_data.index_data, surface_data.index_count, surface_data.aabb);
+ CHECK(mesh2->get_surface_count() == 1);
+ CHECK(mesh2->surface_get_primitive_type(0) == Mesh::PRIMITIVE_TRIANGLES);
+ CHECK((mesh2->surface_get_format(0) & surface_data.format) != 0);
+ CHECK(mesh2->get_aabb().is_equal_approx(surface_data.aabb));
+ }
+}
+
+} // namespace TestArrayMesh
+
+#endif // TEST_ARRAYMESH_H
diff --git a/tests/scene/test_bit_map.h b/tests/scene/test_bit_map.h
index 635449181e..a102f40725 100644
--- a/tests/scene/test_bit_map.h
+++ b/tests/scene/test_bit_map.h
@@ -76,15 +76,11 @@ TEST_CASE("[BitMap] Create bit map from image alpha") {
bit_map.create_from_image_alpha(empty_img);
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because bitmap creation from an empty image should fail.");
- Ref<Image> wrong_format_img;
- wrong_format_img.instantiate();
- wrong_format_img->create(3, 3, false, Image::Format::FORMAT_DXT1);
+ Ref<Image> wrong_format_img = Image::create_empty(3, 3, false, Image::Format::FORMAT_DXT1);
bit_map.create_from_image_alpha(wrong_format_img);
CHECK_MESSAGE(bit_map.get_size() == Size2i(256, 256), "Bitmap should have its old values because converting from a compressed image should fail.");
- Ref<Image> img;
- img.instantiate();
- img->create(3, 3, false, Image::Format::FORMAT_RGBA8);
+ Ref<Image> img = Image::create_empty(3, 3, false, Image::Format::FORMAT_RGBA8);
img->set_pixel(0, 0, Color(0, 0, 0, 0));
img->set_pixel(0, 1, Color(0, 0, 0, 0.09f));
img->set_pixel(0, 2, Color(0, 0, 0, 0.25f));
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 225316b293..652cbed6e8 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -93,10 +93,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "test text");
- CHECK(text_edit->get_caret_column() == 9);
+ CHECK(text_edit->get_caret_column() == 0);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_set");
text_edit->redo();
@@ -104,18 +104,18 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_text() == "");
CHECK(text_edit->get_caret_column() == 0);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_set");
// Cannot undo when not-editable but should still clear.
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "test text");
- CHECK(text_edit->get_caret_column() == 9);
+ CHECK(text_edit->get_caret_column() == 0);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_set");
// Clear.
@@ -131,8 +131,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_text() == "");
CHECK(text_edit->get_caret_column() == 0);
SIGNAL_CHECK("text_set", empty_signal_args);
- SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_clear_args);
+ SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
text_edit->set_editable(true);
@@ -252,6 +252,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_line(0) == "te");
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "te");
+ CHECK(text_edit->get_caret_column() == 2);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -263,6 +264,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_line(0) == "test text");
CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text() == "test");
+ CHECK(text_edit->get_caret_column() == 4);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -271,7 +274,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->redo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_line(0) == "te");
- CHECK_FALSE(text_edit->has_selection()); // Currently not handled.
+ CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_caret_column() == 2);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -425,7 +429,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "testing\nswap");
- CHECK_FALSE(text_edit->has_selection()); // Not currently handled.
+ CHECK(text_edit->has_selection());
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -436,7 +440,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->redo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "new\ntesting\nswap");
- CHECK_FALSE(text_edit->has_selection()); // Not currently handled.
+ CHECK(text_edit->has_selection());
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -448,7 +452,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->has_selection());
CHECK(text_edit->get_selection_from_line() == 0);
CHECK(text_edit->get_selection_to_line() == 2);
- SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK_FALSE("caret_changed");
((Array)lines_edited_args[0])[0] = 2;
((Array)lines_edited_args[0])[1] = 3;
@@ -533,7 +537,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "temidsting\nswap");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 10);
+ CHECK(text_edit->get_caret_column() == 5);
CHECK(text_edit->has_selection());
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
@@ -633,17 +637,42 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] select word under caret") {
- text_edit->set_text("test test");
+ text_edit->set_text("\ntest test\ntest test");
+
text_edit->set_caret_column(0);
+ text_edit->set_caret_line(1);
+
+ text_edit->add_caret(2, 0);
+ text_edit->add_caret(2, 2);
+ CHECK(text_edit->get_caret_count() == 3);
+
+ MessageQueue::get_singleton()->flush();
+
+ SIGNAL_DISCARD("text_set");
+ SIGNAL_DISCARD("text_changed");
+ SIGNAL_DISCARD("lines_edited_from");
+ SIGNAL_DISCARD("caret_changed");
+
text_edit->select_word_under_caret();
- CHECK(text_edit->get_selected_text() == "test");
- CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selection_from_line() == 0);
- CHECK(text_edit->get_selection_from_column() == 0);
- CHECK(text_edit->get_selection_to_line() == 0);
- CHECK(text_edit->get_selection_to_column() == 4);
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_selection_from_line(0) == 1);
+ CHECK(text_edit->get_selection_from_column(0) == 0);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selection_from_line(1) == 2);
+ CHECK(text_edit->get_selection_from_column(1) == 0);
+ CHECK(text_edit->get_selection_to_line(1) == 2);
+ CHECK(text_edit->get_selection_to_column(1) == 4);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+
+ CHECK(text_edit->get_caret_count() == 2);
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
@@ -652,27 +681,44 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_select_word_under_caret");
CHECK(text_edit->get_viewport()->is_input_handled());
MessageQueue::get_singleton()->flush();
- CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selected_text() == "test");
- CHECK(text_edit->get_selection_from_line() == 0);
- CHECK(text_edit->get_selection_from_column() == 0);
- CHECK(text_edit->get_selection_to_line() == 0);
- CHECK(text_edit->get_selection_to_column() == 4);
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->get_selection_from_line(0) == 1);
+ CHECK(text_edit->get_selection_from_column(0) == 0);
+ CHECK(text_edit->get_selection_to_line(0) == 1);
+ CHECK(text_edit->get_selection_to_column(0) == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selection_from_line(1) == 2);
+ CHECK(text_edit->get_selection_from_column(1) == 0);
+ CHECK(text_edit->get_selection_to_line(1) == 2);
+ CHECK(text_edit->get_selection_to_column(1) == 4);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+
+ CHECK(text_edit->get_selected_text() == "test\ntest");
SIGNAL_CHECK("caret_changed", empty_signal_args);
text_edit->set_selecting_enabled(false);
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 4);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 4);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
SIGNAL_CHECK_FALSE("caret_changed");
text_edit->set_selecting_enabled(true);
- text_edit->set_caret_line(0);
- text_edit->set_caret_column(5);
+ text_edit->set_caret_line(1, false, true, 0, 0);
+ text_edit->set_caret_column(5, false, 0);
+
+ text_edit->set_caret_line(2, false, true, 0, 1);
+ text_edit->set_caret_column(5, false, 1);
+
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
@@ -680,11 +726,53 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->select_word_under_caret();
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_selected_text() == "");
- CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 5);
+ CHECK(text_edit->get_caret_line(0) == 1);
+ CHECK(text_edit->get_caret_column(0) == 5);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 5);
SIGNAL_CHECK_FALSE("caret_changed");
}
+ SUBCASE("[TextEdit] add selection for next occurrence") {
+ text_edit->set_text("\ntest other_test\nrandom test\nword test word");
+ text_edit->set_caret_column(0);
+ text_edit->set_caret_line(1);
+
+ text_edit->select_word_under_caret();
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "test");
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->get_selection_from_line(1) == 1);
+ CHECK(text_edit->get_selection_from_column(1) == 13);
+ CHECK(text_edit->get_selection_to_line(1) == 1);
+ CHECK(text_edit->get_selection_to_column(1) == 17);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 17);
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_selected_text(2) == "test");
+ CHECK(text_edit->get_selection_from_line(2) == 2);
+ CHECK(text_edit->get_selection_from_column(2) == 9);
+ CHECK(text_edit->get_selection_to_line(2) == 2);
+ CHECK(text_edit->get_selection_to_column(2) == 13);
+ CHECK(text_edit->get_caret_line(2) == 2);
+ CHECK(text_edit->get_caret_column(2) == 13);
+
+ text_edit->add_selection_for_next_occurrence();
+ CHECK(text_edit->get_caret_count() == 4);
+ CHECK(text_edit->get_selected_text(3) == "test");
+ CHECK(text_edit->get_selection_from_line(3) == 3);
+ CHECK(text_edit->get_selection_from_column(3) == 5);
+ CHECK(text_edit->get_selection_to_line(3) == 3);
+ CHECK(text_edit->get_selection_to_column(3) == 9);
+ CHECK(text_edit->get_caret_line(3) == 3);
+ CHECK(text_edit->get_caret_column(3) == 9);
+ }
+
SUBCASE("[TextEdit] deselect on focus loss") {
text_edit->set_text("test");
@@ -950,11 +1038,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->delete_selection();
CHECK(text_edit->get_text() == "this is some text\nfor selection");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 8);
text_edit->select(0, 8, 0, 4);
CHECK(text_edit->has_selection());
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
CHECK(text_edit->get_text() == "thissome text\nfor selection");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
text_edit->undo();
CHECK(text_edit->has_selection());
@@ -966,7 +1058,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 8);
+ CHECK(text_edit->get_caret_column() == 4);
text_edit->undo();
CHECK(text_edit->has_selection());
@@ -991,7 +1083,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK_FALSE(text_edit->has_selection());
CHECK(text_edit->get_text() == "thissome text\nfor selection");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == 8);
+ CHECK(text_edit->get_caret_column() == 4);
text_edit->undo();
CHECK(text_edit->has_selection());
@@ -1176,8 +1268,8 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->undo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "this is\nsome\n");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 6);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1187,9 +1279,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->redo();
MessageQueue::get_singleton()->flush();
CHECK(text_edit->get_text() == "some\n");
- CHECK(text_edit->get_caret_line() == 1);
- CHECK(text_edit->get_caret_column() == 0);
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK(text_edit->get_caret_line() == 0);
+ CHECK(text_edit->get_caret_column() == 4);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1259,9 +1351,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
lines_edited_args.push_back(args1);
SUBCASE("[TextEdit] ui_text_newline_above") {
- text_edit->set_text("this is some test text.");
+ text_edit->set_text("this is some test text.\nthis is some test text.");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 0, 1, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1269,50 +1366,78 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- ((Array)lines_edited_args[0])[1] = 1;
+ // For the second caret.
+ Array args2;
+ args2.push_back(0);
+ args2.push_back(1);
+ lines_edited_args.push_front(args2);
+
+ ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION(text_edit, "ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
+ CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->set_caret_line(1);
text_edit->set_caret_column(4);
- text_edit->select(0, 0, 0, 4);
+
+ text_edit->set_caret_line(3, false, true, 0, 1);
+ text_edit->set_caret_column(4, false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("caret_changed");
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
+ CHECK(text_edit->get_text() == "\nthis is some test text.\n\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 4);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 4);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ ((Array)lines_edited_args[0])[0] = 2;
+ ((Array)lines_edited_args[0])[1] = 3;
+
SEND_GUI_ACTION(text_edit, "ui_text_newline_above");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n\nthis is some test text.");
+ CHECK(text_edit->get_text() == "\n\nthis is some test text.\n\n\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 4);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SUBCASE("[TextEdit] ui_text_newline_blank") {
- text_edit->set_text("this is some test text.");
+ text_edit->set_text("this is some test text.\nthis is some test text.");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 0, 1, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1320,13 +1445,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- ((Array)lines_edited_args[0])[1] = 1;
+ // For the second caret.
+ Array args2;
+ args2.push_back(1);
+ args2.push_back(2);
+ lines_edited_args.push_front(args2);
+
+ ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION(text_edit, "ui_text_newline_blank");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text.\n");
+ CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1334,10 +1469,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_newline_blank");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text.\n");
+ CHECK(text_edit->get_text() == "this is some test text.\n\nthis is some test text.\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -1345,9 +1484,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] ui_text_newline") {
- text_edit->set_text("this is some test text.");
+ text_edit->set_text("this is some test text.\nthis is some test text.");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 0, 1, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1355,14 +1499,27 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- lines_edited_args.push_back(lines_edited_args[0].duplicate());
- ((Array)lines_edited_args[1])[1] = 1;
+ // For the second caret.
+ Array args2;
+ args2.push_back(1);
+ args2.push_back(1);
+ lines_edited_args.push_front(args2);
+ lines_edited_args.push_front(args2.duplicate());
+ ((Array)lines_edited_args[1])[1] = 2;
+
+ lines_edited_args.push_back(lines_edited_args[2].duplicate());
+ ((Array)lines_edited_args[3])[1] = 1;
+
SEND_GUI_ACTION(text_edit, "ui_text_newline");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.");
+ CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1370,10 +1527,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_newline");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.");
+ CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -1381,10 +1542,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] ui_text_backspace_all_to_left") {
- text_edit->set_text("\nthis is some test text.");
+ text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
text_edit->select(1, 0, 1, 4);
text_edit->set_caret_line(1);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(3, 4);
+ text_edit->select(3, 0, 3, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL);
@@ -1395,34 +1561,50 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(3);
+ args2.push_back(3);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal backspace.
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 1;
+ ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.");
+ CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[1] = 0;
+ ((Array)lines_edited_args[0])[1] = 2;
+ ((Array)lines_edited_args[1])[1] = 0;
// Start of line should also be a normal backspace.
SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1433,23 +1615,33 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- ((Array)lines_edited_args[0])[0] = 0;
+ ((Array)lines_edited_args[0])[0] = 1;
+ ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 0;
SEND_GUI_ACTION(text_edit, "ui_text_backspace_all_to_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "");
+ CHECK(text_edit->get_text() == "\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1458,10 +1650,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
}
SUBCASE("[TextEdit] ui_text_backspace_word") {
- text_edit->set_text("\nthis is some test text.");
+ text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
text_edit->select(1, 0, 1, 4);
text_edit->set_caret_line(1);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(3, 4);
+ text_edit->select(3, 0, 3, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1469,30 +1665,45 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(3);
+ args2.push_back(3);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal backspace.
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 1;
+ ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION(text_edit, "ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.");
+ CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->end_complex_operation();
- ((Array)lines_edited_args[0])[1] = 0;
+ ((Array)lines_edited_args[0])[1] = 2;
+ ((Array)lines_edited_args[1])[1] = 0;
// Start of line should also be a normal backspace.
SEND_GUI_ACTION(text_edit, "ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1500,16 +1711,21 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1517,24 +1733,35 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- ((Array)lines_edited_args[0])[0] = 0;
+ ((Array)lines_edited_args[0])[0] = 1;
+ ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 0;
SEND_GUI_ACTION(text_edit, "ui_text_backspace_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test ");
+ CHECK(text_edit->get_text() == " is some test \n is some test ");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 14);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 14);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SUBCASE("[TextEdit] ui_text_backspace") {
- text_edit->set_text("\nthis is some test text.");
+ text_edit->set_text("\nthis is some test text.\n\nthis is some test text.");
text_edit->select(1, 0, 1, 4);
text_edit->set_caret_line(1);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(3, 4);
+ text_edit->select(3, 0, 3, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1542,34 +1769,50 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(3);
+ args2.push_back(3);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal backspace.
- ((Array)lines_edited_args[0])[0] = 1;
- ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 1;
+ ((Array)lines_edited_args[1])[1] = 1;
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n is some test text.");
+ CHECK(text_edit->get_text() == "\n is some test text.\n\n is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[1] = 0;
+ ((Array)lines_edited_args[0])[1] = 2;
+ ((Array)lines_edited_args[1])[1] = 0;
// Start of line should also be a normal backspace.
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1580,23 +1823,33 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- ((Array)lines_edited_args[0])[0] = 0;
+ ((Array)lines_edited_args[0])[0] = 1;
+ ((Array)lines_edited_args[0])[1] = 1;
+ ((Array)lines_edited_args[1])[0] = 0;
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text");
+ CHECK(text_edit->get_text() == " is some test text\n is some test text");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 18);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 18);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1605,6 +1858,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->select(0, 18, 0, 0);
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
+
+ text_edit->select(1, 18, 1, 0, 1);
+ text_edit->set_caret_line(1, false, true, 0, 1);
+ text_edit->set_caret_column(0, false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1612,12 +1869,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
- ((Array)lines_edited_args[0])[0] = 0;
-
SEND_GUI_ACTION(text_edit, "ui_text_backspace");
- CHECK(text_edit->get_text() == "");
+ CHECK(text_edit->get_text() == "\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1627,10 +1884,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
Ref<InputEvent> tmpevent = InputEventKey::create_reference(Key::BACKSPACE | KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL);
InputMap::get_singleton()->action_add_event("ui_text_delete_all_to_right", tmpevent);
- text_edit->set_text("this is some test text.\n");
+ text_edit->set_text("this is some test text.\nthis is some test text.\n");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_line(0);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 0, 1, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1638,19 +1900,30 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(1);
+ args2.push_back(1);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal delete.
SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
// End of line should not do anything.
text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1660,15 +1933,20 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1679,10 +1957,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " is some test text.\n");
+ CHECK(text_edit->get_text() == " is some test text.\n is some test text.\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -1690,10 +1972,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete_all_to_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\n");
+ CHECK(text_edit->get_text() == "\n\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1705,10 +1991,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_caret_mid_grapheme_enabled(true);
CHECK(text_edit->is_caret_mid_grapheme_enabled());
- text_edit->set_text("this ffi some test text.\n");
+ text_edit->set_text("this ffi some test text.\n\nthis ffi some test text.\n");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_line(0);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(2, 4);
+ text_edit->select(2, 0, 2, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1716,20 +2007,32 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(2);
+ args2.push_back(2);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal delete.
SEND_GUI_ACTION(text_edit, "ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n");
+ CHECK(text_edit->get_text() == " ffi some test text.\n\n ffi some test text.\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
// With selection should be a normal delete.
- ((Array)lines_edited_args[0])[0] = 1;
+ ((Array)lines_edited_args[0])[0] = 3;
+ ((Array)lines_edited_args[1])[0] = 1;
text_edit->set_caret_column(text_edit->get_line(0).length());
+ text_edit->set_caret_column(text_edit->get_line(2).length(), false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1739,16 +2042,23 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.");
+ CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
CHECK_FALSE(text_edit->has_selection());
- SIGNAL_CHECK_FALSE("caret_changed");
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK_FALSE(text_edit->has_selection(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[0] = 0;
+ ((Array)lines_edited_args[1])[0] = 0;
+ ((Array)lines_edited_args[0])[0] = 1;
+ ((Array)lines_edited_args[0])[1] = 1;
text_edit->set_caret_column(0);
+ text_edit->set_caret_column(0, false, 1);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1759,10 +2069,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.");
+ CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -1770,10 +2084,14 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete_word");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " some test text.");
+ CHECK(text_edit->get_text() == " some test text.\n some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -1783,10 +2101,15 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_caret_mid_grapheme_enabled(true);
CHECK(text_edit->is_caret_mid_grapheme_enabled());
- text_edit->set_text("this ffi some test text.\n");
+ text_edit->set_text("this ffi some test text.\nthis ffi some test text.");
text_edit->select(0, 0, 0, 4);
text_edit->set_caret_line(0);
text_edit->set_caret_column(4);
+
+ text_edit->add_caret(1, 4);
+ text_edit->select(1, 0, 1, 4, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1794,19 +2117,31 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(1);
+ args2.push_back(1);
+ lines_edited_args.push_front(args2);
+
// With selection should be a normal delete.
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.\n");
+ CHECK(text_edit->get_text() == " ffi some test text.\n ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
// With selection should be a normal delete.
+ lines_edited_args.remove_at(0);
((Array)lines_edited_args[0])[0] = 1;
+ text_edit->set_caret_column(text_edit->get_line(1).length(), false, 1);
text_edit->set_caret_column(text_edit->get_line(0).length());
MessageQueue::get_singleton()->flush();
@@ -1817,16 +2152,25 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.");
+ CHECK(text_edit->get_text() == " ffi some test text. ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
- CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK(text_edit->get_caret_column() == 20);
+ CHECK_FALSE(text_edit->has_selection(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
- ((Array)lines_edited_args[0])[0] = 0;
+ // Caret should be removed due to column preservation.
+ CHECK(text_edit->get_caret_count() == 1);
+
+ // Lets add it back.
text_edit->set_caret_column(0);
+ text_edit->add_caret(0, 20);
+
+ ((Array)lines_edited_args[0])[0] = 0;
+ lines_edited_args.push_back(args2);
+ ((Array)lines_edited_args[1])[0] = 0;
+ ((Array)lines_edited_args[1])[1] = 0;
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1837,43 +2181,59 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " ffi some test text.");
+ CHECK(text_edit->get_text() == " ffi some test text. ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 20);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
+ text_edit->start_action(TextEdit::EditAction::ACTION_NONE);
+
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "ffi some test text.");
+ CHECK(text_edit->get_text() == "ffi some test text.ffi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 19);
+ CHECK_FALSE(text_edit->has_selection(0));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
+ text_edit->start_action(TextEdit::EditAction::ACTION_NONE);
+
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "fi some test text.");
+ CHECK(text_edit->get_text() == "fi some test text.fi some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 18);
+ CHECK_FALSE(text_edit->has_selection(1));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->set_caret_mid_grapheme_enabled(false);
CHECK_FALSE(text_edit->is_caret_mid_grapheme_enabled());
+ text_edit->start_action(TextEdit::EditAction::ACTION_NONE);
+
text_edit->undo();
- text_edit->set_caret_line(0);
- text_edit->set_caret_column(0);
MessageQueue::get_singleton()->flush();
- CHECK(text_edit->get_text() == "ffi some test text.");
+ CHECK(text_edit->get_text() == "ffi some test text.ffi some test text.");
SIGNAL_DISCARD("text_set");
SIGNAL_DISCARD("text_changed");
@@ -1882,19 +2242,26 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_ACTION(text_edit, "ui_text_delete");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == " some test text.");
+ CHECK(text_edit->get_text() == " some test text. some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
- SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 16);
+ CHECK_FALSE(text_edit->has_selection(1));
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SUBCASE("[TextEdit] ui_text_caret_word_left") {
- text_edit->set_text("\nthis is some test text.");
+ text_edit->set_text("\nthis is some test text.\nthis is some test text.");
text_edit->set_caret_line(1);
text_edit->set_caret_column(7);
+
+ text_edit->add_caret(2, 7);
+ CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1902,47 +2269,67 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Shift should select.
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
- CHECK(text_edit->get_selected_text() == "is");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "is");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ CHECK(text_edit->get_selected_text(1) == "is");
+ CHECK(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Should still move caret with selection.
SEND_GUI_ACTION(text_edit, "ui_text_caret_word_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal word left.
SEND_GUI_ACTION(text_edit, "ui_text_caret_word_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 23);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_caret_left") {
- text_edit->set_text("\nthis is some test text.");
+ text_edit->set_text("\nthis is some test text.\nthis is some test text.");
text_edit->set_caret_line(1);
text_edit->set_caret_column(7);
text_edit->select(1, 2, 1, 7);
+
+ text_edit->add_caret(2, 7);
+ text_edit->select(2, 2, 2, 7, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -1950,62 +2337,91 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Normal left shoud deselect and place at selection start.
SEND_GUI_ACTION(text_edit, "ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
+
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 2);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK_FALSE(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // With shift should select.
SEND_GUI_KEY_EVENT(text_edit, Key::LEFT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 1);
- CHECK(text_edit->get_selected_text() == "h");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "h");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ CHECK(text_edit->get_selected_text(1) == "h");
+ CHECK(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // All ready at select left, should only deselect.
SEND_GUI_ACTION(text_edit, "ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 1);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 1);
+ CHECK_FALSE(text_edit->has_selection(1));
+
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal left.
SEND_GUI_ACTION(text_edit, "ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 0);
CHECK_FALSE(text_edit->has_selection());
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Left at col 0 should go up a line.
SEND_GUI_ACTION(text_edit, "ui_text_caret_left");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "\nthis is some test text.");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 23);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_caret_word_right") {
- text_edit->set_text("this is some test text\n");
+ text_edit->set_text("this is some test text\n\nthis is some test text\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(13);
+
+ text_edit->add_caret(2, 13);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -2013,47 +2429,67 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Shift should select.
#ifdef MACOS_ENABLED
SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::ALT | KeyModifierMask::SHIFT);
#else
SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT);
#endif
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 17);
- CHECK(text_edit->get_selected_text() == "test");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "test");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 17);
+ CHECK(text_edit->get_selected_text(1) == "test");
+ CHECK(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Should still move caret with selection.
SEND_GUI_ACTION(text_edit, "ui_text_caret_word_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 22);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 22);
+ CHECK_FALSE(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal word right.
SEND_GUI_ACTION(text_edit, "ui_text_caret_word_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] ui_text_caret_right") {
- text_edit->set_text("this is some test text\n");
+ text_edit->set_text("this is some test text\n\nthis is some test text\n");
text_edit->set_caret_line(0);
text_edit->set_caret_column(16);
text_edit->select(0, 16, 0, 20);
+
+ text_edit->add_caret(2, 16);
+ text_edit->select(2, 16, 2, 20, 1);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
SIGNAL_DISCARD("text_set");
@@ -2061,53 +2497,76 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Normal right shoud deselect and place at selection start.
SEND_GUI_ACTION(text_edit, "ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 20);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 20);
+ CHECK_FALSE(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // With shift should select.
SEND_GUI_KEY_EVENT(text_edit, Key::RIGHT | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 21);
- CHECK(text_edit->get_selected_text() == "x");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "x");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 21);
+ CHECK(text_edit->get_selected_text(1) == "x");
+ CHECK(text_edit->has_selection(1));
+
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // All ready at select right, should only deselect.
SEND_GUI_ACTION(text_edit, "ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 21);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 21);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal right.
SEND_GUI_ACTION(text_edit, "ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 22);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 22);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Right at end col should go down a line.
SEND_GUI_ACTION(text_edit, "ui_text_caret_right");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some test text\n");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 3);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2117,9 +2576,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
text_edit->set_size(Size2(110, 100));
- text_edit->set_text("this is some\nother test\nlines\ngo here");
- text_edit->set_caret_line(4);
+ text_edit->set_text("this is some\nother test\nlines\ngo here\nthis is some\nother test\nlines\ngo here");
+ text_edit->set_caret_line(3);
text_edit->set_caret_column(7);
+
+ text_edit->add_caret(7, 7);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(0));
@@ -2128,44 +2591,61 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Select + up should select everything to the left on that line.
SEND_GUI_KEY_EVENT(text_edit, Key::UP | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here");
CHECK(text_edit->get_caret_line() == 2);
CHECK(text_edit->get_caret_column() == 5);
- CHECK(text_edit->get_selected_text() == "\ngo here");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "\ngo here");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 6);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ CHECK(text_edit->get_selected_text(1) == "\ngo here");
+ CHECK(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Should deselect and move up.
SEND_GUI_ACTION(text_edit, "ui_text_caret_up");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 8);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 5);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal up over wrapped line.
SEND_GUI_ACTION(text_edit, "ui_text_caret_up");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 12);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 4);
+ CHECK(text_edit->get_caret_column(1) == 12);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_caret_column(12, false);
+ // Normal up over wrapped line to line 0.
SEND_GUI_ACTION(text_edit, "ui_text_caret_up");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "this is some\nother test\nlines\ngo here");
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 7);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 4);
+ CHECK(text_edit->get_caret_column(1) == 7);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2175,9 +2655,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
text_edit->set_size(Size2(110, 100));
- text_edit->set_text("go here\nlines\nother test\nthis is some");
+ text_edit->set_text("go here\nlines\nother test\nthis is some\ngo here\nlines\nother test\nthis is some");
text_edit->set_caret_line(0);
text_edit->set_caret_column(7);
+
+ text_edit->add_caret(4, 7);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(3));
@@ -2186,44 +2670,61 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // Select + down should select everything to the right on that line.
SEND_GUI_KEY_EVENT(text_edit, Key::DOWN | KeyModifierMask::SHIFT);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some");
CHECK(text_edit->get_caret_line() == 1);
CHECK(text_edit->get_caret_column() == 5);
- CHECK(text_edit->get_selected_text() == "\nlines");
- CHECK(text_edit->has_selection());
+ CHECK(text_edit->get_selected_text(0) == "\nlines");
+ CHECK(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 5);
+ CHECK(text_edit->get_caret_column(1) == 5);
+ CHECK(text_edit->get_selected_text(1) == "\nlines");
+ CHECK(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Should deselect and move down.
SEND_GUI_ACTION(text_edit, "ui_text_caret_down");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some");
CHECK(text_edit->get_caret_line() == 2);
CHECK(text_edit->get_caret_column() == 8);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 6);
+ CHECK(text_edit->get_caret_column(1) == 8);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ // Normal down over wrapped line.
SEND_GUI_ACTION(text_edit, "ui_text_caret_down");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some");
CHECK(text_edit->get_caret_line() == 3);
CHECK(text_edit->get_caret_column() == 7);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 7);
+ CHECK(text_edit->get_caret_column(1) == 7);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_caret_column(7, false);
+ // Normal down over wrapped line to last wrapped line.
SEND_GUI_ACTION(text_edit, "ui_text_caret_down");
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "go here\nlines\nother test\nthis is some");
CHECK(text_edit->get_caret_line() == 3);
CHECK(text_edit->get_caret_column() == 12);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 7);
+ CHECK(text_edit->get_caret_column(1) == 12);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2236,6 +2737,10 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_text("this is some\nother test\nlines\ngo here");
text_edit->set_caret_line(4);
text_edit->set_caret_column(7);
+
+ text_edit->add_caret(3, 2);
+ CHECK(text_edit->get_caret_count() == 2);
+
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(0));
@@ -2258,6 +2763,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ CHECK(text_edit->get_caret_count() == 1);
SEND_GUI_ACTION(text_edit, "ui_text_caret_document_start");
CHECK(text_edit->get_viewport()->is_input_handled());
@@ -2277,6 +2783,9 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_text("go here\nlines\nother test\nthis is some");
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
+
+ text_edit->add_caret(1, 0);
+ CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(3));
@@ -2299,6 +2808,7 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
+ CHECK(text_edit->get_caret_count() == 1);
SEND_GUI_ACTION(text_edit, "ui_text_caret_document_end");
CHECK(text_edit->get_viewport()->is_input_handled());
@@ -2315,9 +2825,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
text_edit->set_size(Size2(110, 100));
- text_edit->set_text(" this is some");
+ text_edit->set_text(" this is some\n this is some");
text_edit->set_caret_line(0);
text_edit->set_caret_column(text_edit->get_line(0).length());
+
+ text_edit->add_caret(1, text_edit->get_line(1).length());
+ CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(0));
@@ -2334,8 +2847,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 10);
- CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selected_text() == "some");
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == "some");
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 10);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == "some");
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2344,7 +2862,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 2);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2353,7 +2875,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 0);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 0);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2362,7 +2888,11 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 2);
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2372,9 +2902,12 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
text_edit->set_size(Size2(110, 100));
- text_edit->set_text(" this is some");
+ text_edit->set_text(" this is some\n this is some");
text_edit->set_caret_line(0);
text_edit->set_caret_column(0);
+
+ text_edit->add_caret(1, 0);
+ CHECK(text_edit->get_caret_count() == 2);
MessageQueue::get_singleton()->flush();
CHECK(text_edit->is_line_wrapped(0));
@@ -2391,8 +2924,13 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == 9);
- CHECK(text_edit->has_selection());
- CHECK(text_edit->get_selected_text() == " this is");
+ CHECK(text_edit->has_selection(0));
+ CHECK(text_edit->get_selected_text(0) == " this is");
+
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == 9);
+ CHECK(text_edit->has_selection(1));
+ CHECK(text_edit->get_selected_text(1) == " this is");
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
@@ -2401,13 +2939,24 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
CHECK(text_edit->get_viewport()->is_input_handled());
CHECK(text_edit->get_caret_line() == 0);
CHECK(text_edit->get_caret_column() == text_edit->get_line(0).length());
- CHECK_FALSE(text_edit->has_selection());
+ CHECK_FALSE(text_edit->has_selection(0));
+
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_caret_line(1) == 1);
+ CHECK(text_edit->get_caret_column(1) == text_edit->get_line(1).length());
+ CHECK_FALSE(text_edit->has_selection(1));
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
}
SUBCASE("[TextEdit] unicode") {
+ text_edit->set_text("\n");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+
+ text_edit->add_caret(1, 0);
+ CHECK(text_edit->get_caret_count() == 2);
text_edit->insert_text_at_caret("a");
MessageQueue::get_singleton()->flush();
@@ -2416,10 +2965,17 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SIGNAL_DISCARD("lines_edited_from");
SIGNAL_DISCARD("caret_changed");
+ // For the second caret.
+ Array args2;
+ args2.push_back(1);
+ args2.push_back(1);
+ lines_edited_args.push_front(args2);
+
SEND_GUI_KEY_EVENT(text_edit, Key::A);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "aA");
+ CHECK(text_edit->get_text() == "aA\naA");
CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -2427,20 +2983,24 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
text_edit->set_editable(false);
SEND_GUI_KEY_EVENT(text_edit, Key::A);
CHECK_FALSE(text_edit->get_viewport()->is_input_handled()); // Should this be handled?
- CHECK(text_edit->get_text() == "aA");
+ CHECK(text_edit->get_text() == "aA\naA");
CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
SIGNAL_CHECK_FALSE("caret_changed");
SIGNAL_CHECK_FALSE("text_changed");
SIGNAL_CHECK_FALSE("lines_edited_from");
text_edit->set_editable(true);
- lines_edited_args.push_back(lines_edited_args[0].duplicate());
+ lines_edited_args.push_back(lines_edited_args[1].duplicate());
+ lines_edited_args.push_front(args2.duplicate());
text_edit->select(0, 0, 0, 1);
+ text_edit->select(1, 0, 1, 1, 1);
SEND_GUI_KEY_EVENT(text_edit, Key::B);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "BA");
+ CHECK(text_edit->get_text() == "BA\nBA");
CHECK(text_edit->get_caret_column() == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
@@ -2450,22 +3010,36 @@ TEST_CASE("[SceneTree][TextEdit] text entry") {
SEND_GUI_KEY_EVENT(text_edit, Key::B);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "BB");
+ CHECK(text_edit->get_text() == "BB\nBB");
CHECK(text_edit->get_caret_column() == 2);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->select(0, 0, 0, 1);
+ text_edit->select(1, 0, 1, 1, 1);
SEND_GUI_KEY_EVENT(text_edit, Key::A);
CHECK(text_edit->get_viewport()->is_input_handled());
- CHECK(text_edit->get_text() == "AB");
+ CHECK(text_edit->get_text() == "AB\nAB");
CHECK(text_edit->get_caret_column() == 1);
+ CHECK(text_edit->get_caret_column(1) == 1);
SIGNAL_CHECK("caret_changed", empty_signal_args);
SIGNAL_CHECK("text_changed", empty_signal_args);
SIGNAL_CHECK("lines_edited_from", lines_edited_args);
text_edit->set_overtype_mode_enabled(false);
CHECK_FALSE(text_edit->is_overtype_mode_enabled());
+
+ lines_edited_args.remove_at(0);
+ lines_edited_args.remove_at(1);
+
+ SEND_GUI_KEY_EVENT(text_edit, Key::TAB);
+ CHECK(text_edit->get_viewport()->is_input_handled());
+ CHECK(text_edit->get_text() == "A\tB\nA\tB");
+ CHECK(text_edit->get_caret_column() == 2);
+ CHECK(text_edit->get_caret_column(1) == 2);
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ SIGNAL_CHECK("text_changed", empty_signal_args);
+ SIGNAL_CHECK("lines_edited_from", lines_edited_args);
}
SIGNAL_UNWATCH(text_edit, "text_set");
@@ -2558,7 +3132,7 @@ TEST_CASE("[SceneTree][TextEdit] versioning") {
CHECK(text_edit->has_redo());
text_edit->redo();
- CHECK(text_edit->get_line(0) == "test nested ops");
+ CHECK(text_edit->get_line(0) == "test ops nested");
CHECK(text_edit->get_version() == 3);
CHECK(text_edit->get_saved_version() == 3);
CHECK(text_edit->has_undo());
@@ -2779,6 +3353,136 @@ TEST_CASE("[SceneTree][TextEdit] caret") {
memdelete(text_edit);
}
+TEST_CASE("[SceneTree][TextEdit] multicaret") {
+ TextEdit *text_edit = memnew(TextEdit);
+ SceneTree::get_singleton()->get_root()->add_child(text_edit);
+ text_edit->set_multiple_carets_enabled(true);
+
+ Array empty_signal_args;
+ empty_signal_args.push_back(Array());
+
+ SIGNAL_WATCH(text_edit, "caret_changed");
+
+ text_edit->set_text("this is\nsome test\ntext");
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_DISCARD("caret_changed");
+
+ SUBCASE("[TextEdit] add remove caret") {
+ // Overlapping
+ CHECK(text_edit->add_caret(0, 0) == -1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_CHECK_FALSE("caret_changed");
+
+ // Selection
+ text_edit->select(0, 0, 2, 4);
+ CHECK(text_edit->add_caret(0, 0) == -1);
+ CHECK(text_edit->add_caret(2, 4) == -1);
+ CHECK(text_edit->add_caret(1, 2) == -1);
+
+ // Out of bounds
+ CHECK(text_edit->add_caret(-1, 0) == -1);
+ CHECK(text_edit->add_caret(5, 0) == -1);
+ CHECK(text_edit->add_caret(0, 100) == -1);
+
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_CHECK_FALSE("caret_changed");
+
+ CHECK(text_edit->get_caret_count() == 1);
+
+ text_edit->deselect();
+ SIGNAL_CHECK_FALSE("caret_changed");
+
+ CHECK(text_edit->add_caret(0, 1) == 1);
+ MessageQueue::get_singleton()->flush();
+ SIGNAL_CHECK("caret_changed", empty_signal_args);
+ CHECK(text_edit->get_caret_count() == 2);
+
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 0);
+
+ CHECK(text_edit->get_caret_line(1) == 0);
+ CHECK(text_edit->get_caret_column(1) == 1);
+
+ ERR_PRINT_OFF;
+ text_edit->remove_caret(-1);
+ text_edit->remove_caret(5);
+ ERR_PRINT_ON;
+ CHECK(text_edit->get_caret_count() == 2);
+ SIGNAL_CHECK_FALSE("caret_changed");
+
+ text_edit->remove_caret(0);
+ SIGNAL_CHECK_FALSE("caret_changed");
+ CHECK(text_edit->get_caret_count() == 1);
+ CHECK(text_edit->get_caret_line(0) == 0);
+ CHECK(text_edit->get_caret_column(0) == 1);
+
+ ERR_PRINT_OFF;
+ text_edit->remove_caret(0);
+ CHECK(text_edit->get_caret_count() == 1);
+ ERR_PRINT_ON;
+ }
+
+ SUBCASE("[TextEdit] caret index edit order") {
+ Vector<int> caret_index_get_order;
+ caret_index_get_order.push_back(1);
+ caret_index_get_order.push_back(0);
+
+ CHECK(text_edit->add_caret(1, 0));
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order);
+
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(1);
+ CHECK(text_edit->add_caret(0, 0));
+ CHECK(text_edit->get_caret_count() == 2);
+
+ caret_index_get_order.write[0] = 0;
+ caret_index_get_order.write[1] = 1;
+ CHECK(text_edit->get_caret_index_edit_order() == caret_index_get_order);
+ }
+
+ SUBCASE("[TextEdit] add caret at carets") {
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(1);
+ text_edit->set_caret_column(9);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_caret_line(1) == 2);
+ CHECK(text_edit->get_caret_column(1) == 4);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+
+ text_edit->add_caret_at_carets(false);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_caret_line(2) == 0);
+ CHECK(text_edit->get_caret_column(2) == 7);
+
+ text_edit->remove_secondary_carets();
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(4);
+ text_edit->select(0, 0, 0, 4);
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 2);
+ CHECK(text_edit->get_selection_from_line(1) == 1);
+ CHECK(text_edit->get_selection_to_line(1) == 1);
+ CHECK(text_edit->get_selection_from_column(1) == 0);
+ CHECK(text_edit->get_selection_to_column(1) == 3);
+
+ text_edit->add_caret_at_carets(true);
+ CHECK(text_edit->get_caret_count() == 3);
+ CHECK(text_edit->get_selection_from_line(2) == 2);
+ CHECK(text_edit->get_selection_to_line(2) == 2);
+ CHECK(text_edit->get_selection_from_column(2) == 0);
+ CHECK(text_edit->get_selection_to_column(2) == 4);
+ }
+
+ memdelete(text_edit);
+}
+
TEST_CASE("[SceneTree][TextEdit] line wrapping") {
TextEdit *text_edit = memnew(TextEdit);
SceneTree::get_singleton()->get_root()->add_child(text_edit);
@@ -3291,6 +3995,32 @@ TEST_CASE("[SceneTree][TextEdit] viewport") {
CHECK(text_edit->get_last_full_visible_line_wrap_index() == 0);
CHECK(text_edit->get_caret_wrap_index() == 0);
+ // Typing and undo / redo should adjust viewport
+ text_edit->set_caret_line(0);
+ text_edit->set_caret_column(0);
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ SEND_GUI_KEY_EVENT(text_edit, Key::A);
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->undo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
+ text_edit->set_line_as_first_visible(5);
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 5);
+
+ text_edit->redo();
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_first_visible_line() == 0);
+
memdelete(text_edit);
}
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 039081958f..453310f977 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -84,6 +84,7 @@
#include "tests/core/variant/test_dictionary.h"
#include "tests/core/variant/test_variant.h"
#include "tests/scene/test_animation.h"
+#include "tests/scene/test_arraymesh.h"
#include "tests/scene/test_audio_stream_wav.h"
#include "tests/scene/test_bit_map.h"
#include "tests/scene/test_code_edit.h"
@@ -200,7 +201,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
OS::get_singleton()->set_has_server_feature_callback(nullptr);
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
if (String("headless") == DisplayServer::get_create_function_name(i)) {
- DisplayServer::create(i, "", DisplayServer::WindowMode::WINDOW_MODE_MINIMIZED, DisplayServer::VSyncMode::VSYNC_ENABLED, 0, Vector2i(0, 0), err);
+ DisplayServer::create(i, "", DisplayServer::WindowMode::WINDOW_MODE_MINIMIZED, DisplayServer::VSyncMode::VSYNC_ENABLED, 0, nullptr, Vector2i(0, 0), err);
break;
}
}
diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h
index 1471a952cd..41185a7d16 100644
--- a/tests/test_validate_testing.h
+++ b/tests/test_validate_testing.h
@@ -86,7 +86,7 @@ TEST_SUITE("Validate tests") {
Plane plane(Vector3(1, 1, 1), 1.0);
INFO(plane);
- Quaternion quat(Vector3(0.5, 1.0, 2.0));
+ Quaternion quat = Quaternion::from_euler(Vector3(0.5, 1.0, 2.0));
INFO(quat);
AABB aabb(Vector3(), Vector3(100, 100, 100));
diff --git a/thirdparty/README.md b/thirdparty/README.md
index ac97d9c2a2..3b6be399b8 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.2.0 (4a1d891c6317d2c83e5f3c2607ec5f5ccedffcde, 2022)
+- Version: 5.3.1 (970321db7bddbe8c579b73751fc655a924ea3ce6, 2022)
- License: MIT
Files extracted from upstream source:
@@ -226,7 +226,7 @@ Files extracted from upstream source:
## icu4c
- Upstream: https://github.com/unicode-org/icu
-- Version: 71.1 (c205e7ee49a7086a28b9c275fcfdac9ca3dc815d, 2022)
+- Version: 72.1 (ff3514f257ea10afe7e710e9f946f68d256704b1, 2022)
- License: Unicode
Files extracted from upstream source:
@@ -238,14 +238,14 @@ Files extracted from upstream source:
Files generated from upstream source:
-- the `icudt71l.dat` built with the provided `godot_data.json` config file (see
+- the `icudt72l.dat` built with the provided `godot_data.json` config file (see
https://github.com/unicode-org/icu/blob/master/docs/userguide/icu_data/buildtool.md
for instructions).
- Step 1: Build ICU with default options - `./runConfigureICU {PLATFORM} && make`.
- Step 2: Reconfigure ICU with custom data config - `ICU_DATA_FILTER_FILE={GODOT_SOURCE}/thirdparty/icu4c/godot_data.json ./runConfigureICU {PLATFORM} --with-data-packaging=common`.
- Step 3: Delete `data/out` folder and rebuild data - `cd data && rm -rf ./out && make`.
-- Step 4: Copy `source/data/out/icudt71l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt71l.dat`.
+- Step 4: Copy `source/data/out/icudt72l.dat` to the `{GODOT_SOURCE}/thirdparty/icu4c/icudt72l.dat`.
## jpeg-compressor
@@ -656,7 +656,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/Samsung/thorvg
-- Version: 0.8.1 (c4ccb1078f4390ec749ab8e05ba7e9e35f81285f, 2022)
+- Version: 0.8.2 (496796f1e5e85bd5fbba36dae987edb1b3945592, 2022)
- License: MIT
Files extracted from upstream source:
diff --git a/thirdparty/glad/KHR/khrplatform.h b/thirdparty/glad/KHR/khrplatform.h
index dd22d92701..01646449ca 100644
--- a/thirdparty/glad/KHR/khrplatform.h
+++ b/thirdparty/glad/KHR/khrplatform.h
@@ -153,6 +153,20 @@ typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
+/*
+ * To support platform where unsigned long cannot be used interchangeably with
+ * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
+ * Ideally, we could just use (u)intptr_t everywhere, but this could result in
+ * ABI breakage if khronos_uintptr_t is changed from unsigned long to
+ * unsigned long long or similar (this results in different C++ name mangling).
+ * To avoid changes for existing platforms, we restrict usage of intptr_t to
+ * platforms where the size of a pointer is larger than the size of long.
+ */
+#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
+#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
+#define KHRONOS_USE_INTPTR_T
+#endif
+#endif
#elif defined(__VMS ) || defined(__sgi)
@@ -235,14 +249,21 @@ typedef unsigned short int khronos_uint16_t;
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
-#ifdef _WIN64
+#ifdef KHRONOS_USE_INTPTR_T
+typedef intptr_t khronos_intptr_t;
+typedef uintptr_t khronos_uintptr_t;
+#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
-typedef signed long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
+#endif
+
+#if defined(_WIN64)
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c
index dc1b8cb697..4b20178ef7 100644
--- a/thirdparty/glad/glad.c
+++ b/thirdparty/glad/glad.c
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020.
+ OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++
Specification: gl
@@ -11,16 +11,18 @@
GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample,
- GL_EXT_framebuffer_object
+ GL_EXT_framebuffer_object,
+ GL_OVR_multiview,
+ GL_OVR_multiview2
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/
#include <stdio.h>
@@ -1000,6 +1002,8 @@ int GLAD_GL_ARB_framebuffer_object = 0;
int GLAD_GL_EXT_framebuffer_blit = 0;
int GLAD_GL_EXT_framebuffer_multisample = 0;
int GLAD_GL_EXT_framebuffer_object = 0;
+int GLAD_GL_OVR_multiview = 0;
+int GLAD_GL_OVR_multiview2 = 0;
PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
@@ -1023,6 +1027,7 @@ PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glad_glFramebufferTexture3DEXT = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glad_glFramebufferRenderbufferEXT = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glad_glGetFramebufferAttachmentParameterivEXT = NULL;
PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT = NULL;
+PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
@@ -1844,6 +1849,10 @@ static void load_GL_EXT_framebuffer_object(GLADloadproc load) {
glad_glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)load("glGetFramebufferAttachmentParameterivEXT");
glad_glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)load("glGenerateMipmapEXT");
}
+static void load_GL_OVR_multiview(GLADloadproc load) {
+ if(!GLAD_GL_OVR_multiview) return;
+ glad_glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)load("glFramebufferTextureMultiviewOVR");
+}
static int find_extensionsGL(void) {
if (!get_exts()) return 0;
GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
@@ -1851,6 +1860,8 @@ static int find_extensionsGL(void) {
GLAD_GL_EXT_framebuffer_blit = has_ext("GL_EXT_framebuffer_blit");
GLAD_GL_EXT_framebuffer_multisample = has_ext("GL_EXT_framebuffer_multisample");
GLAD_GL_EXT_framebuffer_object = has_ext("GL_EXT_framebuffer_object");
+ GLAD_GL_OVR_multiview = has_ext("GL_OVR_multiview");
+ GLAD_GL_OVR_multiview2 = has_ext("GL_OVR_multiview2");
free_exts();
return 1;
}
@@ -1934,6 +1945,7 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_EXT_framebuffer_blit(load);
load_GL_EXT_framebuffer_multisample(load);
load_GL_EXT_framebuffer_object(load);
+ load_GL_OVR_multiview(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}
diff --git a/thirdparty/glad/glad/glad.h b/thirdparty/glad/glad/glad.h
index f211e6aa57..37d12e4ee2 100644
--- a/thirdparty/glad/glad/glad.h
+++ b/thirdparty/glad/glad/glad.h
@@ -1,6 +1,6 @@
/*
- OpenGL loader generated by glad 0.1.34 on Tue Nov 17 16:41:02 2020.
+ OpenGL loader generated by glad 0.1.36 on Sun Sep 4 15:50:32 2022.
Language/Generator: C/C++
Specification: gl
@@ -11,16 +11,18 @@
GL_ARB_framebuffer_object,
GL_EXT_framebuffer_blit,
GL_EXT_framebuffer_multisample,
- GL_EXT_framebuffer_object
+ GL_EXT_framebuffer_object,
+ GL_OVR_multiview,
+ GL_OVR_multiview2
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
- --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object"
+ --profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2"
Online:
- https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object
+ https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_debug_output&extensions=GL_ARB_framebuffer_object&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_object&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2
*/
@@ -3687,6 +3689,10 @@ GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define GL_RENDERBUFFER_ALPHA_SIZE_EXT 0x8D53
#define GL_RENDERBUFFER_DEPTH_SIZE_EXT 0x8D54
#define GL_RENDERBUFFER_STENCIL_SIZE_EXT 0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
+#define GL_MAX_VIEWS_OVR 0x9631
+#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
#ifndef GL_ARB_debug_output
#define GL_ARB_debug_output 1
GLAPI int GLAD_GL_ARB_debug_output;
@@ -3776,6 +3782,17 @@ typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC)(GLenum target);
GLAPI PFNGLGENERATEMIPMAPEXTPROC glad_glGenerateMipmapEXT;
#define glGenerateMipmapEXT glad_glGenerateMipmapEXT
#endif
+#ifndef GL_OVR_multiview
+#define GL_OVR_multiview 1
+GLAPI int GLAD_GL_OVR_multiview;
+typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
+GLAPI PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC glad_glFramebufferTextureMultiviewOVR;
+#define glFramebufferTextureMultiviewOVR glad_glFramebufferTextureMultiviewOVR
+#endif
+#ifndef GL_OVR_multiview2
+#define GL_OVR_multiview2 1
+GLAPI int GLAD_GL_OVR_multiview2;
+#endif
#ifdef __cplusplus
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
index 72829377a6..9493ec987e 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/GPOS.hh
@@ -39,7 +39,7 @@ struct GPOS : GSUBGPOS
bool subset (hb_subset_context_t *c) const
{
- hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
+ hb_subset_layout_context_t l (c, tableTag);
return GSUBGPOS::subset<PosLookup> (&l);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
index 5a9dd58a63..b4c9fc3db0 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -80,6 +80,24 @@ struct SinglePosFormat1
return_trace (true);
}
+ bool
+ position_single (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t gid,
+ hb_glyph_position_t &pos) const
+ {
+ unsigned int index = (this+coverage).get_coverage (gid);
+ if (likely (index == NOT_COVERED)) return false;
+
+ /* This is ugly... */
+ hb_buffer_t buffer;
+ buffer.props.direction = direction;
+ OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+ valueFormat.apply_value (&c, this, values, pos);
+ return true;
+ }
+
template<typename Iterator,
typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))>
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
index 8a6e8a42a6..c77951156b 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -68,7 +68,7 @@ struct SinglePosFormat2
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- if (likely (index >= valueCount)) return_trace (false);
+ if (unlikely (index >= valueCount)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
@@ -92,6 +92,28 @@ struct SinglePosFormat2
return_trace (true);
}
+ bool
+ position_single (hb_font_t *font,
+ hb_direction_t direction,
+ hb_codepoint_t gid,
+ hb_glyph_position_t &pos) const
+ {
+ unsigned int index = (this+coverage).get_coverage (gid);
+ if (likely (index == NOT_COVERED)) return false;
+ if (unlikely (index >= valueCount)) return false;
+
+ /* This is ugly... */
+ hb_buffer_t buffer;
+ buffer.props.direction = direction;
+ OT::hb_ot_apply_context_t c (1, font, &buffer);
+
+ valueFormat.apply_value (&c, this,
+ &values[index * valueFormat.get_len ()],
+ pos);
+ return true;
+ }
+
+
template<typename Iterator,
typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))>
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
index c0ff098f49..900cf603e4 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh
@@ -27,7 +27,7 @@ struct GSUB : GSUBGPOS
bool subset (hb_subset_context_t *c) const
{
- hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
+ hb_subset_layout_context_t l (c, tableTag);
return GSUBGPOS::subset<SubstLookup> (&l);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
index f373d921b5..6caa80e056 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
@@ -118,7 +118,7 @@ struct Ligature
match_positions[i] += delta;
if (i)
*p++ = ',';
- sprintf (p, "%u", match_positions[i]);
+ snprintf (p, sizeof(buf), "%u", match_positions[i]);
p += strlen(p);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
index 3d84a5e6ea..abf1c643ff 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
@@ -117,7 +117,7 @@ struct Sequence
{
if (buf < p)
*p++ = ',';
- sprintf (p, "%u", i);
+ snprintf (p, sizeof(buf), "%u", i);
p += strlen(p);
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
index afcb5dc834..0b25659acc 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
@@ -102,17 +102,19 @@ struct Glyph
hb_bytes_t &dest_bytes /* OUT */) const
{
GlyphHeader *glyph_header = nullptr;
- if (all_points.length > 4)
+ if (type != EMPTY && 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);
+ int xMin = 0, xMax = 0;
+ int yMin = 0, yMax = 0;
+ if (all_points.length > 4)
+ {
+ xMin = xMax = roundf (all_points[0].x);
+ yMin = yMax = roundf (all_points[0].y);
+ }
for (unsigned i = 1; i < all_points.length - 4; i++)
{
@@ -128,7 +130,7 @@ struct Glyph
/*for empty glyphs: all_points only include phantom points.
*just update metrics and then return */
- if (all_points.length == 4)
+ if (!glyph_header)
return true;
glyph_header->numberOfContours = header->numberOfContours;
@@ -145,10 +147,17 @@ struct Glyph
hb_font_t *font,
const glyf_accelerator_t &glyf,
hb_bytes_t &dest_start, /* IN/OUT */
- hb_bytes_t &dest_end /* OUT */) const
+ hb_bytes_t &dest_end /* OUT */)
{
contour_point_vector_t all_points, deltas;
- get_points (font, glyf, all_points, &deltas, false);
+ if (!get_points (font, glyf, all_points, &deltas, false, false))
+ return false;
+
+ // .notdef, set type to empty so we only update metrics and don't compile bytes for
+ // it
+ if (gid == 0 &&
+ !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ type = EMPTY;
switch (type) {
case COMPOSITE:
@@ -171,7 +180,12 @@ struct Glyph
break;
}
- return compile_header_bytes (plan, all_points, dest_start);
+ if (!compile_header_bytes (plan, all_points, dest_start))
+ {
+ dest_end.fini ();
+ return false;
+ }
+ return true;
}
@@ -182,6 +196,7 @@ struct Glyph
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 shift_points_hori = true,
bool use_my_metrics = true,
bool phantom_only = false,
unsigned int depth = 0) const
@@ -238,8 +253,7 @@ struct Glyph
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];
+ deltas->copy_vector (points);
}
#ifndef HB_NO_VAR
@@ -271,14 +285,9 @@ struct Glyph
comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font, glyf_accelerator, comp_points,
- deltas, use_my_metrics, phantom_only, depth + 1)))
+ deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1)))
return false;
- /* Copy phantom points from component if USE_MY_METRICS flag set */
- if (use_my_metrics && item.is_use_my_metrics ())
- for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
- phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
-
/* Apply component transformation & translation */
item.transform_points (comp_points);
@@ -299,6 +308,11 @@ struct Glyph
}
}
+ /* Copy phantom points from component if USE_MY_METRICS flag set */
+ if (use_my_metrics && item.is_use_my_metrics ())
+ for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
+ phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
+
all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
comp_index++;
@@ -310,7 +324,7 @@ struct Glyph
all_points.extend (phantoms);
}
- if (depth == 0) /* Apply at top level */
+ if (depth == 0 && shift_points_hori) /* Apply at top level */
{
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
@@ -332,10 +346,16 @@ struct Glyph
hb_bytes_t get_bytes () const { return bytes; }
- Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
- hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_),
- header (bytes.as<GlyphHeader> ()),
- gid (gid_)
+ Glyph () : bytes (),
+ header (bytes.as<GlyphHeader> ()),
+ gid (-1),
+ type(EMPTY)
+ {}
+
+ Glyph (hb_bytes_t bytes_,
+ hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
+ header (bytes.as<GlyphHeader> ()),
+ gid (gid_)
{
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
index b99665d6a0..d45f4eb350 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
@@ -271,31 +271,29 @@ struct SimpleGlyph
}
//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);
+ if (unlikely (!flags.alloc (num_points))) return false;
+ if (unlikely (!x_coords.alloc (2*num_points))) return false;
+ if (unlikely (!y_coords.alloc (2*num_points))) return false;
uint8_t lastflag = 0, repeat = 0;
-
+ int prev_x = 0.f, prev_y = 0.f;
+
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);
+ float cur_x = roundf (all_points[i].x);
+ float cur_y = roundf (all_points[i].y);
+ encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
+ encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
encode_flag (flag, repeat, lastflag, flags);
+
+ prev_x = cur_x;
+ prev_y = cur_y;
}
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
index 7ddefc5a91..88fc93c435 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
@@ -14,7 +14,6 @@ namespace glyf_impl {
struct SubsetGlyph
{
- hb_codepoint_t new_gid;
hb_codepoint_t old_gid;
Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */
diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
index be2cb1d0dc..5fb32f67f3 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh
@@ -72,10 +72,13 @@ struct glyf
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
- _populate_subset_glyphs (c->plan, &glyphs);
+ _populate_subset_glyphs (c->plan, glyphs);
if (!c->plan->pinned_at_default)
- _compile_subset_glyphs_with_deltas (c->plan, &glyphs);
+ {
+ if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs))
+ return_trace (false);
+ }
auto padded_offsets =
+ hb_iter (glyphs)
@@ -105,9 +108,9 @@ struct glyf
void
_populate_subset_glyphs (const hb_subset_plan_t *plan,
- hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
-
- void
+ hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
+
+ bool
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
@@ -180,7 +183,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, nullptr, true, phantom_only)))
+ if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only)))
return false;
if (consumer.is_consuming_contour_points ())
@@ -374,44 +377,43 @@ struct glyf_accelerator_t
inline void
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
- hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
+ hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
+ unsigned num_glyphs = plan->num_output_glyphs ();
+ if (!glyphs.resize (num_glyphs)) return;
- + hb_range (plan->num_output_glyphs ())
- | hb_map ([&] (hb_codepoint_t new_gid)
- {
- glyf_impl::SubsetGlyph subset_glyph = {0};
- subset_glyph.new_gid = new_gid;
-
- /* should never fail: all old gids should be mapped */
- if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
- return subset_glyph;
-
- if (new_gid == 0 &&
- !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
- subset_glyph.source_glyph = glyf_impl::Glyph ();
- else
- subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
- if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- subset_glyph.drop_hints_bytes ();
- else
- subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
- return subset_glyph;
- })
- | hb_sink (glyphs)
- ;
+ for (auto p : plan->glyph_map->iter ())
+ {
+ unsigned new_gid = p.second;
+ glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
+ subset_glyph.old_gid = p.first;
+
+ if (unlikely (new_gid == 0 &&
+ !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
+ plan->pinned_at_default)
+ subset_glyph.source_glyph = glyf_impl::Glyph ();
+ else
+ subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+
+ if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ subset_glyph.drop_hints_bytes ();
+ else
+ subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+ }
}
-inline void
+inline bool
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);
+ if (unlikely (!font)) return false;
hb_vector_t<hb_variation_t> vars;
- vars.alloc (plan->user_axes_location->get_population ());
+ if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
+ return false;
for (auto _ : *plan->user_axes_location)
{
@@ -423,9 +425,16 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
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);
+ {
+ if (!const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf))
+ {
+ hb_font_destroy (font);
+ return false;
+ }
+ }
hb_font_destroy (font);
+ return true;
}
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index 64878a84a4..79c7e690a1 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -70,8 +70,8 @@ struct graph_t
{
DEBUG_MSG (SUBSET_REPACK, nullptr,
"vertex [%lu] bytes != [%lu] bytes, depth = %u",
- table_size (),
- other.table_size (),
+ (unsigned long) table_size (),
+ (unsigned long) other.table_size (),
depth);
auto a = as_bytes ();
@@ -496,6 +496,12 @@ struct graph_t
}
template <typename T, typename ...Ts>
+ vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
+ {
+ return as_table_from_index<T> (mutable_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)
@@ -833,7 +839,20 @@ struct graph_t
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
*/
- bool duplicate (unsigned parent_idx, unsigned child_idx)
+ unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
+ {
+ unsigned new_idx = duplicate (parent_idx, child_idx);
+ if (new_idx == (unsigned) -1) return child_idx;
+ return new_idx;
+ }
+
+
+ /*
+ * Creates a copy of child and re-assigns the link from
+ * parent to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ */
+ unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{
update_parents ();
@@ -849,7 +868,7 @@ struct graph_t
// to child are from parent.
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
parent_idx, child_idx);
- return false;
+ return -1;
}
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
@@ -869,7 +888,7 @@ struct graph_t
reassign_link (l, parent_idx, clone_idx);
}
- return true;
+ return clone_idx;
}
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
index a93e7d1c73..e8d5bef9a8 100644
--- a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
@@ -131,8 +131,10 @@ struct Lookup : public OT::Lookup
for (unsigned i = 0; i < subTable.len; i++)
{
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+ unsigned parent_index = this_index;
if (is_ext) {
unsigned ext_subtable_index = subtable_index;
+ parent_index = ext_subtable_index;
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
c.graph.object (ext_subtable_index).head;
@@ -150,9 +152,9 @@ struct Lookup : public OT::Lookup
switch (type)
{
case 2:
- new_sub_tables = split_subtable<PairPos> (c, subtable_index); break;
+ new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
case 4:
- new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break;
+ new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
default:
break;
}
@@ -172,13 +174,14 @@ struct Lookup : public OT::Lookup
template<typename T>
hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
+ unsigned parent_idx,
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);
+ return sub_table->split_subtables (c, parent_idx, objidx);
}
void add_sub_tables (gsubgpos_graph_context_t& c,
diff --git a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
index 56fa812406..e42a6042cc 100644
--- a/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/markbasepos-graph.hh
@@ -209,7 +209,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
return vertex_len >= MarkBasePosFormat1::static_size;
}
- hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
{
hb_set_t visited;
@@ -261,7 +263,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
split_context_t split_context {
c,
this,
- this_index,
+ c.graph.duplicate_if_shared (parent_index, this_index),
std::move (class_to_info),
c.graph.vertices_[mark_array_id].position_to_index_map (),
};
@@ -365,8 +367,8 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
classCount = count;
- auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
- &markCoverage);
+ auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
+ &markCoverage);
if (!mark_coverage) return false;
hb_set_t marks = sc.marks_for (0, count);
auto new_coverage =
@@ -380,17 +382,17 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
return false;
- auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index,
- &baseArray,
- old_count);
+ auto base_array = sc.c.graph.as_mutable_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);
+ auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
+ &markArray);
if (!mark_array || !mark_array.table->shrink (sc.c,
sc.mark_array_links,
mark_array.index,
@@ -469,11 +471,12 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
{
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
unsigned this_index)
{
switch (u.format) {
case 1:
- return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index);
+ return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BORING_EXPANSION
case 2: HB_FALLTHROUGH;
// Don't split 24bit PairPos's.
diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
index 976b872329..8040778ea3 100644
--- a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
+++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
@@ -47,7 +47,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
min_size + pairSet.get_size () - pairSet.len.get_size();
}
- hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
{
hb_set_t visited;
@@ -81,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
split_context_t split_context {
c,
this,
- this_index,
+ c.graph.duplicate_if_shared (parent_index, this_index),
};
return actuate_subtable_split<split_context_t> (split_context, split_points);
@@ -125,23 +127,19 @@ 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.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 || !coverage_table->sanitize (coverage_v))
- return false;
+ auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
+ if (!coverage) return false;
+ unsigned coverage_size = coverage.vertex->table_size ();
auto new_coverage =
- + hb_zip (coverage_table->iter (), hb_range ())
+ + hb_zip (coverage.table->iter (), hb_range ())
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
return p.second < count;
})
| hb_map_retains_sorting (hb_first)
;
- return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size);
+ return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
}
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
@@ -206,7 +204,9 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
min_size + class1_count * get_class1_record_size ();
}
- hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ 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);
@@ -287,7 +287,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_context_t split_context {
c,
this,
- this_index,
+ c.graph.duplicate_if_shared (parent_index, this_index),
class1_record_size,
total_value_len,
value_1_len,
@@ -508,40 +508,37 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
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 coverage =
+ graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
+ if (!coverage) return false;
+
+ auto class_def_1 =
+ graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
+ if (!class_def_1) return false;
auto klass_map =
- + coverage_table->iter ()
+ + 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));
+ 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)
;
+ auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
if (!Coverage::make_coverage (split_context.c,
- + klass_map | hb_map_retains_sorting (hb_first),
- coverage_id,
- coverage_v.table_size ()))
+ + new_coverage,
+ coverage.index,
+ // existing ranges my not be kept, worst case size is a format 1
+ // coverage table.
+ 4 + new_coverage.len() * 2))
return false;
return ClassDef::make_class_def (split_context.c,
+ klass_map,
- class_def_1_id,
- class_def_1_v.table_size ());
+ class_def_1.index,
+ class_def_1.vertex->table_size ());
}
hb_hashmap_t<unsigned, unsigned>
@@ -605,13 +602,15 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
struct PairPos : public OT::Layout::GPOS_impl::PairPos
{
- hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
+ unsigned parent_index,
+ unsigned this_index)
{
switch (u.format) {
case 1:
- return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
+ return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
case 2:
- return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
+ return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BORING_EXPANSION
case 3: HB_FALLTHROUGH;
case 4: HB_FALLTHROUGH;
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
index 57c105967d..8fd3990f88 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
@@ -70,9 +70,9 @@ struct DecompositionAction
ActionSubrecordHeader
header;
- HBFixed lowerLimit; /* If the distance factor is less than this value,
+ F16DOT16 lowerLimit; /* If the distance factor is less than this value,
* then the ligature is decomposed. */
- HBFixed upperLimit; /* If the distance factor is greater than this value,
+ F16DOT16 upperLimit; /* If the distance factor is greater than this value,
* then the ligature is decomposed. */
HBUINT16 order; /* Numerical order in which this ligature will
* be decomposed; you may want infrequent ligatures
@@ -118,7 +118,7 @@ struct ConditionalAddGlyphAction
protected:
ActionSubrecordHeader
header;
- HBFixed substThreshold; /* Distance growth factor (in ems) at which
+ F16DOT16 substThreshold; /* Distance growth factor (in ems) at which
* this glyph is replaced and the growth factor
* recalculated. */
HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is
@@ -146,13 +146,13 @@ struct DuctileGlyphAction
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
* This would normally be 0x64756374 ('duct'),
* but you may use any axis the font contains. */
- HBFixed minimumLimit; /* The lowest value for the ductility axis that
+ F16DOT16 minimumLimit; /* The lowest value for the ductility axis that
* still yields an acceptable appearance. Normally
* this will be 1.0. */
- HBFixed noStretchValue; /* This is the default value that corresponds to
+ F16DOT16 noStretchValue; /* This is the default value that corresponds to
* no change in appearance. Normally, this will
* be 1.0. */
- HBFixed maximumLimit; /* The highest value for the ductility axis that
+ F16DOT16 maximumLimit; /* The highest value for the ductility axis that
* still yields an acceptable appearance. */
public:
DEFINE_SIZE_STATIC (22);
@@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
};
protected:
- HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
+ F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the
* glyph is permitted to grow on the left or top side. */
- HBFixed beforeShrinkLimit;
+ F16DOT16 beforeShrinkLimit;
/* The ratio by which the advance width of the
* glyph is permitted to shrink on the left or top side. */
- HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
+ F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph
* is permitted to shrink on the left or top side. */
- HBFixed afterShrinkLimit;
+ F16DOT16 afterShrinkLimit;
/* The ratio by which the advance width of the glyph
* is at most permitted to shrink on the right or
* bottom side. */
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
index 68bcb2396f..2ba9355b06 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
+++ b/thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
@@ -62,7 +62,7 @@ struct TrackTableEntry
}
protected:
- HBFixed track; /* Track value for this record. */
+ F16DOT16 track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
@@ -82,7 +82,7 @@ struct TrackData
const void *base) const
{
unsigned int sizes = nSizes;
- hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+ hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
@@ -120,7 +120,7 @@ struct TrackData
if (!sizes) return 0.;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
- hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
+ hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem)
@@ -141,7 +141,7 @@ struct TrackData
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
- NNOffset32To<UnsizedArrayOf<HBFixed>>
+ NNOffset32To<UnsizedArrayOf<F16DOT16>>
sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout.cc b/thirdparty/harfbuzz/src/hb-aat-layout.cc
index e06d286ff0..d60126fe19 100644
--- a/thirdparty/harfbuzz/src/hb-aat-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-aat-layout.cc
@@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
+ {HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh
index 5567ddaec3..d56617f6a9 100644
--- a/thirdparty/harfbuzz/src/hb-config.hh
+++ b/thirdparty/harfbuzz/src/hb-config.hh
@@ -71,6 +71,7 @@
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
+#define HB_NO_LAYOUT_RARELY_USED
#define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH
#define HB_NO_META
diff --git a/thirdparty/harfbuzz/src/hb-cplusplus.hh b/thirdparty/harfbuzz/src/hb-cplusplus.hh
index c4d9d29e23..a210ab7960 100644
--- a/thirdparty/harfbuzz/src/hb-cplusplus.hh
+++ b/thirdparty/harfbuzz/src/hb-cplusplus.hh
@@ -69,9 +69,9 @@ struct shared_ptr
operator T * () const { return p; }
T& operator * () const { return *get (); }
T* operator -> () const { return get (); }
- operator bool () { return p; }
- bool operator == (const shared_ptr &o) { return p == o.p; }
- bool operator != (const shared_ptr &o) { return p != o.p; }
+ operator bool () const { return p; }
+ bool operator == (const shared_ptr &o) const { return p == o.p; }
+ bool operator != (const shared_ptr &o) const { return p != o.p; }
static T* get_empty() { return v::get_empty (); }
T* reference() { return v::reference (p); }
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 2160d6a010..e7deb31dd8 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -633,20 +633,29 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
* face-builder: A face that has add_table().
*/
+struct face_table_info_t
+{
+ hb_blob_t* data;
+ unsigned order;
+};
+
struct hb_face_builder_data_t
{
- hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
+ hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
};
static int compare_entries (const void* pa, const void* pb)
{
- const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
- const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
+ const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
+ const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */
- if (a.second->length != b.second->length)
- return a.second->length < b.second->length ? -1 : +1;
+ if (a.second.order != b.second.order)
+ return a.second.order < b.second.order ? -1 : +1;
+
+ if (a.second.data->length != b.second.data->length)
+ return a.second.data->length < b.second.data->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
}
@@ -668,8 +677,8 @@ _hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
- for (hb_blob_t* b : data->tables.values())
- hb_blob_destroy (b);
+ for (auto info : data->tables.values())
+ hb_blob_destroy (info.data);
data->tables.fini ();
@@ -683,8 +692,8 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12;
- for (hb_blob_t* b : data->tables.values())
- face_length += hb_ceil_to_4 (hb_blob_get_length (b));
+ for (auto info : data->tables.values())
+ face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf))
@@ -699,7 +708,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
// Sort the tags so that produced face is deterministic.
- hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
+ hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ()))
{
@@ -708,7 +717,13 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
}
sorted_entries.qsort (compare_entries);
- bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
+
+ bool ret = f->serialize_single (&c,
+ sfnt_tag,
+ + sorted_entries.iter()
+ | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
+ return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
+ }));
c.end_serialize ();
@@ -729,7 +744,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
if (!tag)
return _hb_face_builder_data_reference_blob (data);
- return hb_blob_reference (data->tables[tag]);
+ return hb_blob_reference (data->tables[tag].data);
}
@@ -777,8 +792,8 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
- hb_blob_t* previous = data->tables.get (tag);
- if (!data->tables.set (tag, hb_blob_reference (blob)))
+ hb_blob_t* previous = data->tables.get (tag).data;
+ if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0}))
{
hb_blob_destroy (blob);
return false;
@@ -787,3 +802,36 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
hb_blob_destroy (previous);
return true;
}
+
+/**
+ * hb_face_builder_sort_tables:
+ * @face: A face object created with hb_face_builder_create()
+ * @tags: (array zero-terminated=1): ordered list of table tags terminated by
+ * %HB_TAG_NONE
+ *
+ * Set the ordering of tables for serialization. Any tables not
+ * specified in the tags list will be ordered after the tables in
+ * tags, ordered by the default sort ordering.
+ *
+ * Since: 5.3.0
+ **/
+void
+hb_face_builder_sort_tables (hb_face_t *face,
+ const hb_tag_t *tags)
+{
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+ // Sort all unspecified tables after any specified tables.
+ for (auto& info : data->tables.values_ref())
+ info.order = -1;
+
+ unsigned order = 0;
+ for (const hb_tag_t* tag = tags;
+ *tag;
+ tag++)
+ {
+ face_table_info_t* info;
+ if (!data->tables.has (*tag, &info)) continue;
+ info->order = order++;
+ }
+}
diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h
index 6ef2f8b886..38e7104af6 100644
--- a/thirdparty/harfbuzz/src/hb-face.h
+++ b/thirdparty/harfbuzz/src/hb-face.h
@@ -171,6 +171,10 @@ hb_face_builder_add_table (hb_face_t *face,
hb_tag_t tag,
hb_blob_t *blob);
+HB_EXTERN void
+hb_face_builder_sort_tables (hb_face_t *face,
+ const hb_tag_t *tags);
+
HB_END_DECLS
diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh
index 1921ccbb6d..52a6791e31 100644
--- a/thirdparty/harfbuzz/src/hb-meta.hh
+++ b/thirdparty/harfbuzz/src/hb-meta.hh
@@ -133,6 +133,18 @@ struct
template <typename T> constexpr auto
operator () (T *v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
+
+ template <typename T> constexpr auto
+ operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
}
HB_FUNCOBJ (hb_deref);
diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh
index d0d01a68c5..e66f451820 100644
--- a/thirdparty/harfbuzz/src/hb-open-type.hh
+++ b/thirdparty/harfbuzz/src/hb-open-type.hh
@@ -141,27 +141,24 @@ typedef HBINT32 FWORD32;
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
typedef HBUINT16 UFWORD;
-/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
-struct F2DOT14 : HBINT16
+template <typename Type, unsigned fraction_bits>
+struct HBFixed : Type
{
- F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
- // 16384 means 1<<14
- float to_float () const { return ((int32_t) v) / 16384.f; }
- void set_float (float f) { v = roundf (f * 16384.f); }
+ static constexpr float shift = (float) (1 << fraction_bits);
+ static_assert (Type::static_size * 8 > fraction_bits, "");
+
+ HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
+ float to_float () const { return ((int32_t) Type::v) / shift; }
+ void set_float (float f) { Type::v = roundf (f * shift); }
public:
- DEFINE_SIZE_STATIC (2);
+ DEFINE_SIZE_STATIC (Type::static_size);
};
+/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
+using F2DOT14 = HBFixed<HBINT16, 14>;
+
/* 32-bit signed fixed-point number (16.16). */
-struct HBFixed : HBINT32
-{
- HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
- // 65536 means 1<<16
- float to_float () const { return ((int32_t) v) / 65536.f; }
- void set_float (float f) { v = roundf (f * 65536.f); }
- public:
- DEFINE_SIZE_STATIC (4);
-};
+using F16DOT16 = HBFixed<HBINT32, 16>;
/* Date represented in number of seconds since 12:00 midnight, January 1,
* 1904. The value is represented as a signed 64-bit integer. */
diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
index f01d383bdc..908bf550f0 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
@@ -358,14 +358,14 @@ struct Affine2x3
return_trace (c->check_struct (this));
}
- HBFixed xx;
- HBFixed yx;
- HBFixed xy;
- HBFixed yy;
- HBFixed dx;
- HBFixed dy;
+ F16DOT16 xx;
+ F16DOT16 yx;
+ F16DOT16 xy;
+ F16DOT16 yy;
+ F16DOT16 dx;
+ F16DOT16 dy;
public:
- DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
+ DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
};
struct PaintColrLayers
diff --git a/thirdparty/harfbuzz/src/hb-ot-color.cc b/thirdparty/harfbuzz/src/hb-ot-color.cc
index a9ae013682..696ca3e17f 100644
--- a/thirdparty/harfbuzz/src/hb-ot-color.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-color.cc
@@ -295,8 +295,8 @@ hb_ot_color_has_png (hb_face_t *face)
* @glyph: a glyph index
*
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
- * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
- * object. If UPEM is unset, the blob returned will be the largest PNG available.
+ * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
+ * object. If PPEM is unset, the blob returned will be the largest PNG available.
*
* If the glyph has no PNG image, the singleton empty blob is returned.
*
diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc
index c90a65665c..825b30853c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-font.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-font.cc
@@ -40,7 +40,6 @@
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
-#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-vorg-table.hh"
@@ -349,15 +348,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
+ if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
#endif
-#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
- if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
-#endif
// TODO Hook up side-bearings variations.
return false;
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 05916a252c..579abf011a 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -94,6 +94,19 @@ static bool ClassDef_remap_and_serialize (
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*/);
+struct hb_collect_feature_substitutes_with_var_context_t
+{
+ const hb_map_t *axes_index_tag_map;
+ const hb_hashmap_t<hb_tag_t, int> *axes_location;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
+ hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+
+ // not stored in subset_plan
+ hb_set_t *feature_indices;
+ bool apply;
+ unsigned cur_record_idx;
+ hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
+};
struct hb_prune_langsys_context_t
{
@@ -160,24 +173,40 @@ struct hb_subset_layout_context_t :
const hb_map_t *lookup_index_map;
const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
const hb_map_t *feature_index_map;
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+
unsigned cur_script_index;
+ unsigned cur_feature_var_record_idx;
hb_subset_layout_context_t (hb_subset_context_t *c_,
- hb_tag_t tag_,
- hb_map_t *lookup_map_,
- hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
- hb_map_t *feature_index_map_) :
+ hb_tag_t tag_) :
subset_context (c_),
table_tag (tag_),
- lookup_index_map (lookup_map_),
- script_langsys_map (script_langsys_map_),
- feature_index_map (feature_index_map_),
cur_script_index (0xFFFFu),
+ cur_feature_var_record_idx (0u),
script_count (0),
langsys_count (0),
feature_index_count (0),
lookup_index_count (0)
- {}
+ {
+ if (tag_ == HB_OT_TAG_GSUB)
+ {
+ lookup_index_map = c_->plan->gsub_lookups;
+ script_langsys_map = c_->plan->gsub_langsys;
+ feature_index_map = c_->plan->gsub_features;
+ feature_substitutes_map = c_->plan->gsub_feature_substitutes_map;
+ feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map;
+ }
+ else
+ {
+ lookup_index_map = c_->plan->gpos_lookups;
+ script_langsys_map = c_->plan->gpos_langsys;
+ feature_index_map = c_->plan->gpos_features;
+ feature_substitutes_map = c_->plan->gpos_feature_substitutes_map;
+ feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map;
+ }
+ }
private:
unsigned script_count;
@@ -324,6 +353,31 @@ struct subset_record_array_t
const void *base;
};
+template<typename OutputArray, typename Arg>
+struct subset_record_array_arg_t
+{
+ subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
+ const void *base_,
+ Arg &&arg_) : subset_layout_context (c_),
+ out (out_), base (base_), arg (arg_) {}
+
+ template <typename T>
+ void
+ operator () (T&& record)
+ {
+ auto snap = subset_layout_context->subset_context->serializer->snapshot ();
+ bool ret = record.subset (subset_layout_context, base, arg);
+ if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
+ else out->len++;
+ }
+
+ private:
+ hb_subset_layout_context_t *subset_layout_context;
+ OutputArray *out;
+ const void *base;
+ Arg &&arg;
+};
+
/*
* Helper to subset a RecordList/record array. Subsets each Record in the array and
* discards the record if the subset operation returns false.
@@ -335,6 +389,13 @@ struct
operator () (hb_subset_layout_context_t *c, OutputArray* out,
const void *base) const
{ return subset_record_array_t<OutputArray> (c, out, base); }
+
+ /* Variant with one extra argument passed to subset */
+ template<typename OutputArray, typename Arg>
+ subset_record_array_arg_t<OutputArray, Arg>
+ operator () (hb_subset_layout_context_t *c, OutputArray* out,
+ const void *base, Arg &&arg) const
+ { return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
}
HB_FUNCOBJ (subset_record_array);
@@ -431,94 +492,6 @@ struct IndexArray : Array16Of<Index>
};
-struct Record_sanitize_closure_t {
- hb_tag_t tag;
- const void *list_base;
-};
-
-template <typename Type>
-struct Record
-{
- int cmp (hb_tag_t a) const { return tag.cmp (a); }
-
- bool subset (hb_subset_layout_context_t *c, const void *base) const
- {
- TRACE_SUBSET (this);
- auto *out = c->subset_context->serializer->embed (this);
- if (unlikely (!out)) return_trace (false);
- bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
- return_trace (ret);
- }
-
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
- {
- TRACE_SANITIZE (this);
- const Record_sanitize_closure_t closure = {tag, base};
- return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
- }
-
- Tag tag; /* 4-byte Tag identifier */
- Offset16To<Type>
- offset; /* Offset from beginning of object holding
- * the Record */
- public:
- DEFINE_SIZE_STATIC (6);
-};
-
-template <typename Type>
-struct RecordArrayOf : SortedArray16Of<Record<Type>>
-{
- const Offset16To<Type>& get_offset (unsigned int i) const
- { return (*this)[i].offset; }
- Offset16To<Type>& get_offset (unsigned int i)
- { return (*this)[i].offset; }
- const Tag& get_tag (unsigned int i) const
- { return (*this)[i].tag; }
- unsigned int get_tags (unsigned int start_offset,
- unsigned int *record_count /* IN/OUT */,
- hb_tag_t *record_tags /* OUT */) const
- {
- if (record_count)
- {
- + this->sub_array (start_offset, record_count)
- | hb_map (&Record<Type>::tag)
- | hb_sink (hb_array (record_tags, *record_count))
- ;
- }
- return this->len;
- }
- bool find_index (hb_tag_t tag, unsigned int *index) const
- {
- return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
- }
-};
-
-template <typename Type>
-struct RecordListOf : RecordArrayOf<Type>
-{
- const Type& operator [] (unsigned int i) const
- { return this+this->get_offset (i); }
-
- bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
- {
- TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
-
- + this->iter ()
- | hb_apply (subset_record_array (l, out, this))
- ;
- return_trace (true);
- }
-
- bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (RecordArrayOf<Type>::sanitize (c, this));
- }
-};
-
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
struct FeatureParamsSize
{
@@ -801,6 +774,10 @@ struct FeatureParams
DEFINE_SIZE_MIN (0);
};
+struct Record_sanitize_closure_t {
+ hb_tag_t tag;
+ const void *list_base;
+};
struct Feature
{
@@ -897,6 +874,103 @@ struct Feature
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
};
+template <typename Type>
+struct Record
+{
+ int cmp (hb_tag_t a) const { return tag.cmp (a); }
+
+ bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->subset_context->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (!f_sub)
+ return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
+
+ const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
+ auto *s = c->subset_context->serializer;
+ s->push ();
+
+ out->offset = 0;
+ bool ret = f.subset (c->subset_context, c, &tag);
+ if (ret)
+ s->add_link (out->offset, s->pop_pack ());
+ else
+ s->pop_discard ();
+
+ return_trace (ret);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ const Record_sanitize_closure_t closure = {tag, base};
+ return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+ }
+
+ Tag tag; /* 4-byte Tag identifier */
+ Offset16To<Type>
+ offset; /* Offset from beginning of object holding
+ * the Record */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : SortedArray16Of<Record<Type>>
+{
+ const Offset16To<Type>& get_offset (unsigned int i) const
+ { return (*this)[i].offset; }
+ Offset16To<Type>& get_offset (unsigned int i)
+ { return (*this)[i].offset; }
+ const Tag& get_tag (unsigned int i) const
+ { return (*this)[i].tag; }
+ unsigned int get_tags (unsigned int start_offset,
+ unsigned int *record_count /* IN/OUT */,
+ hb_tag_t *record_tags /* OUT */) const
+ {
+ if (record_count)
+ {
+ + this->sub_array (start_offset, record_count)
+ | hb_map (&Record<Type>::tag)
+ | hb_sink (hb_array (record_tags, *record_count))
+ ;
+ }
+ return this->len;
+ }
+ bool find_index (hb_tag_t tag, unsigned int *index) const
+ {
+ return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+ }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+ const Type& operator [] (unsigned int i) const
+ { return this+this->get_offset (i); }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ + this->iter ()
+ | hb_apply (subset_record_array (l, out, this))
+ ;
+ return_trace (true);
+ }
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (RecordArrayOf<Type>::sanitize (c, this));
+ }
+};
+
struct RecordListOfFeature : RecordListOf<Feature>
{
bool subset (hb_subset_context_t *c,
@@ -907,11 +981,20 @@ struct RecordListOfFeature : RecordListOf<Feature>
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
unsigned count = this->len;
+
+ hb_zip (*this, hb_range (count))
| hb_filter (l->feature_index_map, hb_second)
- | hb_map (hb_first)
- | hb_apply (subset_record_array (l, out, this))
+ | hb_apply ([l, out, this] (const hb_pair_t<const Record<Feature>&, unsigned>& _)
+ {
+ const Feature *f_sub = nullptr;
+ const Feature **f = nullptr;
+ if (l->feature_substitutes_map->has (_.second, &f))
+ f_sub = *f;
+
+ subset_record_array (l, out, this, f_sub) (_.first);
+ })
;
+
return_trace (true);
}
};
@@ -2692,6 +2775,13 @@ struct VariationStore
/*
* Feature Variations
*/
+enum Cond_with_Var_flag_t
+{
+ KEEP_COND_WITH_VAR = 0,
+ DROP_COND_WITH_VAR = 1,
+ DROP_RECORD_WITH_VAR = 2,
+ MEM_ERR_WITH_VAR = 3,
+};
struct ConditionFormat1
{
@@ -2702,10 +2792,52 @@ struct ConditionFormat1
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (true);
+
+ const hb_map_t *index_map = c->plan->axes_index_map;
+ if (index_map->is_empty ()) return_trace (true);
+
+ if (!index_map->has (axisIndex))
+ return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
private:
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ hb_map_t *condition_map /* OUT */) const
+ {
+ //invalid axis index, drop the entire record
+ if (!c->axes_index_tag_map->has (axisIndex))
+ return DROP_RECORD_WITH_VAR;
+
+ hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
+
+ //axis not pinned, keep the condition
+ if (!c->axes_location->has (axis_tag))
+ {
+ // add axisIndex->value into the hashmap so we can check if the record is
+ // unique with variations
+ int16_t min_val = filterRangeMinValue;
+ int16_t max_val = filterRangeMaxValue;
+ hb_codepoint_t val = (max_val << 16) + min_val;
+
+ condition_map->set (axisIndex, val);
+ return KEEP_COND_WITH_VAR;
+ }
+
+ //axis pinned, check if condition is met
+ //TODO: add check for axis Ranges
+ int v = c->axes_location->get (axis_tag);
+
+ //condition not met, drop the entire record
+ if (v < filterRangeMinValue || v > filterRangeMaxValue)
+ return DROP_RECORD_WITH_VAR;
+
+ //axis pinned and condition met, drop the condition
+ return DROP_COND_WITH_VAR;
+ }
+
bool evaluate (const int *coords, unsigned int coord_len) const
{
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
@@ -2737,6 +2869,15 @@ struct Condition
}
}
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ hb_map_t *condition_map /* OUT */) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.keep_with_variations (c, condition_map);
+ default:return KEEP_COND_WITH_VAR;
+ }
+ }
+
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
@@ -2778,15 +2919,65 @@ struct ConditionSet
return true;
}
- bool subset (hb_subset_context_t *c) const
+ Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ hb_map_t *condition_map = hb_map_create ();
+ if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
+ hb::shared_ptr<hb_map_t> p {condition_map};
+
+ hb_set_t *cond_set = hb_set_create ();
+ if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
+ hb::shared_ptr<hb_set_t> s {cond_set};
+
+ unsigned num_kept_cond = 0, cond_idx = 0;
+ for (const auto& offset : conditions)
+ {
+ Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
+ // one condition is not met, drop the entire record
+ if (ret == DROP_RECORD_WITH_VAR)
+ return DROP_RECORD_WITH_VAR;
+
+ // axis not pinned, keep this condition
+ if (ret == KEEP_COND_WITH_VAR)
+ {
+ cond_set->add (cond_idx);
+ num_kept_cond++;
+ }
+ cond_idx++;
+ }
+
+ // all conditions met
+ if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
+
+ //check if condition_set is unique with variations
+ if (c->conditionset_map->has (p))
+ //duplicate found, drop the entire record
+ return DROP_RECORD_WITH_VAR;
+
+ c->conditionset_map->set (p, 1);
+ c->record_cond_idx_map->set (c->cur_record_idx, s);
+
+ return KEEP_COND_WITH_VAR;
+ }
+
+ bool subset (hb_subset_context_t *c,
+ hb_subset_layout_context_t *l) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
- + conditions.iter ()
- | hb_apply (subset_offset_array (c, out->conditions, this))
- ;
+ hb_set_t *retained_cond_set = nullptr;
+ if (l->feature_record_cond_idx_map != nullptr)
+ retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
+
+ unsigned int count = conditions.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (retained_cond_set != nullptr && !retained_cond_set->has (i))
+ continue;
+ subset_offset_array (c, out->conditions, this) (conditions[i]);
+ }
return_trace (bool (out->conditions));
}
@@ -2820,10 +3011,19 @@ struct FeatureTableSubstitutionRecord
feature_indexes->add (featureIndex);
}
+ void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+ const hb_set_t *feature_indices,
+ const void *base) const
+ {
+ if (feature_indices->has (featureIndex))
+ feature_substitutes_map->set (featureIndex, &(base+feature));
+ }
+
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
- if (!c->feature_index_map->has (featureIndex)) {
+ if (!c->feature_index_map->has (featureIndex) ||
+ c->feature_substitutes_map->has (featureIndex)) {
// Feature that is being substituted is not being retained, so we don't
// need this.
return_trace (false);
@@ -2865,10 +3065,16 @@ struct FeatureTableSubstitution
}
void collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
+ hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
+ | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
+ {
+ if (feature_substitutes_map == nullptr) return true;
+ return !feature_substitutes_map->has (record.featureIndex);
+ })
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
{ r.collect_lookups (this, lookup_indexes); })
;
@@ -2890,6 +3096,12 @@ struct FeatureTableSubstitution
return false;
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ for (const FeatureTableSubstitutionRecord& record : substitutions)
+ record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l) const
{
@@ -2929,9 +3141,10 @@ struct FeatureVariationRecord
void collect_lookups (const void *base,
const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
- return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
+ return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
}
void closure_features (const void *base,
@@ -2946,13 +3159,25 @@ struct FeatureVariationRecord
return (base+substitutions).intersects_features (feature_index_map);
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
+ const void *base) const
+ {
+ // ret == 1, all conditions met
+ if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
+ c->apply)
+ {
+ (base+substitutions).collect_feature_substitutes_with_variations (c);
+ c->apply = false; // set variations only once
+ }
+ }
+
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- out->conditions.serialize_subset (c->subset_context, conditions, base);
+ out->conditions.serialize_subset (c->subset_context, conditions, base, c);
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
return_trace (true);
@@ -3002,6 +3227,16 @@ struct FeatureVariations
return (this+record.substitutions).find_substitute (feature_index);
}
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ {
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ c->cur_record_idx = i;
+ varRecords[i].collect_feature_substitutes_with_variations (c, this);
+ }
+ }
+
FeatureVariations* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
@@ -3009,17 +3244,25 @@ struct FeatureVariations
}
void collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
for (const FeatureVariationRecord& r : varRecords)
- r.collect_lookups (this, feature_indexes, lookup_indexes);
+ r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
}
void closure_features (const hb_map_t *lookup_indexes,
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *feature_indexes /* OUT */) const
{
- for (const FeatureVariationRecord& record : varRecords)
- record.closure_features (this, lookup_indexes, feature_indexes);
+ unsigned int count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (feature_record_cond_idx_map != nullptr &&
+ !feature_record_cond_idx_map->has (i))
+ continue;
+ varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
+ }
}
bool subset (hb_subset_context_t *c,
@@ -3041,7 +3284,13 @@ struct FeatureVariations
}
unsigned count = (unsigned) (keep_up_to + 1);
- for (unsigned i = 0; i < count; i++) {
+ for (unsigned i = 0; i < count; i++)
+ {
+ if (l->feature_record_cond_idx_map != nullptr &&
+ !l->feature_record_cond_idx_map->has (i))
+ continue;
+
+ l->cur_feature_var_record_idx = i;
subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
}
return_trace (bool (out->varRecords));
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index c15a42b0f1..d1d94255f4 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -4236,13 +4236,19 @@ struct GSUBGPOS
}
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
#ifndef HB_NO_VAR
- get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes);
+ get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
#endif
}
+#ifndef HB_NO_VAR
+ void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
+#endif
+
template <typename TLookup>
void closure_lookups (hb_face_t *face,
const hb_set_t *glyphs,
@@ -4278,6 +4284,8 @@ struct GSUBGPOS
}
void prune_features (const hb_map_t *lookup_indices, /* IN */
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
+ const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
hb_set_t *feature_indices /* IN/OUT */) const
{
#ifndef HB_NO_VAR
@@ -4285,7 +4293,7 @@ struct GSUBGPOS
// if the FeatureVariation's table and the alternate version(s) intersect the
// set of lookup indices.
hb_set_t alternate_feature_indices;
- get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices);
+ get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
if (unlikely (alternate_feature_indices.in_error()))
{
feature_indices->err ();
@@ -4295,7 +4303,6 @@ struct GSUBGPOS
for (unsigned i : feature_indices->iter())
{
- const Feature& f = get_feature (i);
hb_tag_t tag = get_feature_tag (i);
if (tag == HB_TAG ('p', 'r', 'e', 'f'))
// Note: Never ever drop feature 'pref', even if it's empty.
@@ -4305,11 +4312,16 @@ struct GSUBGPOS
continue;
- if (!f.featureParams.is_null () &&
+ const Feature *f = &(get_feature (i));
+ const Feature** p = nullptr;
+ if (feature_substitutes_map->has (i, &p))
+ f = *p;
+
+ if (!f->featureParams.is_null () &&
tag == HB_TAG ('s', 'i', 'z', 'e'))
continue;
- if (!f.intersects_lookup_indexes (lookup_indices)
+ if (!f->intersects_lookup_indexes (lookup_indices)
#ifndef HB_NO_VAR
&& !alternate_feature_indices.has (i)
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc
index 44e57987b7..dbb30076a2 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc
@@ -1271,7 +1271,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
hb_set_next (&feature_indexes, &feature_index);)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
- g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
+ g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
}
@@ -1709,6 +1709,8 @@ hb_ot_layout_get_size_params (hb_face_t *face,
return false;
}
+
+
/**
* hb_ot_layout_feature_get_name_ids:
* @face: #hb_face_t to work upon
@@ -2341,6 +2343,7 @@ struct hb_get_glyph_alternates_dispatch_t :
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
};
+#ifndef HB_NO_LAYOUT_RARELY_USED
/**
* hb_ot_layout_lookup_get_glyph_alternates:
* @face: a face.
@@ -2373,4 +2376,72 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
return ret;
}
+
+struct hb_position_single_dispatch_t :
+ hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
+{
+ static return_t default_return_value () { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+
+ private:
+ template <typename T, typename ...Ts> auto
+ _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
+ ( obj.position_single (std::forward<Ts> (ds)...) )
+ template <typename T, typename ...Ts> auto
+ _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
+ ( default_return_value () )
+ public:
+ template <typename T, typename ...Ts> auto
+ dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
+ ( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+};
+
+/**
+ * hb_ot_layout_lookup_get_optical_bound:
+ * @font: a font.
+ * @lookup_index: index of the feature lookup to query.
+ * @direction: edge of the glyph to query.
+ * @glyph: a glyph id.
+ *
+ * Fetches the optical bound of a glyph positioned at the margin of text.
+ * The direction identifies which edge of the glyph to query.
+ *
+ * Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
+ *
+ * Since: 5.3.0
+ **/
+hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
+ unsigned lookup_index,
+ hb_direction_t direction,
+ hb_codepoint_t glyph)
+{
+ const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+ hb_glyph_position_t pos = {0};
+ hb_position_single_dispatch_t c;
+ lookup.dispatch (&c, font, direction, glyph, pos);
+ hb_position_t ret = 0;
+ switch (direction)
+ {
+ case HB_DIRECTION_LTR:
+ ret = pos.x_offset;
+ break;
+ case HB_DIRECTION_RTL:
+ ret = pos.x_advance - pos.x_offset;
+ break;
+ case HB_DIRECTION_TTB:
+ ret = pos.y_offset;
+ break;
+ case HB_DIRECTION_BTT:
+ ret = pos.y_advance - pos.y_offset;
+ break;
+ case HB_DIRECTION_INVALID:
+ default:
+ break;
+ }
+ return ret;
+}
+#endif
+
+
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h
index 4edddd9e0d..f7b488f870 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout.h
+++ b/thirdparty/harfbuzz/src/hb-ot-layout.h
@@ -403,6 +403,16 @@ hb_ot_layout_get_size_params (hb_face_t *face,
unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */);
+HB_EXTERN hb_position_t
+hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
+ unsigned lookup_index,
+ hb_direction_t direction,
+ hb_codepoint_t glyph);
+
+
+/*
+ * GSUB/GPOS
+ */
HB_EXTERN hb_bool_t
hb_ot_layout_feature_get_name_ids (hb_face_t *face,
@@ -423,6 +433,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
unsigned int *char_count /* IN/OUT. May be NULL */,
hb_codepoint_t *characters /* OUT. May be NULL */);
+
/*
* BASE
*/
diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
index 80d02ffba7..59c1de3784 100644
--- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh
@@ -282,7 +282,7 @@ struct post
* 0x00020000 for version 2.0
* 0x00025000 for version 2.5 (deprecated)
* 0x00030000 for version 3.0 */
- HBFixed italicAngle; /* Italic angle in counter-clockwise degrees
+ F16DOT16 italicAngle; /* Italic angle in counter-clockwise degrees
* from the vertical. Zero for upright text,
* negative for text that leans to the right
* (forward). */
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 7f679cfd39..249b5a864c 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -527,18 +527,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
}
#endif
/* Or part of the Other_Grapheme_Extend that is not marks.
- * As of Unicode 11 that is just:
+ * As of Unicode 15 that is just:
*
* 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
* FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
* E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
*
* ZWNJ is special, we don't want to merge it as there's no need, and keeping
- * it separate results in more granular clusters. Ignore Katakana for now.
+ * it separate results in more granular clusters.
* Tags are used for Emoji sub-region flag sequences:
* https://github.com/harfbuzz/harfbuzz/issues/1556
+ * Katakana ones were requested:
+ * https://github.com/harfbuzz/harfbuzz/issues/3844
*/
- else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
+ else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
_hb_glyph_info_set_continuation (&info[i]);
}
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
index 6395d689ae..9833fb55de 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
@@ -25,6 +25,7 @@
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
* # Override values For Indic_Positional_Category
* # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -34,6 +35,7 @@
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
+ * # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
* UnicodeData.txt does not have a header.
*/
@@ -90,7 +92,7 @@
#pragma GCC diagnostic pop
static const uint8_t
-hb_use_u8[3115] =
+hb_use_u8[3141] =
{
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,
@@ -125,11 +127,11 @@ hb_use_u8[3115] =
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, 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,
+ 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 2,
+ 2, 2, 2, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 95, 95, 96, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 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,
@@ -226,70 +228,72 @@ hb_use_u8[3115] =
0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
- 20, 106, 155, 0, 0, 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,
+ 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
- 8, 16, 17, 19, 20, 160, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
+ 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
- 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,
+ 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
+ 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
- 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,
+ 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
+ 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 164, 35, 0,
+ 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
- 2, 21, 21, 16, 30, 31, 10, 166, 167, 168, 169, 0, 0, 0, 0, 0,
+ 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
- 2, 2, 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,
+ 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
+ 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
+ 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
+ 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
- 25, 9, 157, 176, 172, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
+ 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
- 0, 2, 177, 64, 45, 0, 0, 0, 0, 9, 178, 2, 2, 2, 2, 2,
+ 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
- 0, 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,
+ 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
+ 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0,
- 0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B,
- O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
- B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre,
- VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre,
- O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,
- CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv,
- B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O, 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,
- CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B,
- CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst,
- FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,
- VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw,
- FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ,
- O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,
- VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B,
- FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,
- VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre,
- VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, 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,
+ 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
+ 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
+ O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
+ CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
+ VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
+ VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
+ O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
+ VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
+ B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
+ SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
+ MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
+ VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
+ VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
+ B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
+ SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
+ SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
+ CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
+ VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
+ O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
+ VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
+ CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
+ R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
+ H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
+ MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
+ H, B,VMBlw, O, VBlw,
};
static const uint16_t
-hb_use_u16[776] =
+hb_use_u16[784] =
{
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,
@@ -332,14 +336,14 @@ hb_use_u16[776] =
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,
+ 9, 9, 9,254,255,256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 9, 9, 9,257, 0, 0, 0, 0, 9, 9, 9, 9,258,259,260,260,
+ 261,262, 0, 0, 0, 0,263, 0, 9, 9, 9, 9, 9,264, 0, 0,
+ 9, 9, 9, 9, 9, 9,105, 70, 94,265, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,266, 9, 9, 70,267,268, 0, 0, 0,
+ 0, 9,269, 0, 9, 9,270, 2, 0, 0, 0, 0, 0, 9,271, 2,
+ 9, 9, 9, 9,272, 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
@@ -350,7 +354,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[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;
+ return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#undef B
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
index cb4db4a8b2..e76b554b00 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc
@@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
break;
+ case HB_SCRIPT_KHOJKI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur ().codepoint)
+ {
+ case 0x11200u:
+ switch (buffer->cur (1).codepoint)
+ {
+ case 0x1122Cu: case 0x11231u: case 0x11233u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x11206u:
+ matched = 0x1122Cu == buffer->cur (1).codepoint;
+ break;
+ case 0x1122Cu:
+ switch (buffer->cur (1).codepoint)
+ {
+ case 0x11230u: case 0x11231u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x11240u:
+ matched = 0x1122Eu == buffer->cur (1).codepoint;
+ break;
+ }
+ (void) buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ break;
+
case HB_SCRIPT_KHUDAWADI:
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
index d83bf14219..af6d550c0e 100644
--- a/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-stat-table.hh
@@ -136,7 +136,7 @@ struct AxisValueFormat1
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed value; /* A numeric value for this attribute value. */
+ F16DOT16 value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (12);
};
@@ -195,10 +195,10 @@ struct AxisValueFormat2
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed nominalValue; /* A numeric value for this attribute value. */
- HBFixed rangeMinValue; /* The minimum value for a range associated
+ F16DOT16 nominalValue; /* A numeric value for this attribute value. */
+ F16DOT16 rangeMinValue; /* The minimum value for a range associated
* with the specified name ID. */
- HBFixed rangeMaxValue; /* The maximum value for a range associated
+ F16DOT16 rangeMaxValue; /* The maximum value for a range associated
* with the specified name ID. */
public:
DEFINE_SIZE_STATIC (20);
@@ -258,8 +258,8 @@ struct AxisValueFormat3
NameID valueNameID; /* The name ID for entries in the 'name' table
* that provide a display string for this
* attribute value. */
- HBFixed value; /* A numeric value for this attribute value. */
- HBFixed linkedValue; /* The numeric value for a style-linked mapping
+ F16DOT16 value; /* A numeric value for this attribute value. */
+ F16DOT16 linkedValue; /* The numeric value for a style-linked mapping
* from this value. */
public:
DEFINE_SIZE_STATIC (16);
@@ -280,7 +280,7 @@ struct AxisValueRecord
HBUINT16 axisIndex; /* Zero-base index into the axis record array
* identifying the axis to which this value
* applies. Must be less than designAxisCount. */
- HBFixed value; /* A numeric value for this attribute value. */
+ F16DOT16 value; /* A numeric value for this attribute value. */
public:
DEFINE_SIZE_STATIC (6);
};
diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
index b9b49f2287..af23862870 100644
--- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh
@@ -44,9 +44,47 @@ struct InstanceRecord
{
friend struct fvar;
- hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
+ hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
{ return coordinatesZ.as_array (axis_count); }
+ bool subset (hb_subset_context_t *c,
+ unsigned axis_count,
+ bool has_postscript_nameid) const
+ {
+ TRACE_SUBSET (this);
+ if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
+ if (unlikely (!c->serializer->embed (flags))) return_trace (false);
+
+ const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+ const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
+ for (unsigned i = 0 ; i < axis_count; i++)
+ {
+ unsigned *axis_tag;
+ // only keep instances whose coordinates == pinned axis location
+ if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
+
+ if (axes_location->has (*axis_tag) &&
+ fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
+ return_trace (false);
+
+ if (!c->plan->axes_index_map->has (i))
+ continue;
+
+ if (!c->serializer->embed (coords[i]))
+ return_trace (false);
+ }
+
+ if (has_postscript_nameid)
+ {
+ NameID name_id;
+ name_id = StructAfter<NameID> (coords);
+ if (!c->serializer->embed (name_id))
+ return_trace (false);
+ }
+
+ return_trace (true);
+ }
+
bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
{
TRACE_SANITIZE (this);
@@ -58,7 +96,7 @@ struct InstanceRecord
NameID subfamilyNameID;/* The name ID for entries in the 'name' table
* that provide subfamily names for this instance. */
HBUINT16 flags; /* Reserved for future use — set to 0. */
- UnsizedArrayOf<HBFixed>
+ UnsizedArrayOf<F16DOT16>
coordinatesZ; /* The coordinates array for this instance. */
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
// * table that provide PostScript names for this
@@ -151,9 +189,9 @@ struct AxisRecord
public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
protected:
- HBFixed minValue; /* The minimum coordinate value for the axis. */
- HBFixed defaultValue; /* The default coordinate value for the axis. */
- HBFixed maxValue; /* The maximum coordinate value for the axis. */
+ F16DOT16 minValue; /* The minimum coordinate value for the axis. */
+ F16DOT16 defaultValue; /* The default coordinate value for the axis. */
+ F16DOT16 maxValue; /* The maximum coordinate value for the axis. */
public:
HBUINT16 flags; /* Axis flags. */
NameID axisNameID; /* The name ID for entries in the 'name' table that
@@ -268,7 +306,7 @@ struct fvar
if (coords_length && *coords_length)
{
- hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
+ hb_array_t<const F16DOT16> instanceCoords = instance->get_coordinates (axisCount)
.sub_array (0, coords_length);
for (unsigned int i = 0; i < instanceCoords.length; i++)
coords[i] = instanceCoords.arrayZ[i].to_float ();
@@ -301,7 +339,7 @@ struct fvar
if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
| hb_filter (pinned_axes, hb_second)
- | hb_map ([&] (const hb_pair_t<const HBFixed&, unsigned>& _)
+ | hb_map ([&] (const hb_pair_t<const F16DOT16&, unsigned>& _)
{
hb_tag_t axis_tag = pinned_axes.get (_.second);
float location = user_axes_location->get (axis_tag);
@@ -321,6 +359,48 @@ struct fvar
}
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ unsigned retained_axis_count = c->plan->axes_index_map->get_population ();
+ if (!retained_axis_count) //all axes are pinned
+ return_trace (false);
+
+ fvar *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ bool has_postscript_nameid = false;
+ if (instanceSize >= axisCount * 4 + 6)
+ has_postscript_nameid = true;
+
+ if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ auto axes_records = get_axes ();
+ for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
+ {
+ if (!c->plan->axes_index_map->has (i)) continue;
+ if (unlikely (!c->serializer->embed (axes_records[i])))
+ return_trace (false);
+ }
+
+ if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
+ {
+ const InstanceRecord *instance = get_instance (i);
+ auto snap = c->serializer->snapshot ();
+ if (!instance->subset (c, axisCount, has_postscript_nameid))
+ c->serializer->revert (snap);
+ }
+ return_trace (true);
+ }
+
public:
hb_array_t<const AxisRecord> get_axes () const
{ return hb_array (&(this+firstAxis), axisCount); }
@@ -346,8 +426,8 @@ struct fvar
HBUINT16 instanceCount; /* The number of named instances defined in the font
* (the number of records in the instances array). */
HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set
- * to either axisCount * sizeof(HBFixed) + 4, or to
- * axisCount * sizeof(HBFixed) + 6. */
+ * to either axisCount * sizeof(F16DOT16) + 4, or to
+ * axisCount * sizeof(F16DOT16) + 6. */
public:
DEFINE_SIZE_STATIC (16);
diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh
index 40a5326118..c97ce6cc2c 100644
--- a/thirdparty/harfbuzz/src/hb-repacker.hh
+++ b/thirdparty/harfbuzz/src/hb-repacker.hh
@@ -244,7 +244,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
{
// The child object is shared, we may be able to eliminate the overflow
// by duplicating it.
- if (!sorted_graph.duplicate (r.parent, r.child)) continue;
+ if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
return true;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset-accelerator.hh b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
new file mode 100644
index 0000000000..34bd0534fb
--- /dev/null
+++ b/thirdparty/harfbuzz/src/hb-subset-accelerator.hh
@@ -0,0 +1,76 @@
+/*
+ * 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 HB_SUBSET_ACCELERATOR_HH
+#define HB_SUBSET_ACCELERATOR_HH
+
+
+#include "hb.hh"
+
+#include "hb-map.hh"
+#include "hb-set.hh"
+
+struct hb_subset_accelerator_t
+{
+ static hb_user_data_key_t* user_data_key()
+ {
+ static hb_user_data_key_t key;
+ return &key;
+ }
+
+ static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
+ const hb_set_t& unicodes_) {
+ hb_subset_accelerator_t* accel =
+ (hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
+ new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
+ return accel;
+ }
+
+ static void destroy(void* value) {
+ if (!value) return;
+
+ hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
+ accel->~hb_subset_accelerator_t ();
+ hb_free (accel);
+ }
+
+ hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
+ const hb_set_t& unicodes_)
+ : unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
+
+ const hb_map_t unicode_to_gid;
+ const hb_set_t unicodes;
+ // TODO(garretrieger): cumulative glyf checksum map
+ // TODO(garretrieger): sanitized table cache.
+
+ bool in_error () const
+ {
+ return unicode_to_gid.in_error() || unicodes.in_error ();
+ }
+};
+
+
+#endif /* HB_SUBSET_ACCELERATOR_HH */
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc
index 14ae210d49..fd250104bb 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-input.cc
@@ -49,7 +49,7 @@ hb_subset_input_create_or_fail (void)
set = hb_set_create ();
input->axes_location = hb_hashmap_create<hb_tag_t, float> ();
-
+
if (!input->axes_location || input->in_error ())
{
hb_subset_input_destroy (input);
@@ -89,7 +89,6 @@ hb_subset_input_create_or_fail (void)
hb_tag_t default_no_subset_tables[] = {
HB_TAG ('a', 'v', 'a', 'r'),
- HB_TAG ('f', 'v', 'a', 'r'),
HB_TAG ('g', 'a', 's', 'p'),
HB_TAG ('c', 'v', 't', ' '),
HB_TAG ('f', 'p', 'g', 'm'),
@@ -393,7 +392,7 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
*
* Since: EXPERIMENTAL
**/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag)
@@ -417,7 +416,7 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
*
* Since: EXPERIMENTAL
**/
-hb_bool_t
+HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag,
@@ -432,3 +431,51 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
}
#endif
#endif
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_preprocess
+ * @input: a #hb_face_t object.
+ *
+ * Preprocesses the face and attaches data that will be needed by the
+ * subsetter. Future subsetting operations can then use the precomputed data
+ * to speed up the subsetting operation.
+ *
+ * Since: EXPERIMENTAL
+ **/
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source)
+{
+ hb_subset_input_t* input = hb_subset_input_create_or_fail ();
+
+ hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+ hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
+
+ hb_set_clear (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_ID));
+ hb_set_invert (hb_subset_input_set(input,
+ HB_SUBSET_SETS_NAME_ID));
+
+ hb_subset_input_set_flags(input,
+ HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
+ HB_SUBSET_FLAGS_GLYPH_NAMES |
+ HB_SUBSET_FLAGS_RETAIN_GIDS);
+ input->attach_accelerator_data = true;
+
+ hb_face_t* new_source = hb_subset_or_fail (source, input);
+ hb_subset_input_destroy (input);
+
+ return new_source;
+}
+#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-input.hh b/thirdparty/harfbuzz/src/hb-subset-input.hh
index 2335f0634f..dabb4918fe 100644
--- a/thirdparty/harfbuzz/src/hb-subset-input.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-input.hh
@@ -59,6 +59,7 @@ struct hb_subset_input_t
};
unsigned flags;
+ bool attach_accelerator_data = false;
hb_hashmap_t<hb_tag_t, float> *axes_location;
inline unsigned num_sets () const
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc
index 079ab8bf99..9cf7c9e431 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc
@@ -25,6 +25,7 @@
*/
#include "hb-subset-plan.hh"
+#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
#include "hb-set.hh"
@@ -129,7 +130,9 @@ template <typename T>
static void _collect_layout_indices (hb_subset_plan_t *plan,
const T& table,
hb_set_t *lookup_indices, /* OUT */
- hb_set_t *feature_indices /* OUT */)
+ hb_set_t *feature_indices, /* OUT */
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
{
unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features;
@@ -154,16 +157,37 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
retain_all_features ? nullptr : features.arrayZ,
feature_indices);
+#ifndef HB_NO_VAR
+ // collect feature substitutes with variations
+ if (!plan->user_axes_location->is_empty ())
+ {
+ hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
+ OT::hb_collect_feature_substitutes_with_var_context_t c =
+ {
+ plan->axes_old_index_tag_map,
+ plan->axes_location,
+ feature_record_cond_idx_map,
+ feature_substitutes_map,
+ feature_indices,
+ true,
+ 0,
+ &conditionset_map
+ };
+ table.collect_feature_substitutes_with_variations (&c);
+ }
+#endif
+
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);
+ const OT::Feature* f = &(table.get_feature (feature_index));
+ const OT::Feature **p = nullptr;
+ if (feature_substitutes_map->has (feature_index, &p))
+ f = *p;
+
+ 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);
+ table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
}
@@ -171,6 +195,7 @@ static inline void
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
const hb_map_t *lookup_indices,
const hb_set_t *feature_indices,
+ const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
hb_map_t *duplicate_feature_map /* OUT */)
{
if (feature_indices->is_empty ()) return;
@@ -195,16 +220,22 @@ _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
hb_set_t* same_tag_features = unique_features.get (t);
for (unsigned other_f_index : same_tag_features->iter ())
{
- const OT::Feature& f = g.get_feature (i);
- const OT::Feature& other_f = g.get_feature (other_f_index);
+ const OT::Feature* f = &(g.get_feature (i));
+ const OT::Feature **p = nullptr;
+ if (feature_substitutes_map->has (i, &p))
+ f = *p;
+
+ const OT::Feature* other_f = &(g.get_feature (other_f_index));
+ if (feature_substitutes_map->has (other_f_index, &p))
+ f = *p;
auto f_iter =
- + hb_iter (f.lookupIndex)
+ + hb_iter (f->lookupIndex)
| hb_filter (lookup_indices)
;
auto other_f_iter =
- + hb_iter (other_f.lookupIndex)
+ + hb_iter (other_f->lookupIndex)
| hb_filter (lookup_indices)
;
@@ -237,7 +268,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
hb_set_t *gids_to_retain,
hb_map_t *lookups,
hb_map_t *features,
- script_langsys_map *langsys_map)
+ script_langsys_map *langsys_map,
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
{
hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag;
@@ -245,7 +278,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
_collect_layout_indices<T> (plan,
*table,
&lookup_indices,
- &feature_indices);
+ &feature_indices,
+ feature_record_cond_idx_map,
+ feature_substitutes_map);
if (table_tag == HB_OT_TAG_GSUB)
hb_ot_layout_lookups_substitute_closure (plan->source,
@@ -257,9 +292,12 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
_remap_indexes (&lookup_indices, lookups);
// prune features
- table->prune_features (lookups, &feature_indices);
+ table->prune_features (lookups,
+ plan->user_axes_location->is_empty () ? nullptr : feature_record_cond_idx_map,
+ feature_substitutes_map,
+ &feature_indices);
hb_map_t duplicate_feature_map;
- _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map);
+ _GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
feature_indices.clear ();
table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
@@ -419,41 +457,73 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
hb_subset_plan_t *plan)
{
OT::cmap::accelerator_t cmap (plan->source);
-
unsigned size_threshold = plan->source->get_num_glyphs ();
if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
{
+
+ const hb_map_t* unicode_to_gid = nullptr;
+ if (plan->accelerator)
+ unicode_to_gid = &plan->accelerator->unicode_to_gid;
+
// This is approach to collection is faster, but can only be used if glyphs
// are not being explicitly added to the subset and the input unicodes set is
// not excessively large (eg. an inverted set).
plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
- for (hb_codepoint_t cp : *unicodes)
- {
- hb_codepoint_t gid;
- if (!cmap.get_nominal_glyph (cp, &gid))
+ if (!unicode_to_gid) {
+ for (hb_codepoint_t cp : *unicodes)
{
- DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
- continue;
+ hb_codepoint_t gid;
+ if (!cmap.get_nominal_glyph (cp, &gid))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+ continue;
+ }
+
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
+ } else {
+ // Use in memory unicode to gid map it's faster then looking up from
+ // the map. This code is mostly duplicated from above to avoid doing
+ // conditionals on the presence of the unicode_to_gid map each
+ // iteration.
+ for (hb_codepoint_t cp : *unicodes)
+ {
+ hb_codepoint_t gid = unicode_to_gid->get (cp);
+ if (gid == HB_MAP_VALUE_INVALID)
+ {
+ DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
+ continue;
+ }
+
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
-
- plan->codepoint_to_glyph->set (cp, gid);
- plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
}
else
{
// This approach is slower, but can handle adding in glyphs to the subset and will match
// them with cmap entries.
- hb_map_t unicode_glyphid_map;
- hb_set_t cmap_unicodes;
- cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map);
- plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
- + glyphs->get_population (),
- cmap_unicodes.get_population ()));
-
- for (hb_codepoint_t cp : cmap_unicodes)
+
+ hb_map_t unicode_glyphid_map_storage;
+ hb_set_t cmap_unicodes_storage;
+ const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
+ const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
+
+ if (!plan->accelerator) {
+ cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
+ plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
+ + glyphs->get_population (),
+ cmap_unicodes->get_population ()));
+ } else {
+ unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
+ cmap_unicodes = &plan->accelerator->unicodes;
+ }
+
+ for (hb_codepoint_t cp : *cmap_unicodes)
{
- hb_codepoint_t gid = unicode_glyphid_map[cp];
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
if (!unicodes->has (cp) && !glyphs->has (gid))
continue;
@@ -509,9 +579,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
- bool close_over_gsub,
- bool close_over_gpos,
- bool close_over_gdef)
+ hb_set_t* drop_tables)
{
OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF
@@ -523,32 +591,42 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
#ifndef HB_NO_SUBSET_LAYOUT
- if (close_over_gsub)
+ if (!drop_tables->has (HB_OT_TAG_GSUB))
// closure all glyphs/lookups/features needed for GSUB substitutions.
_closure_glyphs_lookups_features<GSUB> (
plan,
plan->_glyphset_gsub,
plan->gsub_lookups,
plan->gsub_features,
- plan->gsub_langsys);
+ plan->gsub_langsys,
+ plan->gsub_feature_record_cond_idx_map,
+ plan->gsub_feature_substitutes_map);
- if (close_over_gpos)
+ if (!drop_tables->has (HB_OT_TAG_GPOS))
_closure_glyphs_lookups_features<GPOS> (
plan,
plan->_glyphset_gsub,
plan->gpos_lookups,
plan->gpos_features,
- plan->gpos_langsys);
+ plan->gpos_langsys,
+ plan->gpos_feature_record_cond_idx_map,
+ plan->gpos_feature_substitutes_map);
#endif
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
- _math_closure (plan, plan->_glyphset_mathed);
- _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+ if (!drop_tables->has (HB_OT_TAG_MATH))
+ {
+ _math_closure (plan, plan->_glyphset_mathed);
+ _remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
+ }
hb_set_t cur_glyphset = *plan->_glyphset_mathed;
- _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
- _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
+ if (!drop_tables->has (HB_OT_TAG_COLR))
+ {
+ _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
+ _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
+ }
hb_set_set (plan->_glyphset_colred, &cur_glyphset);
@@ -570,7 +648,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
#ifndef HB_NO_VAR
- if (close_over_gdef)
+ if (!drop_tables->has (HB_OT_TAG_GDEF))
_collect_layout_variation_indices (plan);
#endif
}
@@ -659,18 +737,22 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
seg_maps = face->table.avar->get_segment_maps ();
bool axis_not_pinned = false;
- unsigned axis_count = 0;
+ unsigned old_axis_idx = 0, new_axis_idx = 0;
for (const auto& axis : axes)
{
hb_tag_t axis_tag = axis.get_axis_tag ();
+ plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag);
+
if (!plan->user_axes_location->has (axis_tag))
{
axis_not_pinned = true;
+ plan->axes_index_map->set (old_axis_idx, new_axis_idx);
+ new_axis_idx++;
}
else
{
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 ())
+ if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
{
normalized_v = seg_maps->map (normalized_v);
}
@@ -681,7 +763,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
if (has_avar)
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
- axis_count++;
+ old_axis_idx++;
}
plan->all_axes_pinned = !axis_not_pinned;
}
@@ -741,6 +823,13 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->gsub_features = hb_map_create ();
plan->gpos_features = hb_map_create ();
+
+ plan->check_success (plan->gsub_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+ plan->check_success (plan->gpos_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
+
+ plan->check_success (plan->gsub_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+ plan->check_success (plan->gpos_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
+
plan->colrv1_layers = hb_map_create ();
plan->colr_palettes = hb_map_create ();
plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
@@ -751,12 +840,21 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
if (plan->user_axes_location && input->axes_location)
*plan->user_axes_location = *input->axes_location;
+ plan->check_success (plan->axes_index_map = hb_map_create ());
+ plan->check_success (plan->axes_old_index_tag_map = hb_map_create ());
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>> ());
+ void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
+
+ plan->attach_accelerator_data = input->attach_accelerator_data;
+ if (accel)
+ plan->accelerator = (hb_subset_accelerator_t*) accel;
+
+
if (unlikely (plan->in_error ())) {
hb_subset_plan_destroy (plan);
return nullptr;
@@ -768,10 +866,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
- _populate_gids_to_retain (plan,
- !input->sets.drop_tables->has (HB_OT_TAG_GSUB),
- !input->sets.drop_tables->has (HB_OT_TAG_GPOS),
- !input->sets.drop_tables->has (HB_OT_TAG_GDEF));
+ _populate_gids_to_retain (plan, input->sets.drop_tables);
_create_old_gid_to_new_gid_map (face,
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh
index 98a45e5f6d..15fabba9c3 100644
--- a/thirdparty/harfbuzz/src/hb-subset-plan.hh
+++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh
@@ -31,11 +31,16 @@
#include "hb-subset.h"
#include "hb-subset-input.hh"
+#include "hb-subset-accelerator.hh"
#include "hb-map.hh"
#include "hb-bimap.hh"
#include "hb-set.hh"
+namespace OT {
+struct Feature;
+}
+
struct hb_subset_plan_t
{
hb_subset_plan_t ()
@@ -67,9 +72,15 @@ struct hb_subset_plan_t
hb_map_destroy (gpos_features);
hb_map_destroy (colrv1_layers);
hb_map_destroy (colr_palettes);
+ hb_map_destroy (axes_index_map);
+ hb_map_destroy (axes_old_index_tag_map);
hb_hashmap_destroy (gsub_langsys);
hb_hashmap_destroy (gpos_langsys);
+ hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
+ hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
+ hb_hashmap_destroy (gsub_feature_substitutes_map);
+ hb_hashmap_destroy (gpos_feature_substitutes_map);
hb_hashmap_destroy (axes_location);
hb_hashmap_destroy (sanitized_table_cache);
hb_hashmap_destroy (hmtx_map);
@@ -87,6 +98,7 @@ struct hb_subset_plan_t
bool successful;
unsigned flags;
+ bool attach_accelerator_data = false;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
@@ -143,6 +155,15 @@ struct hb_subset_plan_t
hb_map_t *gsub_features;
hb_map_t *gpos_features;
+ //active feature variation records/condition index with variations
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
+ hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
+
+ //feature index-> address of substituation feature table mapping with
+ //variations
+ hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
+ hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
+
//active layers/palettes we'd like to retain
hb_map_t *colrv1_layers;
hb_map_t *colr_palettes;
@@ -158,6 +179,10 @@ struct hb_subset_plan_t
hb_hashmap_t<hb_tag_t, int> *axes_location;
//user specified axes location map
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
+ //retained old axis index -> new axis index mapping in fvar axis array
+ hb_map_t *axes_index_map;
+ //axis_index->axis_tag mapping in fvar axis array
+ hb_map_t *axes_old_index_tag_map;
bool all_axes_pinned;
bool pinned_at_default;
@@ -166,6 +191,8 @@ struct hb_subset_plan_t
//vmtx metrics map: new gid->(advance, lsb)
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
+ const hb_subset_accelerator_t* accelerator;
+
public:
template<typename T>
diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc
index 1a0bcbd1fe..6026aa6eff 100644
--- a/thirdparty/harfbuzz/src/hb-subset.cc
+++ b/thirdparty/harfbuzz/src/hb-subset.cc
@@ -50,11 +50,13 @@
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-gvar-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-math-table.hh"
#include "hb-ot-stat-table.hh"
#include "hb-repacker.hh"
+#include "hb-subset-accelerator.hh"
using OT::Layout::GSUB;
using OT::Layout::GPOS;
@@ -475,6 +477,9 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
#endif
+ case HB_OT_TAG_fvar:
+ if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
+ return _subset<const OT::fvar> (plan, buf);
case HB_OT_TAG_STAT:
/*TODO(qxliu): change the condition as we support more complex
* instancing operation*/
@@ -490,6 +495,27 @@ _subset_table (hb_subset_plan_t *plan,
}
}
+static void _attach_accelerator_data (const hb_subset_plan_t* plan,
+ hb_face_t* face /* IN/OUT */)
+{
+ hb_subset_accelerator_t* accel =
+ hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
+ *plan->unicodes);
+
+ if (accel->in_error ())
+ {
+ hb_subset_accelerator_t::destroy (accel);
+ return;
+ }
+
+ if (!hb_face_set_user_data(face,
+ hb_subset_accelerator_t::user_data_key(),
+ accel,
+ hb_subset_accelerator_t::destroy,
+ true))
+ hb_subset_accelerator_t::destroy (accel);
+}
+
/**
* hb_subset_or_fail:
* @source: font face data to be subset.
@@ -572,6 +598,10 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
offset += num_tables;
}
+ if (success && plan->attach_accelerator_data) {
+ _attach_accelerator_data (plan, plan->dest);
+ }
+
end:
return success ? hb_face_reference (plan->dest) : nullptr;
}
diff --git a/thirdparty/harfbuzz/src/hb-subset.h b/thirdparty/harfbuzz/src/hb-subset.h
index 08e52dbd2d..6a2c5f6114 100644
--- a/thirdparty/harfbuzz/src/hb-subset.h
+++ b/thirdparty/harfbuzz/src/hb-subset.h
@@ -70,6 +70,14 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified
+ * to produce a subset that is better suited to patching. For example cmap
+ * subtable format will be kept stable.
+ * @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final
+ * glyf table bytes. The table directory will include and entry as if the table was
+ * there but the actual final font blob will be truncated prior to the glyf data. This
+ * is a useful performance optimization when a font aware binary patching algorithm
+ * is being used to diff two subsets.
*
* List of boolean properties that can be configured on the subset input.
*
@@ -86,6 +94,8 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
+ // Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u,
+ // Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000400u,
} hb_subset_flags_t;
/**
@@ -169,6 +179,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
#endif
#endif
+#ifdef HB_EXPERIMENTAL_API
+
+HB_EXTERN hb_face_t *
+hb_subset_preprocess (hb_face_t *source);
+
+#endif
+
HB_EXTERN hb_face_t *
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index fa7403cae7..8d6ec66e13 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -47,20 +47,20 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 2
+#define HB_VERSION_MINOR 3
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 0
+#define HB_VERSION_MICRO 1
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "5.2.0"
+#define HB_VERSION_STRING "5.3.1"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/icu4c/common/appendable.cpp b/thirdparty/icu4c/common/appendable.cpp
index fca3c1e413..f9b20180eb 100644
--- a/thirdparty/icu4c/common/appendable.cpp
+++ b/thirdparty/icu4c/common/appendable.cpp
@@ -37,23 +37,23 @@ Appendable::appendString(const UChar *s, int32_t length) {
UChar c;
while((c=*s++)!=0) {
if(!appendCodeUnit(c)) {
- return FALSE;
+ return false;
}
}
} else if(length>0) {
const UChar *limit=s+length;
do {
if(!appendCodeUnit(*s++)) {
- return FALSE;
+ return false;
}
} while(s<limit);
}
- return TRUE;
+ return true;
}
UBool
Appendable::reserveAppendCapacity(int32_t /*appendCapacity*/) {
- return TRUE;
+ return true;
}
UChar *
diff --git a/thirdparty/icu4c/common/bmpset.cpp b/thirdparty/icu4c/common/bmpset.cpp
index bc79f5e5a6..14ab894267 100644
--- a/thirdparty/icu4c/common/bmpset.cpp
+++ b/thirdparty/icu4c/common/bmpset.cpp
@@ -309,9 +309,9 @@ BMPSet::contains(UChar32 c) const {
// surrogate or supplementary code point
return containsSlow(c, list4kStarts[0xd], list4kStarts[0x11]);
} else {
- // Out-of-range code points get FALSE, consistent with long-standing
+ // Out-of-range code points get false, consistent with long-standing
// behavior of UnicodeSet::contains(c).
- return FALSE;
+ return false;
}
}
diff --git a/thirdparty/icu4c/common/brkeng.cpp b/thirdparty/icu4c/common/brkeng.cpp
index dc9fb99bf1..bd6abbb55a 100644
--- a/thirdparty/icu4c/common/brkeng.cpp
+++ b/thirdparty/icu4c/common/brkeng.cpp
@@ -261,10 +261,10 @@ ICULanguageBreakFactory::loadDictionaryMatcherFor(UScriptCode script) {
const UChar *extStart = u_memrchr(dictfname, 0x002e, dictnlength); // last dot
if (extStart != NULL) {
int32_t len = (int32_t)(extStart - dictfname);
- ext.appendInvariantChars(UnicodeString(FALSE, extStart + 1, dictnlength - len - 1), status);
+ ext.appendInvariantChars(UnicodeString(false, extStart + 1, dictnlength - len - 1), status);
dictnlength = len;
}
- dictnbuf.appendInvariantChars(UnicodeString(FALSE, dictfname, dictnlength), status);
+ dictnbuf.appendInvariantChars(UnicodeString(false, dictfname, dictnlength), status);
ures_close(b);
UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext.data(), dictnbuf.data(), &status);
diff --git a/thirdparty/icu4c/common/brkiter.cpp b/thirdparty/icu4c/common/brkiter.cpp
index 8a1915880e..d6996734e3 100644
--- a/thirdparty/icu4c/common/brkiter.cpp
+++ b/thirdparty/icu4c/common/brkiter.cpp
@@ -279,7 +279,7 @@ ICUBreakIteratorService::~ICUBreakIteratorService() {}
// defined in ucln_cmn.h
U_NAMESPACE_END
-static icu::UInitOnce gInitOnceBrkiter = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gInitOnceBrkiter {};
static icu::ICULocaleService* gService = NULL;
@@ -296,7 +296,7 @@ static UBool U_CALLCONV breakiterator_cleanup(void) {
}
gInitOnceBrkiter.reset();
#endif
- return TRUE;
+ return true;
}
U_CDECL_END
U_NAMESPACE_BEGIN
@@ -347,7 +347,7 @@ BreakIterator::unregister(URegistryKey key, UErrorCode& status)
}
status = U_MEMORY_ALLOCATION_ERROR;
}
- return FALSE;
+ return false;
}
// -------------------------------------
diff --git a/thirdparty/icu4c/common/bytesinkutil.cpp b/thirdparty/icu4c/common/bytesinkutil.cpp
index c64a845f87..a32254a7db 100644
--- a/thirdparty/icu4c/common/bytesinkutil.cpp
+++ b/thirdparty/icu4c/common/bytesinkutil.cpp
@@ -20,7 +20,7 @@ U_NAMESPACE_BEGIN
UBool
ByteSinkUtil::appendChange(int32_t length, const char16_t *s16, int32_t s16Length,
ByteSink &sink, Edits *edits, UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
char scratch[200];
int32_t s8Length = 0;
for (int32_t i = 0; i < s16Length;) {
@@ -44,7 +44,7 @@ ByteSinkUtil::appendChange(int32_t length, const char16_t *s16, int32_t s16Lengt
}
if (j > (INT32_MAX - s8Length)) {
errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
- return FALSE;
+ return false;
}
sink.Append(buffer, j);
s8Length += j;
@@ -52,17 +52,17 @@ ByteSinkUtil::appendChange(int32_t length, const char16_t *s16, int32_t s16Lengt
if (edits != nullptr) {
edits->addReplace(length, s8Length);
}
- return TRUE;
+ return true;
}
UBool
ByteSinkUtil::appendChange(const uint8_t *s, const uint8_t *limit,
const char16_t *s16, int32_t s16Length,
ByteSink &sink, Edits *edits, UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
if ((limit - s) > INT32_MAX) {
errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
- return FALSE;
+ return false;
}
return appendChange((int32_t)(limit - s), s16, s16Length, sink, edits, errorCode);
}
@@ -109,16 +109,16 @@ UBool
ByteSinkUtil::appendUnchanged(const uint8_t *s, const uint8_t *limit,
ByteSink &sink, uint32_t options, Edits *edits,
UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
if ((limit - s) > INT32_MAX) {
errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
- return FALSE;
+ return false;
}
int32_t length = (int32_t)(limit - s);
if (length > 0) {
appendNonEmptyUnchanged(s, length, sink, options, edits);
}
- return TRUE;
+ return true;
}
CharStringByteSink::CharStringByteSink(CharString* dest) : dest_(*dest) {
diff --git a/thirdparty/icu4c/common/bytesinkutil.h b/thirdparty/icu4c/common/bytesinkutil.h
index ab2516432d..929c71fbee 100644
--- a/thirdparty/icu4c/common/bytesinkutil.h
+++ b/thirdparty/icu4c/common/bytesinkutil.h
@@ -4,6 +4,9 @@
// bytesinkutil.h
// created: 2017sep14 Markus W. Scherer
+#ifndef BYTESINKUTIL_H
+#define BYTESINKUTIL_H
+
#include "unicode/utypes.h"
#include "unicode/bytestream.h"
#include "unicode/edits.h"
@@ -81,3 +84,5 @@ private:
};
U_NAMESPACE_END
+
+#endif //BYTESINKUTIL_H
diff --git a/thirdparty/icu4c/common/bytestream.cpp b/thirdparty/icu4c/common/bytestream.cpp
index 0d0e4dda39..c14f206dfe 100644
--- a/thirdparty/icu4c/common/bytestream.cpp
+++ b/thirdparty/icu4c/common/bytestream.cpp
@@ -30,14 +30,14 @@ void ByteSink::Flush() {}
CheckedArrayByteSink::CheckedArrayByteSink(char* outbuf, int32_t capacity)
: outbuf_(outbuf), capacity_(capacity < 0 ? 0 : capacity),
- size_(0), appended_(0), overflowed_(FALSE) {
+ size_(0), appended_(0), overflowed_(false) {
}
CheckedArrayByteSink::~CheckedArrayByteSink() {}
CheckedArrayByteSink& CheckedArrayByteSink::Reset() {
size_ = appended_ = 0;
- overflowed_ = FALSE;
+ overflowed_ = false;
return *this;
}
@@ -48,14 +48,14 @@ void CheckedArrayByteSink::Append(const char* bytes, int32_t n) {
if (n > (INT32_MAX - appended_)) {
// TODO: Report as integer overflow, not merely buffer overflow.
appended_ = INT32_MAX;
- overflowed_ = TRUE;
+ overflowed_ = true;
return;
}
appended_ += n;
int32_t available = capacity_ - size_;
if (n > available) {
n = available;
- overflowed_ = TRUE;
+ overflowed_ = true;
}
if (n > 0 && bytes != (outbuf_ + size_)) {
uprv_memcpy(outbuf_ + size_, bytes, n);
diff --git a/thirdparty/icu4c/common/bytestrie.cpp b/thirdparty/icu4c/common/bytestrie.cpp
index c4d498c4bf..c272cc4022 100644
--- a/thirdparty/icu4c/common/bytestrie.cpp
+++ b/thirdparty/icu4c/common/bytestrie.cpp
@@ -337,13 +337,13 @@ BytesTrie::findUniqueValueFromBranch(const uint8_t *pos, int32_t length,
}
} else {
uniqueValue=value;
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
} else {
if(!findUniqueValue(pos+value, haveUniqueValue, uniqueValue)) {
return NULL;
}
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
} while(--length>1);
return pos+1; // ignore the last comparison byte
@@ -359,9 +359,9 @@ BytesTrie::findUniqueValue(const uint8_t *pos, UBool haveUniqueValue, int32_t &u
}
pos=findUniqueValueFromBranch(pos, node+1, haveUniqueValue, uniqueValue);
if(pos==NULL) {
- return FALSE;
+ return false;
}
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
} else if(node<kMinValueLead) {
// linear-match node
pos+=node-kMinLinearMatch+1; // Ignore the match bytes.
@@ -370,14 +370,14 @@ BytesTrie::findUniqueValue(const uint8_t *pos, UBool haveUniqueValue, int32_t &u
int32_t value=readValue(pos, node>>1);
if(haveUniqueValue) {
if(value!=uniqueValue) {
- return FALSE;
+ return false;
}
} else {
uniqueValue=value;
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
if(isFinal) {
- return TRUE;
+ return true;
}
pos=skipValue(pos, node);
}
diff --git a/thirdparty/icu4c/common/bytestriebuilder.cpp b/thirdparty/icu4c/common/bytestriebuilder.cpp
index 82dad42ca5..ac7d3d867e 100644
--- a/thirdparty/icu4c/common/bytestriebuilder.cpp
+++ b/thirdparty/icu4c/common/bytestriebuilder.cpp
@@ -231,7 +231,7 @@ BytesTrieBuilder::buildBytes(UStringTrieBuildOption buildOption, UErrorCode &err
}
uprv_sortArray(elements, elementsLength, (int32_t)sizeof(BytesTrieElement),
compareElementStrings, strings,
- FALSE, // need not be a stable sort
+ false, // need not be a stable sort
&errorCode);
if(U_FAILURE(errorCode)) {
return;
@@ -375,7 +375,7 @@ BytesTrieBuilder::createLinearMatchNode(int32_t i, int32_t byteIndex, int32_t le
UBool
BytesTrieBuilder::ensureCapacity(int32_t length) {
if(bytes==NULL) {
- return FALSE; // previous memory allocation had failed
+ return false; // previous memory allocation had failed
}
if(length>bytesCapacity) {
int32_t newCapacity=bytesCapacity;
@@ -388,7 +388,7 @@ BytesTrieBuilder::ensureCapacity(int32_t length) {
uprv_free(bytes);
bytes=NULL;
bytesCapacity=0;
- return FALSE;
+ return false;
}
uprv_memcpy(newBytes+(newCapacity-bytesLength),
bytes+(bytesCapacity-bytesLength), bytesLength);
@@ -396,7 +396,7 @@ BytesTrieBuilder::ensureCapacity(int32_t length) {
bytes=newBytes;
bytesCapacity=newCapacity;
}
- return TRUE;
+ return true;
}
int32_t
@@ -463,7 +463,7 @@ int32_t
BytesTrieBuilder::writeValueAndType(UBool hasValue, int32_t value, int32_t node) {
int32_t offset=write(node);
if(hasValue) {
- offset=writeValueAndFinal(value, FALSE);
+ offset=writeValueAndFinal(value, false);
}
return offset;
}
diff --git a/thirdparty/icu4c/common/bytestrieiterator.cpp b/thirdparty/icu4c/common/bytestrieiterator.cpp
index e64961a1f1..eacb7eedb0 100644
--- a/thirdparty/icu4c/common/bytestrieiterator.cpp
+++ b/thirdparty/icu4c/common/bytestrieiterator.cpp
@@ -101,12 +101,12 @@ BytesTrie::Iterator::hasNext() const { return pos_!=NULL || !stack_->isEmpty();
UBool
BytesTrie::Iterator::next(UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
const uint8_t *pos=pos_;
if(pos==NULL) {
if(stack_->isEmpty()) {
- return FALSE;
+ return false;
}
// Pop the state off the stack and continue with the next outbound edge of
// the branch node.
@@ -119,7 +119,7 @@ BytesTrie::Iterator::next(UErrorCode &errorCode) {
if(length>1) {
pos=branchNext(pos, length, errorCode);
if(pos==NULL) {
- return TRUE; // Reached a final value.
+ return true; // Reached a final value.
}
} else {
str_->append((char)*pos++, errorCode);
@@ -141,7 +141,7 @@ BytesTrie::Iterator::next(UErrorCode &errorCode) {
} else {
pos_=skipValue(pos, node);
}
- return TRUE;
+ return true;
}
if(maxLength_>0 && str_->length()==maxLength_) {
return truncateAndStop();
@@ -152,7 +152,7 @@ BytesTrie::Iterator::next(UErrorCode &errorCode) {
}
pos=branchNext(pos, node+1, errorCode);
if(pos==NULL) {
- return TRUE; // Reached a final value.
+ return true; // Reached a final value.
}
} else {
// Linear-match node, append length bytes to str_.
@@ -177,7 +177,7 @@ UBool
BytesTrie::Iterator::truncateAndStop() {
pos_=NULL;
value_=-1; // no real value for str
- return TRUE;
+ return true;
}
// Branch node, needs to take the first outbound edge and push state for the rest.
diff --git a/thirdparty/icu4c/common/caniter.cpp b/thirdparty/icu4c/common/caniter.cpp
index a2083afde3..81f17265fb 100644
--- a/thirdparty/icu4c/common/caniter.cpp
+++ b/thirdparty/icu4c/common/caniter.cpp
@@ -119,7 +119,7 @@ UnicodeString CanonicalIterator::getSource() {
* Resets the iterator so that one can start again from the beginning.
*/
void CanonicalIterator::reset() {
- done = FALSE;
+ done = false;
for (int i = 0; i < current_length; ++i) {
current[i] = 0;
}
@@ -151,7 +151,7 @@ UnicodeString CanonicalIterator::next() {
for (i = current_length - 1; ; --i) {
if (i < 0) {
- done = TRUE;
+ done = true;
break;
}
current[i]++;
@@ -176,7 +176,7 @@ void CanonicalIterator::setSource(const UnicodeString &newSource, UErrorCode &st
if(U_FAILURE(status)) {
return;
}
- done = FALSE;
+ done = false;
cleanPieces();
@@ -521,7 +521,7 @@ Hashtable *CanonicalIterator::extract(Hashtable *fillinResult, UChar32 comp, con
int32_t decompLen=decompString.length();
// See if it matches the start of segment (at segmentPos)
- UBool ok = FALSE;
+ UBool ok = false;
UChar32 cp;
int32_t decompPos = 0;
UChar32 decompCp;
@@ -537,7 +537,7 @@ Hashtable *CanonicalIterator::extract(Hashtable *fillinResult, UChar32 comp, con
if (decompPos == decompLen) { // done, have all decomp characters!
temp.append(segment+i, segLen-i);
- ok = TRUE;
+ ok = true;
break;
}
U16_NEXT(decomp, decompPos, decompLen, decompCp);
diff --git a/thirdparty/icu4c/common/characterproperties.cpp b/thirdparty/icu4c/common/characterproperties.cpp
index a84996b47c..2316a391a3 100644
--- a/thirdparty/icu4c/common/characterproperties.cpp
+++ b/thirdparty/icu4c/common/characterproperties.cpp
@@ -36,11 +36,11 @@ namespace {
UBool U_CALLCONV characterproperties_cleanup();
-constexpr int32_t NUM_INCLUSIONS = UPROPS_SRC_COUNT + UCHAR_INT_LIMIT - UCHAR_INT_START;
+constexpr int32_t NUM_INCLUSIONS = UPROPS_SRC_COUNT + (UCHAR_INT_LIMIT - UCHAR_INT_START);
struct Inclusion {
UnicodeSet *fSet = nullptr;
- UInitOnce fInitOnce = U_INITONCE_INITIALIZER;
+ UInitOnce fInitOnce {};
};
Inclusion gInclusions[NUM_INCLUSIONS]; // cached getInclusions()
@@ -85,7 +85,7 @@ UBool U_CALLCONV characterproperties_cleanup() {
ucptrie_close(reinterpret_cast<UCPTrie *>(maps[i]));
maps[i] = nullptr;
}
- return TRUE;
+ return true;
}
void U_CALLCONV initInclusion(UPropertySource src, UErrorCode &errorCode) {
@@ -210,7 +210,7 @@ const UnicodeSet *getInclusionsForSource(UPropertySource src, UErrorCode &errorC
void U_CALLCONV initIntPropInclusion(UProperty prop, UErrorCode &errorCode) {
// This function is invoked only via umtx_initOnce().
U_ASSERT(UCHAR_INT_START <= prop && prop < UCHAR_INT_LIMIT);
- int32_t inclIndex = UPROPS_SRC_COUNT + prop - UCHAR_INT_START;
+ int32_t inclIndex = UPROPS_SRC_COUNT + (prop - UCHAR_INT_START);
U_ASSERT(gInclusions[inclIndex].fSet == nullptr);
UPropertySource src = uprops_getSource(prop);
const UnicodeSet *incl = getInclusionsForSource(src, errorCode);
@@ -255,7 +255,7 @@ const UnicodeSet *CharacterProperties::getInclusionsForProperty(
UProperty prop, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return nullptr; }
if (UCHAR_INT_START <= prop && prop < UCHAR_INT_LIMIT) {
- int32_t inclIndex = UPROPS_SRC_COUNT + prop - UCHAR_INT_START;
+ int32_t inclIndex = UPROPS_SRC_COUNT + (prop - UCHAR_INT_START);
Inclusion &i = gInclusions[inclIndex];
umtx_initOnce(i.fInitOnce, &initIntPropInclusion, prop, errorCode);
return i.fSet;
diff --git a/thirdparty/icu4c/common/charstr.cpp b/thirdparty/icu4c/common/charstr.cpp
index c35622882c..8a0994c737 100644
--- a/thirdparty/icu4c/common/charstr.cpp
+++ b/thirdparty/icu4c/common/charstr.cpp
@@ -220,7 +220,7 @@ UBool CharString::ensureCapacity(int32_t capacity,
int32_t desiredCapacityHint,
UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
if(capacity>buffer.getCapacity()) {
if(desiredCapacityHint==0) {
@@ -230,10 +230,10 @@ UBool CharString::ensureCapacity(int32_t capacity,
buffer.resize(capacity, len+1)==NULL
) {
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
diff --git a/thirdparty/icu4c/common/charstr.h b/thirdparty/icu4c/common/charstr.h
index 175acd1c0a..92a75d3d2f 100644
--- a/thirdparty/icu4c/common/charstr.h
+++ b/thirdparty/icu4c/common/charstr.h
@@ -177,8 +177,8 @@ private:
UBool ensureCapacity(int32_t capacity, int32_t desiredCapacityHint, UErrorCode &errorCode);
- CharString(const CharString &other); // forbid copying of this class
- CharString &operator=(const CharString &other); // forbid copying of this class
+ CharString(const CharString &other) = delete; // forbid copying of this class
+ CharString &operator=(const CharString &other) = delete; // forbid copying of this class
/**
* Returns U_FILE_ALT_SEP_CHAR if found in string, and U_FILE_SEP_CHAR is not found.
diff --git a/thirdparty/icu4c/common/cmemory.cpp b/thirdparty/icu4c/common/cmemory.cpp
index 663c1411e4..64f5034921 100644
--- a/thirdparty/icu4c/common/cmemory.cpp
+++ b/thirdparty/icu4c/common/cmemory.cpp
@@ -134,5 +134,5 @@ U_CFUNC UBool cmemory_cleanup(void) {
pAlloc = NULL;
pRealloc = NULL;
pFree = NULL;
- return TRUE;
+ return true;
}
diff --git a/thirdparty/icu4c/common/cstr.h b/thirdparty/icu4c/common/cstr.h
index c7a77a0ae5..be21d910bb 100644
--- a/thirdparty/icu4c/common/cstr.h
+++ b/thirdparty/icu4c/common/cstr.h
@@ -51,8 +51,8 @@ class U_COMMON_API CStr : public UMemory {
private:
CharString s;
- CStr(const CStr &other); // Forbid copying of this class.
- CStr &operator =(const CStr &other); // Forbid assignment.
+ CStr(const CStr &other) = delete; // Forbid copying of this class.
+ CStr &operator =(const CStr &other) = delete; // Forbid assignment.
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/dictbe.cpp b/thirdparty/icu4c/common/dictbe.cpp
index 4fdbdf2760..768eb49b95 100644
--- a/thirdparty/icu4c/common/dictbe.cpp
+++ b/thirdparty/icu4c/common/dictbe.cpp
@@ -119,7 +119,7 @@ public:
// Select the currently marked candidate, point after it in the text, and invalidate self
int32_t acceptMarked( UText *text );
- // Back up from the current candidate to the next shorter one; return TRUE if that exists
+ // Back up from the current candidate to the next shorter one; return true if that exists
// and point the text after it
UBool backUp( UText *text );
@@ -165,9 +165,9 @@ UBool
PossibleWord::backUp( UText *text ) {
if (current > 0) {
utext_setNativeIndex(text, offset + cuLengths[--current]);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -1146,7 +1146,7 @@ CjkBreakEngine::divideUpDictionaryRange( UText *inText,
// Input UText is in one contiguous UTF-16 chunk.
// Use Read-only aliasing UnicodeString.
- inString.setTo(FALSE,
+ inString.setTo(false,
inText->chunkContents + rangeStart - inText->chunkNativeStart,
rangeEnd - rangeStart);
} else {
diff --git a/thirdparty/icu4c/common/edits.cpp b/thirdparty/icu4c/common/edits.cpp
index 92ca36fb5d..21d7c3f006 100644
--- a/thirdparty/icu4c/common/edits.cpp
+++ b/thirdparty/icu4c/common/edits.cpp
@@ -221,7 +221,7 @@ UBool Edits::growArray() {
// Not U_BUFFER_OVERFLOW_ERROR because that could be confused on a string transform API
// with a result-string-buffer overflow.
errorCode_ = U_INDEX_OUTOFBOUNDS_ERROR;
- return FALSE;
+ return false;
} else if (capacity >= (INT32_MAX / 2)) {
newCapacity = INT32_MAX;
} else {
@@ -230,25 +230,25 @@ UBool Edits::growArray() {
// Grow by at least 5 units so that a maximal change record will fit.
if ((newCapacity - capacity) < 5) {
errorCode_ = U_INDEX_OUTOFBOUNDS_ERROR;
- return FALSE;
+ return false;
}
uint16_t *newArray = (uint16_t *)uprv_malloc((size_t)newCapacity * 2);
if (newArray == NULL) {
errorCode_ = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
uprv_memcpy(newArray, array, (size_t)length * 2);
releaseArray();
array = newArray;
capacity = newCapacity;
- return TRUE;
+ return true;
}
UBool Edits::copyErrorTo(UErrorCode &outErrorCode) const {
- if (U_FAILURE(outErrorCode)) { return TRUE; }
- if (U_SUCCESS(errorCode_)) { return FALSE; }
+ if (U_FAILURE(outErrorCode)) { return true; }
+ if (U_SUCCESS(errorCode_)) { return false; }
outErrorCode = errorCode_;
- return TRUE;
+ return true;
}
Edits &Edits::mergeAndAppend(const Edits &ab, const Edits &bc, UErrorCode &errorCode) {
@@ -257,7 +257,7 @@ Edits &Edits::mergeAndAppend(const Edits &ab, const Edits &bc, UErrorCode &error
// Parallel iteration over both Edits.
Iterator abIter = ab.getFineIterator();
Iterator bcIter = bc.getFineIterator();
- UBool abHasNext = TRUE, bcHasNext = TRUE;
+ UBool abHasNext = true, bcHasNext = true;
// Copy iterator state into local variables, so that we can modify and subdivide spans.
// ab old & new length, bc old & new length
int32_t aLength = 0, ab_bLength = 0, bc_bLength = 0, cLength = 0;
@@ -400,7 +400,7 @@ Edits &Edits::mergeAndAppend(const Edits &ab, const Edits &bc, UErrorCode &error
Edits::Iterator::Iterator(const uint16_t *a, int32_t len, UBool oc, UBool crs) :
array(a), index(0), length(len), remaining(0),
onlyChanges_(oc), coarse(crs),
- dir(0), changed(FALSE), oldLength_(0), newLength_(0),
+ dir(0), changed(false), oldLength_(0), newLength_(0),
srcIndex(0), replIndex(0), destIndex(0) {}
int32_t Edits::Iterator::readLength(int32_t head) {
@@ -441,16 +441,16 @@ void Edits::Iterator::updatePreviousIndexes() {
UBool Edits::Iterator::noNext() {
// No change before or beyond the string.
dir = 0;
- changed = FALSE;
+ changed = false;
oldLength_ = newLength_ = 0;
- return FALSE;
+ return false;
}
UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
// Forward iteration: Update the string indexes to the limit of the current span,
// and post-increment-read array units to assemble a new span.
// Leaves the array index one after the last unit of that span.
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
// We have an errorCode in case we need to start guarding against integer overflows.
// It is also convenient for caller loops if we bail out when an error was set elsewhere.
if (dir > 0) {
@@ -464,7 +464,7 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
// Stay on the current one of a sequence of compressed changes.
++index; // next() rests on the index after the sequence unit.
dir = 1;
- return TRUE;
+ return true;
}
}
dir = 1;
@@ -473,7 +473,7 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
// Fine-grained iterator: Continue a sequence of compressed changes.
if (remaining > 1) {
--remaining;
- return TRUE;
+ return true;
}
remaining = 0;
}
@@ -483,7 +483,7 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
int32_t u = array[index++];
if (u <= MAX_UNCHANGED) {
// Combine adjacent unchanged ranges.
- changed = FALSE;
+ changed = false;
oldLength_ = u + 1;
while (index < length && (u = array[index]) <= MAX_UNCHANGED) {
++index;
@@ -498,10 +498,10 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
// already fetched u > MAX_UNCHANGED at index
++index;
} else {
- return TRUE;
+ return true;
}
}
- changed = TRUE;
+ changed = true;
if (u <= MAX_SHORT_CHANGE) {
int32_t oldLen = u >> 12;
int32_t newLen = (u >> 9) & MAX_SHORT_CHANGE_NEW_LENGTH;
@@ -516,14 +516,14 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
if (num > 1) {
remaining = num; // This is the first of two or more changes.
}
- return TRUE;
+ return true;
}
} else {
U_ASSERT(u <= 0x7fff);
oldLength_ = readLength((u >> 6) & 0x3f);
newLength_ = readLength(u & 0x3f);
if (!coarse) {
- return TRUE;
+ return true;
}
}
// Combine adjacent changes.
@@ -539,14 +539,14 @@ UBool Edits::Iterator::next(UBool onlyChanges, UErrorCode &errorCode) {
newLength_ += readLength(u & 0x3f);
}
}
- return TRUE;
+ return true;
}
UBool Edits::Iterator::previous(UErrorCode &errorCode) {
// Backward iteration: Pre-decrement-read array units to assemble a new span,
// then update the string indexes to the start of that span.
// Leaves the array index on the head unit of that span.
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
// We have an errorCode in case we need to start guarding against integer overflows.
// It is also convenient for caller loops if we bail out when an error was set elsewhere.
if (dir >= 0) {
@@ -559,7 +559,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
// Stay on the current one of a sequence of compressed changes.
--index; // previous() rests on the sequence unit.
dir = -1;
- return TRUE;
+ return true;
}
updateNextIndexes();
}
@@ -572,7 +572,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
if (remaining <= (u & SHORT_CHANGE_NUM_MASK)) {
++remaining;
updatePreviousIndexes();
- return TRUE;
+ return true;
}
remaining = 0;
}
@@ -582,7 +582,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
int32_t u = array[--index];
if (u <= MAX_UNCHANGED) {
// Combine adjacent unchanged ranges.
- changed = FALSE;
+ changed = false;
oldLength_ = u + 1;
while (index > 0 && (u = array[index - 1]) <= MAX_UNCHANGED) {
--index;
@@ -591,9 +591,9 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
newLength_ = oldLength_;
// No need to handle onlyChanges as long as previous() is called only from findIndex().
updatePreviousIndexes();
- return TRUE;
+ return true;
}
- changed = TRUE;
+ changed = true;
if (u <= MAX_SHORT_CHANGE) {
int32_t oldLen = u >> 12;
int32_t newLen = (u >> 9) & MAX_SHORT_CHANGE_NEW_LENGTH;
@@ -609,7 +609,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
remaining = 1; // This is the last of two or more changes.
}
updatePreviousIndexes();
- return TRUE;
+ return true;
}
} else {
if (u <= 0x7fff) {
@@ -629,7 +629,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
}
if (!coarse) {
updatePreviousIndexes();
- return TRUE;
+ return true;
}
}
// Combine adjacent changes.
@@ -648,7 +648,7 @@ UBool Edits::Iterator::previous(UErrorCode &errorCode) {
}
}
updatePreviousIndexes();
- return TRUE;
+ return true;
}
int32_t Edits::Iterator::findIndex(int32_t i, UBool findSource, UErrorCode &errorCode) {
@@ -705,7 +705,7 @@ int32_t Edits::Iterator::findIndex(int32_t i, UBool findSource, UErrorCode &erro
// The index is in the current span.
return 0;
}
- while (next(FALSE, errorCode)) {
+ while (next(false, errorCode)) {
if (findSource) {
spanStart = srcIndex;
spanLength = oldLength_;
@@ -739,7 +739,7 @@ int32_t Edits::Iterator::findIndex(int32_t i, UBool findSource, UErrorCode &erro
}
int32_t Edits::Iterator::destinationIndexFromSourceIndex(int32_t i, UErrorCode &errorCode) {
- int32_t where = findIndex(i, TRUE, errorCode);
+ int32_t where = findIndex(i, true, errorCode);
if (where < 0) {
// Error or before the string.
return 0;
@@ -758,7 +758,7 @@ int32_t Edits::Iterator::destinationIndexFromSourceIndex(int32_t i, UErrorCode &
}
int32_t Edits::Iterator::sourceIndexFromDestinationIndex(int32_t i, UErrorCode &errorCode) {
- int32_t where = findIndex(i, FALSE, errorCode);
+ int32_t where = findIndex(i, false, errorCode);
if (where < 0) {
// Error or before the string.
return 0;
diff --git a/thirdparty/icu4c/common/emojiprops.cpp b/thirdparty/icu4c/common/emojiprops.cpp
index 2a05e8602d..d07e07c6cc 100644
--- a/thirdparty/icu4c/common/emojiprops.cpp
+++ b/thirdparty/icu4c/common/emojiprops.cpp
@@ -22,7 +22,7 @@ U_NAMESPACE_BEGIN
namespace {
EmojiProps *singleton = nullptr;
-icu::UInitOnce emojiInitOnce = U_INITONCE_INITIALIZER;
+icu::UInitOnce emojiInitOnce {};
UBool U_CALLCONV emojiprops_cleanup() {
delete singleton;
diff --git a/thirdparty/icu4c/common/filteredbrk.cpp b/thirdparty/icu4c/common/filteredbrk.cpp
index e4817367a5..baa1d4e42d 100644
--- a/thirdparty/icu4c/common/filteredbrk.cpp
+++ b/thirdparty/icu4c/common/filteredbrk.cpp
@@ -58,7 +58,7 @@ static int32_t U_CALLCONV compareUnicodeString(UElement t1, UElement t2) {
/**
* A UVector which implements a set of strings.
*/
-class U_COMMON_API UStringSet : public UVector {
+class UStringSet : public UVector {
public:
UStringSet(UErrorCode &status) : UVector(uprv_deleteUObject,
uhash_compareUnicodeString,
@@ -482,7 +482,7 @@ SimpleFilteredSentenceBreakIterator::last(void) {
/**
* Concrete implementation of builder class.
*/
-class U_COMMON_API SimpleFilteredBreakIteratorBuilder : public FilteredBreakIteratorBuilder {
+class SimpleFilteredBreakIteratorBuilder : public FilteredBreakIteratorBuilder {
public:
virtual ~SimpleFilteredBreakIteratorBuilder();
SimpleFilteredBreakIteratorBuilder(const Locale &fromLocale, UErrorCode &status);
@@ -614,11 +614,11 @@ SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UEr
i++) {
const UnicodeString *abbr = fSet.getStringAt(i);
if(abbr) {
- FB_TRACE("build",abbr,TRUE,i);
+ FB_TRACE("build",abbr,true,i);
ustrs[n] = *abbr; // copy by value
- FB_TRACE("ustrs[n]",&ustrs[n],TRUE,i);
+ FB_TRACE("ustrs[n]",&ustrs[n],true,i);
} else {
- FB_TRACE("build",abbr,FALSE,i);
+ FB_TRACE("build",abbr,false,i);
status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
@@ -629,37 +629,37 @@ SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UEr
for(int i=0;i<subCount;i++) {
int nn = ustrs[i].indexOf(kFULLSTOP); // TODO: non-'.' abbreviations
if(nn>-1 && (nn+1)!=ustrs[i].length()) {
- FB_TRACE("partial",&ustrs[i],FALSE,i);
+ FB_TRACE("partial",&ustrs[i],false,i);
// is partial.
// is it unique?
int sameAs = -1;
for(int j=0;j<subCount;j++) {
if(j==i) continue;
if(ustrs[i].compare(0,nn+1,ustrs[j],0,nn+1)==0) {
- FB_TRACE("prefix",&ustrs[j],FALSE,nn+1);
+ FB_TRACE("prefix",&ustrs[j],false,nn+1);
//UBool otherIsPartial = ((nn+1)!=ustrs[j].length()); // true if ustrs[j] doesn't end at nn
if(partials[j]==0) { // hasn't been processed yet
partials[j] = kSuppressInReverse | kAddToForward;
- FB_TRACE("suppressing",&ustrs[j],FALSE,j);
+ FB_TRACE("suppressing",&ustrs[j],false,j);
} else if(partials[j] & kSuppressInReverse) {
sameAs = j; // the other entry is already in the reverse table.
}
}
}
- FB_TRACE("for partial same-",&ustrs[i],FALSE,sameAs);
- FB_TRACE(" == partial #",&ustrs[i],FALSE,partials[i]);
+ FB_TRACE("for partial same-",&ustrs[i],false,sameAs);
+ FB_TRACE(" == partial #",&ustrs[i],false,partials[i]);
UnicodeString prefix(ustrs[i], 0, nn+1);
if(sameAs == -1 && partials[i] == 0) {
// first one - add the prefix to the reverse table.
prefix.reverse();
builder->add(prefix, kPARTIAL, status);
revCount++;
- FB_TRACE("Added partial",&prefix,FALSE, i);
- FB_TRACE(u_errorName(status),&ustrs[i],FALSE,i);
+ FB_TRACE("Added partial",&prefix,false, i);
+ FB_TRACE(u_errorName(status),&ustrs[i],false,i);
partials[i] = kSuppressInReverse | kAddToForward;
} else {
- FB_TRACE("NOT adding partial",&prefix,FALSE, i);
- FB_TRACE(u_errorName(status),&ustrs[i],FALSE,i);
+ FB_TRACE("NOT adding partial",&prefix,false, i);
+ FB_TRACE(u_errorName(status),&ustrs[i],false,i);
}
}
}
@@ -668,9 +668,9 @@ SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UEr
ustrs[i].reverse();
builder->add(ustrs[i], kMATCH, status);
revCount++;
- FB_TRACE(u_errorName(status), &ustrs[i], FALSE, i);
+ FB_TRACE(u_errorName(status), &ustrs[i], false, i);
} else {
- FB_TRACE("Adding fwd",&ustrs[i], FALSE, i);
+ FB_TRACE("Adding fwd",&ustrs[i], false, i);
// an optimization would be to only add the portion after the '.'
// for example, for "Ph.D." we store ".hP" in the reverse table. We could just store "D." in the forward,
@@ -682,12 +682,12 @@ SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UEr
////if(debug2) u_printf("SUPPRESS- not Added(%d): /%S/ status=%s\n",partials[i], ustrs[i].getTerminatedBuffer(), u_errorName(status));
}
}
- FB_TRACE("AbbrCount",NULL,FALSE, subCount);
+ FB_TRACE("AbbrCount",NULL,false, subCount);
if(revCount>0) {
backwardsTrie.adoptInstead(builder->build(USTRINGTRIE_BUILD_FAST, status));
if(U_FAILURE(status)) {
- FB_TRACE(u_errorName(status),NULL,FALSE, -1);
+ FB_TRACE(u_errorName(status),NULL,false, -1);
return NULL;
}
}
@@ -695,7 +695,7 @@ SimpleFilteredBreakIteratorBuilder::build(BreakIterator* adoptBreakIterator, UEr
if(fwdCount>0) {
forwardsPartialTrie.adoptInstead(builder2->build(USTRINGTRIE_BUILD_FAST, status));
if(U_FAILURE(status)) {
- FB_TRACE(u_errorName(status),NULL,FALSE, -1);
+ FB_TRACE(u_errorName(status),NULL,false, -1);
return NULL;
}
}
diff --git a/thirdparty/icu4c/common/filterednormalizer2.cpp b/thirdparty/icu4c/common/filterednormalizer2.cpp
index 1a0914d3f7..63f01206e9 100644
--- a/thirdparty/icu4c/common/filterednormalizer2.cpp
+++ b/thirdparty/icu4c/common/filterednormalizer2.cpp
@@ -137,14 +137,14 @@ UnicodeString &
FilteredNormalizer2::normalizeSecondAndAppend(UnicodeString &first,
const UnicodeString &second,
UErrorCode &errorCode) const {
- return normalizeSecondAndAppend(first, second, TRUE, errorCode);
+ return normalizeSecondAndAppend(first, second, true, errorCode);
}
UnicodeString &
FilteredNormalizer2::append(UnicodeString &first,
const UnicodeString &second,
UErrorCode &errorCode) const {
- return normalizeSecondAndAppend(first, second, FALSE, errorCode);
+ return normalizeSecondAndAppend(first, second, false, errorCode);
}
UnicodeString &
@@ -224,7 +224,7 @@ UBool
FilteredNormalizer2::isNormalized(const UnicodeString &s, UErrorCode &errorCode) const {
uprv_checkCanGetBuffer(s, errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
USetSpanCondition spanCondition=USET_SPAN_SIMPLE;
for(int32_t prevSpanLimit=0; prevSpanLimit<s.length();) {
@@ -235,19 +235,19 @@ FilteredNormalizer2::isNormalized(const UnicodeString &s, UErrorCode &errorCode)
if( !norm2.isNormalized(s.tempSubStringBetween(prevSpanLimit, spanLimit), errorCode) ||
U_FAILURE(errorCode)
) {
- return FALSE;
+ return false;
}
spanCondition=USET_SPAN_NOT_CONTAINED;
}
prevSpanLimit=spanLimit;
}
- return TRUE;
+ return true;
}
UBool
FilteredNormalizer2::isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) const {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
const char *s = sp.data();
int32_t length = sp.length();
@@ -259,14 +259,14 @@ FilteredNormalizer2::isNormalizedUTF8(StringPiece sp, UErrorCode &errorCode) con
} else {
if (!norm2.isNormalizedUTF8(StringPiece(s, spanLength), errorCode) ||
U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
spanCondition = USET_SPAN_NOT_CONTAINED;
}
s += spanLength;
length -= spanLength;
}
- return TRUE;
+ return true;
}
UNormalizationCheckResult
diff --git a/thirdparty/icu4c/common/hash.h b/thirdparty/icu4c/common/hash.h
index b927ddb3c3..c9afeaf562 100644
--- a/thirdparty/icu4c/common/hash.h
+++ b/thirdparty/icu4c/common/hash.h
@@ -115,8 +115,8 @@ public:
inline UBool equals(const Hashtable& that) const;
private:
- Hashtable(const Hashtable &other); // forbid copying of this class
- Hashtable &operator=(const Hashtable &other); // forbid copying of this class
+ Hashtable(const Hashtable &other) = delete; // forbid copying of this class
+ Hashtable &operator=(const Hashtable &other) = delete; // forbid copying of this class
};
/*********************************************************************
diff --git a/thirdparty/icu4c/common/icuplug.cpp b/thirdparty/icu4c/common/icuplug.cpp
index 52a0deced6..72b5d27175 100644
--- a/thirdparty/icu4c/common/icuplug.cpp
+++ b/thirdparty/icu4c/common/icuplug.cpp
@@ -59,8 +59,8 @@ struct UPlugData {
void *context; /**< user context data */
char name[UPLUG_NAME_MAX]; /**< name of plugin */
UPlugLevel level; /**< level of plugin */
- UBool awaitingLoad; /**< TRUE if the plugin is awaiting a load call */
- UBool dontUnload; /**< TRUE if plugin must stay resident (leak plugin and lib) */
+ UBool awaitingLoad; /**< true if the plugin is awaiting a load call */
+ UBool dontUnload; /**< true if plugin must stay resident (leak plugin and lib) */
UErrorCode pluginStatus; /**< status code of plugin */
};
@@ -304,11 +304,11 @@ static void uplug_queryPlug(UPlugData *plug, UErrorCode *status) {
if(U_SUCCESS(*status)) {
if(plug->level == UPLUG_LEVEL_INVALID) {
plug->pluginStatus = U_PLUGIN_DIDNT_SET_LEVEL;
- plug->awaitingLoad = FALSE;
+ plug->awaitingLoad = false;
}
} else {
plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
- plug->awaitingLoad = FALSE;
+ plug->awaitingLoad = false;
}
}
@@ -322,7 +322,7 @@ static void uplug_loadPlug(UPlugData *plug, UErrorCode *status) {
return;
}
uplug_callPlug(plug, UPLUG_REASON_LOAD, status);
- plug->awaitingLoad = FALSE;
+ plug->awaitingLoad = false;
if(!U_SUCCESS(*status)) {
plug->pluginStatus = U_INTERNAL_PROGRAM_ERROR;
}
@@ -347,8 +347,8 @@ static UPlugData *uplug_allocateEmptyPlug(UErrorCode *status)
plug->structSize = sizeof(UPlugData);
plug->name[0]=0;
plug->level = UPLUG_LEVEL_UNKNOWN; /* initialize to null state */
- plug->awaitingLoad = TRUE;
- plug->dontUnload = FALSE;
+ plug->awaitingLoad = true;
+ plug->dontUnload = false;
plug->pluginStatus = U_ZERO_ERROR;
plug->libName[0] = 0;
plug->config[0]=0;
@@ -403,9 +403,9 @@ static void uplug_deallocatePlug(UPlugData *plug, UErrorCode *status) {
pluginCount = uplug_removeEntryAt(pluginList, pluginCount, sizeof(plug[0]), uplug_pluginNumber(plug));
} else {
/* not ok- leave as a message. */
- plug->awaitingLoad=FALSE;
+ plug->awaitingLoad=false;
plug->entrypoint=0;
- plug->dontUnload=TRUE;
+ plug->dontUnload=true;
}
}
@@ -558,8 +558,8 @@ uplug_initErrorPlug(const char *libName, const char *sym, const char *config, co
if(U_FAILURE(*status)) return NULL;
plug->pluginStatus = loadStatus;
- plug->awaitingLoad = FALSE; /* Won't load. */
- plug->dontUnload = TRUE; /* cannot unload. */
+ plug->awaitingLoad = false; /* Won't load. */
+ plug->dontUnload = true; /* cannot unload. */
if(sym!=NULL) {
uprv_strncpy(plug->sym, sym, UPLUG_NAME_MAX);
@@ -646,7 +646,7 @@ static UBool U_CALLCONV uplug_cleanup(void)
}
/* close other held libs? */
gCurrentLevel = UPLUG_LEVEL_LOW;
- return TRUE;
+ return true;
}
#if U_ENABLE_DYLOAD
@@ -678,7 +678,7 @@ static void uplug_loadWaitingPlugs(UErrorCode *status) {
currentLevel = newLevel;
}
}
- pluginToLoad->awaitingLoad = FALSE;
+ pluginToLoad->awaitingLoad = false;
}
}
}
@@ -694,7 +694,7 @@ static void uplug_loadWaitingPlugs(UErrorCode *status) {
} else {
uplug_loadPlug(pluginToLoad, &subStatus);
}
- pluginToLoad->awaitingLoad = FALSE;
+ pluginToLoad->awaitingLoad = false;
}
}
diff --git a/thirdparty/icu4c/common/loadednormalizer2impl.cpp b/thirdparty/icu4c/common/loadednormalizer2impl.cpp
index 905fc1decc..24ff629f84 100644
--- a/thirdparty/icu4c/common/loadednormalizer2impl.cpp
+++ b/thirdparty/icu4c/common/loadednormalizer2impl.cpp
@@ -67,9 +67,9 @@ LoadedNormalizer2Impl::isAcceptable(void * /*context*/,
) {
// Normalizer2Impl *me=(Normalizer2Impl *)context;
// uprv_memcpy(me->dataVersion, pInfo->dataVersion, 4);
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
@@ -134,14 +134,14 @@ U_CDECL_END
#if !NORM2_HARDCODE_NFC_DATA
static Norm2AllModes *nfcSingleton;
-static icu::UInitOnce nfcInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce nfcInitOnce {};
#endif
static Norm2AllModes *nfkcSingleton;
-static icu::UInitOnce nfkcInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce nfkcInitOnce {};
static Norm2AllModes *nfkc_cfSingleton;
-static icu::UInitOnce nfkc_cfInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce nfkc_cfInitOnce {};
static UHashtable *cache=NULL;
@@ -185,7 +185,7 @@ static UBool U_CALLCONV uprv_loaded_normalizer2_cleanup() {
uhash_close(cache);
cache=NULL;
- return TRUE;
+ return true;
}
U_CDECL_END
diff --git a/thirdparty/icu4c/common/localebuilder.cpp b/thirdparty/icu4c/common/localebuilder.cpp
index a5f201e847..c1e1f2ad68 100644
--- a/thirdparty/icu4c/common/localebuilder.cpp
+++ b/thirdparty/icu4c/common/localebuilder.cpp
@@ -15,7 +15,7 @@ U_NAMESPACE_BEGIN
#define UPRV_ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
#define UPRV_ISALPHANUM(c) (uprv_isASCIILetter(c) || UPRV_ISDIGIT(c) )
-const char* kAttributeKey = "attribute";
+constexpr const char* kAttributeKey = "attribute";
static bool _isExtensionSubtags(char key, const char* s, int32_t len) {
switch (uprv_tolower(key)) {
@@ -459,7 +459,7 @@ Locale LocaleBuilder::build(UErrorCode& errorCode)
UBool LocaleBuilder::copyErrorTo(UErrorCode &outErrorCode) const {
if (U_FAILURE(outErrorCode)) {
// Do not overwrite the older error code
- return TRUE;
+ return true;
}
outErrorCode = status_;
return U_FAILURE(outErrorCode);
diff --git a/thirdparty/icu4c/common/localefallback_data.h b/thirdparty/icu4c/common/localefallback_data.h
new file mode 100644
index 0000000000..da725de42d
--- /dev/null
+++ b/thirdparty/icu4c/common/localefallback_data.h
@@ -0,0 +1,632 @@
+// © 2022 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+//
+// Internal static data tables used by uresbund.cpp
+// WARNING: This file is mechanically generated by the CLDR-to-ICU tool
+// (see tools/cldr/cldr-to-icu/src/main/java/org/unicode/tool/cldrtoicu/generator/ResourcFallbackCodeGenerator.java).
+// DO NOT HAND EDIT!!!
+
+#ifdef INCLUDED_FROM_URESBUND_CPP
+
+//======================================================================
+// Default script table
+const char scriptCodeChars[] =
+ "Aghb\0Ahom\0Arab\0Armi\0Armn\0Avst\0Bamu\0Bass\0Beng\0Brah\0Cakm\0"
+ "Cans\0Cari\0Cham\0Cher\0Chrs\0Copt\0Cprt\0Cyrl\0Deva\0Egyp\0Ethi\0"
+ "Geor\0Gong\0Gonm\0Goth\0Grek\0Gujr\0Guru\0Hans\0Hant\0Hebr\0Hluw\0"
+ "Hmnp\0Ital\0Jpan\0Kali\0Kana\0Kawi\0Khar\0Khmr\0Kits\0Knda\0Kore\0"
+ "Lana\0Laoo\0Lepc\0Lina\0Lisu\0Lyci\0Lydi\0Mand\0Mani\0Medf\0Merc\0"
+ "Mlym\0Mong\0Mroo\0Mymr\0Narb\0Nkoo\0Nshu\0Ogam\0Olck\0Orkh\0Orya\0"
+ "Osge\0Ougr\0Pauc\0Phli\0Phnx\0Plrd\0Prti\0Rohg\0Runr\0Samr\0Sarb\0"
+ "Saur\0Sgnw\0Sinh\0Sogd\0Sora\0Soyo\0Syrc\0Tale\0Talu\0Taml\0Tang\0"
+ "Tavt\0Telu\0Tfng\0Thaa\0Thai\0Tibt\0Tnsa\0Toto\0Ugar\0Vaii\0Wcho\0"
+ "Xpeo\0Xsux\0Yiii\0";
+
+const char dsLocaleIDChars[] =
+ "ab\0abq\0adp\0ady\0ae\0aeb\0aho\0ajt\0akk\0alt\0am\0apc\0apd\0"
+ "ar\0arc\0arq\0ars\0ary\0arz\0as\0ase\0av\0avl\0awa\0az_IQ\0az_IR\0"
+ "az_RU\0ba\0bal\0bap\0bax\0bcq\0be\0bej\0bfq\0bft\0bfy\0bg\0bgc\0"
+ "bgn\0bgx\0bhb\0bhi\0bho\0bji\0bjj\0blt\0bn\0bo\0bpy\0bqi\0bra\0"
+ "brh\0brx\0bsq\0bst\0btv\0bua\0byn\0ccp\0ce\0chm\0chr\0cja\0cjm\0"
+ "ckb\0cmg\0cop\0cr\0crh\0crk\0crl\0csw\0ctd\0cu\0cv\0dar\0dcc\0"
+ "dgl\0dmf\0doi\0drh\0drs\0dty\0dv\0dz\0egy\0eky\0el\0esg\0ett\0"
+ "fa\0fia\0fub\0gan\0gbm\0gbz\0gez\0ggn\0gjk\0gju\0glk\0gmv\0gof\0"
+ "gom\0gon\0got\0grc\0grt\0gu\0gvr\0gwc\0gwt\0ha_CM\0ha_SD\0hak\0"
+ "haz\0hdy\0he\0hi\0hlu\0hmd\0hnd\0hne\0hnj\0hno\0hoc\0hoj\0hsn\0"
+ "hy\0ii\0inh\0iu\0iw\0ja\0ji\0jml\0ka\0kaa\0kaw\0kbd\0kby\0kdt\0"
+ "kfr\0kfy\0khb\0khn\0kht\0khw\0kjg\0kk\0kk_AF\0kk_CN\0kk_IR\0kk_MN\0"
+ "km\0kn\0ko\0koi\0kok\0kqy\0krc\0kru\0ks\0ktb\0ku_LB\0kum\0kv\0"
+ "kvx\0kxc\0kxl\0kxm\0kxp\0ky\0ky_CN\0kzh\0lab\0lad\0lah\0lbe\0"
+ "lcp\0lep\0lez\0lif\0lis\0lki\0lmn\0lo\0lrc\0luz\0lwl\0lzh\0mag\0"
+ "mai\0man_GN\0mde\0mdf\0mdx\0mfa\0mgp\0mk\0mki\0ml\0mn\0mn_CN\0"
+ "mni\0mnw\0mr\0mrd\0mrj\0mro\0ms_CC\0mtr\0mvy\0mwr\0mww\0my\0mym\0"
+ "myv\0myz\0mzn\0nan\0ne\0new\0nnp\0nod\0noe\0non\0nqo\0nsk\0nst\0"
+ "oj\0ojs\0or\0oru\0os\0osa\0ota\0otk\0oui\0pa\0pa_PK\0pal\0peo\0"
+ "phl\0phn\0pka\0pnt\0ppa\0pra\0prd\0ps\0raj\0rhg\0rif\0rjs\0rkt\0"
+ "rmt\0ru\0rue\0ryu\0sa\0sah\0sat\0saz\0sck\0scl\0sd\0sd_IN\0sdh\0"
+ "sga\0sgw\0shi\0shn\0shu\0si\0skr\0smp\0sog\0sou\0sr\0srb\0srx\0"
+ "swb\0swv\0syl\0syr\0ta\0taj\0tcy\0tdd\0tdg\0tdh\0te\0tg\0tg_PK\0"
+ "th\0thl\0thq\0thr\0ti\0tig\0tkt\0trw\0tsd\0tsf\0tsj\0tt\0tts\0"
+ "txg\0txo\0tyv\0udi\0udm\0ug\0ug_KZ\0ug_MN\0uga\0uk\0unr\0unr_NP\0"
+ "unx\0ur\0uz_AF\0uz_CN\0vai\0wal\0wbq\0wbr\0wni\0wsg\0wtm\0wuu\0"
+ "xco\0xcr\0xlc\0xld\0xmf\0xmn\0xmr\0xna\0xnr\0xpr\0xsa\0xsr\0yi\0"
+ "yue\0yue_CN\0zdj\0zgh\0zh\0zh_AU\0zh_BN\0zh_GB\0zh_GF\0zh_HK\0"
+ "zh_ID\0zh_MO\0zh_PA\0zh_PF\0zh_PH\0zh_SR\0zh_TH\0zh_TW\0zh_US\0"
+ "zh_VN\0zhx\0zkt\0";
+
+const int32_t defaultScriptTable[] = {
+ 0, 90, // ab -> Cyrl
+ 3, 90, // abq -> Cyrl
+ 7, 465, // adp -> Tibt
+ 11, 90, // ady -> Cyrl
+ 15, 25, // ae -> Avst
+ 18, 10, // aeb -> Arab
+ 22, 5, // aho -> Ahom
+ 26, 10, // ajt -> Arab
+ 30, 500, // akk -> Xsux
+ 34, 90, // alt -> Cyrl
+ 38, 105, // am -> Ethi
+ 41, 10, // apc -> Arab
+ 45, 10, // apd -> Arab
+ 49, 10, // ar -> Arab
+ 52, 15, // arc -> Armi
+ 56, 10, // arq -> Arab
+ 60, 10, // ars -> Arab
+ 64, 10, // ary -> Arab
+ 68, 10, // arz -> Arab
+ 72, 40, // as -> Beng
+ 75, 390, // ase -> Sgnw
+ 79, 90, // av -> Cyrl
+ 82, 10, // avl -> Arab
+ 86, 95, // awa -> Deva
+ 90, 10, // az_IQ -> Arab
+ 96, 10, // az_IR -> Arab
+ 102, 90, // az_RU -> Cyrl
+ 108, 90, // ba -> Cyrl
+ 111, 10, // bal -> Arab
+ 115, 95, // bap -> Deva
+ 119, 30, // bax -> Bamu
+ 123, 105, // bcq -> Ethi
+ 127, 90, // be -> Cyrl
+ 130, 10, // bej -> Arab
+ 134, 430, // bfq -> Taml
+ 138, 10, // bft -> Arab
+ 142, 95, // bfy -> Deva
+ 146, 90, // bg -> Cyrl
+ 149, 95, // bgc -> Deva
+ 153, 10, // bgn -> Arab
+ 157, 130, // bgx -> Grek
+ 161, 95, // bhb -> Deva
+ 165, 95, // bhi -> Deva
+ 169, 95, // bho -> Deva
+ 173, 105, // bji -> Ethi
+ 177, 95, // bjj -> Deva
+ 181, 440, // blt -> Tavt
+ 185, 40, // bn -> Beng
+ 188, 465, // bo -> Tibt
+ 191, 40, // bpy -> Beng
+ 195, 10, // bqi -> Arab
+ 199, 95, // bra -> Deva
+ 203, 10, // brh -> Arab
+ 207, 95, // brx -> Deva
+ 211, 35, // bsq -> Bass
+ 215, 105, // bst -> Ethi
+ 219, 95, // btv -> Deva
+ 223, 90, // bua -> Cyrl
+ 227, 105, // byn -> Ethi
+ 231, 50, // ccp -> Cakm
+ 235, 90, // ce -> Cyrl
+ 238, 90, // chm -> Cyrl
+ 242, 70, // chr -> Cher
+ 246, 10, // cja -> Arab
+ 250, 65, // cjm -> Cham
+ 254, 10, // ckb -> Arab
+ 258, 410, // cmg -> Soyo
+ 262, 80, // cop -> Copt
+ 266, 55, // cr -> Cans
+ 269, 90, // crh -> Cyrl
+ 273, 55, // crk -> Cans
+ 277, 55, // crl -> Cans
+ 281, 55, // csw -> Cans
+ 285, 340, // ctd -> Pauc
+ 289, 90, // cu -> Cyrl
+ 292, 90, // cv -> Cyrl
+ 295, 90, // dar -> Cyrl
+ 299, 10, // dcc -> Arab
+ 303, 10, // dgl -> Arab
+ 307, 265, // dmf -> Medf
+ 311, 95, // doi -> Deva
+ 315, 280, // drh -> Mong
+ 319, 105, // drs -> Ethi
+ 323, 95, // dty -> Deva
+ 327, 455, // dv -> Thaa
+ 330, 465, // dz -> Tibt
+ 333, 100, // egy -> Egyp
+ 337, 180, // eky -> Kali
+ 341, 130, // el -> Grek
+ 344, 120, // esg -> Gonm
+ 348, 170, // ett -> Ital
+ 352, 10, // fa -> Arab
+ 355, 10, // fia -> Arab
+ 359, 10, // fub -> Arab
+ 363, 145, // gan -> Hans
+ 367, 95, // gbm -> Deva
+ 371, 10, // gbz -> Arab
+ 375, 105, // gez -> Ethi
+ 379, 95, // ggn -> Deva
+ 383, 10, // gjk -> Arab
+ 387, 10, // gju -> Arab
+ 391, 10, // glk -> Arab
+ 395, 105, // gmv -> Ethi
+ 399, 105, // gof -> Ethi
+ 403, 95, // gom -> Deva
+ 407, 445, // gon -> Telu
+ 411, 125, // got -> Goth
+ 415, 85, // grc -> Cprt
+ 419, 40, // grt -> Beng
+ 423, 135, // gu -> Gujr
+ 426, 95, // gvr -> Deva
+ 430, 10, // gwc -> Arab
+ 434, 10, // gwt -> Arab
+ 438, 10, // ha_CM -> Arab
+ 444, 10, // ha_SD -> Arab
+ 450, 145, // hak -> Hans
+ 454, 10, // haz -> Arab
+ 458, 105, // hdy -> Ethi
+ 462, 155, // he -> Hebr
+ 465, 95, // hi -> Deva
+ 468, 160, // hlu -> Hluw
+ 472, 355, // hmd -> Plrd
+ 476, 10, // hnd -> Arab
+ 480, 95, // hne -> Deva
+ 484, 165, // hnj -> Hmnp
+ 488, 10, // hno -> Arab
+ 492, 95, // hoc -> Deva
+ 496, 95, // hoj -> Deva
+ 500, 145, // hsn -> Hans
+ 504, 20, // hy -> Armn
+ 507, 505, // ii -> Yiii
+ 510, 90, // inh -> Cyrl
+ 514, 55, // iu -> Cans
+ 517, 155, // iw -> Hebr
+ 520, 175, // ja -> Jpan
+ 523, 155, // ji -> Hebr
+ 526, 95, // jml -> Deva
+ 530, 110, // ka -> Geor
+ 533, 90, // kaa -> Cyrl
+ 537, 190, // kaw -> Kawi
+ 541, 90, // kbd -> Cyrl
+ 545, 10, // kby -> Arab
+ 549, 460, // kdt -> Thai
+ 553, 95, // kfr -> Deva
+ 557, 95, // kfy -> Deva
+ 561, 425, // khb -> Talu
+ 565, 95, // khn -> Deva
+ 569, 290, // kht -> Mymr
+ 573, 10, // khw -> Arab
+ 577, 225, // kjg -> Laoo
+ 581, 90, // kk -> Cyrl
+ 584, 10, // kk_AF -> Arab
+ 590, 10, // kk_CN -> Arab
+ 596, 10, // kk_IR -> Arab
+ 602, 10, // kk_MN -> Arab
+ 608, 200, // km -> Khmr
+ 611, 210, // kn -> Knda
+ 614, 215, // ko -> Kore
+ 617, 90, // koi -> Cyrl
+ 621, 95, // kok -> Deva
+ 625, 105, // kqy -> Ethi
+ 629, 90, // krc -> Cyrl
+ 633, 95, // kru -> Deva
+ 637, 10, // ks -> Arab
+ 640, 105, // ktb -> Ethi
+ 644, 10, // ku_LB -> Arab
+ 650, 90, // kum -> Cyrl
+ 654, 90, // kv -> Cyrl
+ 657, 10, // kvx -> Arab
+ 661, 105, // kxc -> Ethi
+ 665, 95, // kxl -> Deva
+ 669, 460, // kxm -> Thai
+ 673, 10, // kxp -> Arab
+ 677, 90, // ky -> Cyrl
+ 680, 10, // ky_CN -> Arab
+ 686, 10, // kzh -> Arab
+ 690, 235, // lab -> Lina
+ 694, 155, // lad -> Hebr
+ 698, 10, // lah -> Arab
+ 702, 90, // lbe -> Cyrl
+ 706, 460, // lcp -> Thai
+ 710, 230, // lep -> Lepc
+ 714, 90, // lez -> Cyrl
+ 718, 95, // lif -> Deva
+ 722, 240, // lis -> Lisu
+ 726, 10, // lki -> Arab
+ 730, 445, // lmn -> Telu
+ 734, 225, // lo -> Laoo
+ 737, 10, // lrc -> Arab
+ 741, 10, // luz -> Arab
+ 745, 460, // lwl -> Thai
+ 749, 145, // lzh -> Hans
+ 753, 95, // mag -> Deva
+ 757, 95, // mai -> Deva
+ 761, 300, // man_GN -> Nkoo
+ 768, 10, // mde -> Arab
+ 772, 90, // mdf -> Cyrl
+ 776, 105, // mdx -> Ethi
+ 780, 10, // mfa -> Arab
+ 784, 95, // mgp -> Deva
+ 788, 90, // mk -> Cyrl
+ 791, 10, // mki -> Arab
+ 795, 275, // ml -> Mlym
+ 798, 90, // mn -> Cyrl
+ 801, 280, // mn_CN -> Mong
+ 807, 40, // mni -> Beng
+ 811, 290, // mnw -> Mymr
+ 815, 95, // mr -> Deva
+ 818, 95, // mrd -> Deva
+ 822, 90, // mrj -> Cyrl
+ 826, 285, // mro -> Mroo
+ 830, 10, // ms_CC -> Arab
+ 836, 95, // mtr -> Deva
+ 840, 10, // mvy -> Arab
+ 844, 95, // mwr -> Deva
+ 848, 165, // mww -> Hmnp
+ 852, 290, // my -> Mymr
+ 855, 105, // mym -> Ethi
+ 859, 90, // myv -> Cyrl
+ 863, 255, // myz -> Mand
+ 867, 10, // mzn -> Arab
+ 871, 145, // nan -> Hans
+ 875, 95, // ne -> Deva
+ 878, 95, // new -> Deva
+ 882, 490, // nnp -> Wcho
+ 886, 220, // nod -> Lana
+ 890, 95, // noe -> Deva
+ 894, 370, // non -> Runr
+ 898, 300, // nqo -> Nkoo
+ 902, 55, // nsk -> Cans
+ 906, 470, // nst -> Tnsa
+ 910, 55, // oj -> Cans
+ 913, 55, // ojs -> Cans
+ 917, 325, // or -> Orya
+ 920, 10, // oru -> Arab
+ 924, 90, // os -> Cyrl
+ 927, 330, // osa -> Osge
+ 931, 10, // ota -> Arab
+ 935, 320, // otk -> Orkh
+ 939, 335, // oui -> Ougr
+ 943, 140, // pa -> Guru
+ 946, 10, // pa_PK -> Arab
+ 952, 345, // pal -> Phli
+ 956, 495, // peo -> Xpeo
+ 960, 10, // phl -> Arab
+ 964, 350, // phn -> Phnx
+ 968, 45, // pka -> Brah
+ 972, 130, // pnt -> Grek
+ 976, 95, // ppa -> Deva
+ 980, 195, // pra -> Khar
+ 984, 10, // prd -> Arab
+ 988, 10, // ps -> Arab
+ 991, 95, // raj -> Deva
+ 995, 365, // rhg -> Rohg
+ 999, 450, // rif -> Tfng
+ 1003, 95, // rjs -> Deva
+ 1007, 40, // rkt -> Beng
+ 1011, 10, // rmt -> Arab
+ 1015, 90, // ru -> Cyrl
+ 1018, 90, // rue -> Cyrl
+ 1022, 185, // ryu -> Kana
+ 1026, 95, // sa -> Deva
+ 1029, 90, // sah -> Cyrl
+ 1033, 315, // sat -> Olck
+ 1037, 385, // saz -> Saur
+ 1041, 95, // sck -> Deva
+ 1045, 10, // scl -> Arab
+ 1049, 10, // sd -> Arab
+ 1052, 95, // sd_IN -> Deva
+ 1058, 10, // sdh -> Arab
+ 1062, 310, // sga -> Ogam
+ 1066, 105, // sgw -> Ethi
+ 1070, 450, // shi -> Tfng
+ 1074, 290, // shn -> Mymr
+ 1078, 10, // shu -> Arab
+ 1082, 395, // si -> Sinh
+ 1085, 10, // skr -> Arab
+ 1089, 375, // smp -> Samr
+ 1093, 400, // sog -> Sogd
+ 1097, 460, // sou -> Thai
+ 1101, 90, // sr -> Cyrl
+ 1104, 405, // srb -> Sora
+ 1108, 95, // srx -> Deva
+ 1112, 10, // swb -> Arab
+ 1116, 95, // swv -> Deva
+ 1120, 40, // syl -> Beng
+ 1124, 415, // syr -> Syrc
+ 1128, 430, // ta -> Taml
+ 1131, 95, // taj -> Deva
+ 1135, 210, // tcy -> Knda
+ 1139, 420, // tdd -> Tale
+ 1143, 95, // tdg -> Deva
+ 1147, 95, // tdh -> Deva
+ 1151, 445, // te -> Telu
+ 1154, 90, // tg -> Cyrl
+ 1157, 10, // tg_PK -> Arab
+ 1163, 460, // th -> Thai
+ 1166, 95, // thl -> Deva
+ 1170, 95, // thq -> Deva
+ 1174, 95, // thr -> Deva
+ 1178, 105, // ti -> Ethi
+ 1181, 105, // tig -> Ethi
+ 1185, 95, // tkt -> Deva
+ 1189, 10, // trw -> Arab
+ 1193, 130, // tsd -> Grek
+ 1197, 95, // tsf -> Deva
+ 1201, 465, // tsj -> Tibt
+ 1205, 90, // tt -> Cyrl
+ 1208, 460, // tts -> Thai
+ 1212, 435, // txg -> Tang
+ 1216, 475, // txo -> Toto
+ 1220, 90, // tyv -> Cyrl
+ 1224, 0, // udi -> Aghb
+ 1228, 90, // udm -> Cyrl
+ 1232, 10, // ug -> Arab
+ 1235, 90, // ug_KZ -> Cyrl
+ 1241, 90, // ug_MN -> Cyrl
+ 1247, 480, // uga -> Ugar
+ 1251, 90, // uk -> Cyrl
+ 1254, 40, // unr -> Beng
+ 1258, 95, // unr_NP -> Deva
+ 1265, 40, // unx -> Beng
+ 1269, 10, // ur -> Arab
+ 1272, 10, // uz_AF -> Arab
+ 1278, 90, // uz_CN -> Cyrl
+ 1284, 485, // vai -> Vaii
+ 1288, 105, // wal -> Ethi
+ 1292, 445, // wbq -> Telu
+ 1296, 95, // wbr -> Deva
+ 1300, 10, // wni -> Arab
+ 1304, 115, // wsg -> Gong
+ 1308, 95, // wtm -> Deva
+ 1312, 145, // wuu -> Hans
+ 1316, 75, // xco -> Chrs
+ 1320, 60, // xcr -> Cari
+ 1324, 245, // xlc -> Lyci
+ 1328, 250, // xld -> Lydi
+ 1332, 110, // xmf -> Geor
+ 1336, 260, // xmn -> Mani
+ 1340, 270, // xmr -> Merc
+ 1344, 295, // xna -> Narb
+ 1348, 95, // xnr -> Deva
+ 1352, 360, // xpr -> Prti
+ 1356, 380, // xsa -> Sarb
+ 1360, 95, // xsr -> Deva
+ 1364, 155, // yi -> Hebr
+ 1367, 150, // yue -> Hant
+ 1371, 145, // yue_CN -> Hans
+ 1378, 10, // zdj -> Arab
+ 1382, 450, // zgh -> Tfng
+ 1386, 145, // zh -> Hans
+ 1389, 150, // zh_AU -> Hant
+ 1395, 150, // zh_BN -> Hant
+ 1401, 150, // zh_GB -> Hant
+ 1407, 150, // zh_GF -> Hant
+ 1413, 150, // zh_HK -> Hant
+ 1419, 150, // zh_ID -> Hant
+ 1425, 150, // zh_MO -> Hant
+ 1431, 150, // zh_PA -> Hant
+ 1437, 150, // zh_PF -> Hant
+ 1443, 150, // zh_PH -> Hant
+ 1449, 150, // zh_SR -> Hant
+ 1455, 150, // zh_TH -> Hant
+ 1461, 150, // zh_TW -> Hant
+ 1467, 150, // zh_US -> Hant
+ 1473, 150, // zh_VN -> Hant
+ 1479, 305, // zhx -> Nshu
+ 1483, 205, // zkt -> Kits
+};
+
+//======================================================================
+// Parent locale table
+const char parentLocaleChars[] =
+ "az_Arab\0az_Cyrl\0bal_Latn\0blt_Latn\0bm_Nkoo\0bs_Cyrl\0byn_Latn\0"
+ "cu_Glag\0dje_Arab\0dyo_Arab\0en_001\0en_150\0en_AG\0en_AI\0en_AT\0"
+ "en_AU\0en_BB\0en_BE\0en_BM\0en_BS\0en_BW\0en_BZ\0en_CC\0en_CH\0"
+ "en_CK\0en_CM\0en_CX\0en_CY\0en_DE\0en_DG\0en_DK\0en_DM\0en_Dsrt\0"
+ "en_ER\0en_FI\0en_FJ\0en_FK\0en_FM\0en_GB\0en_GD\0en_GG\0en_GH\0"
+ "en_GI\0en_GM\0en_GY\0en_HK\0en_IE\0en_IL\0en_IM\0en_IN\0en_IO\0"
+ "en_JE\0en_JM\0en_KE\0en_KI\0en_KN\0en_KY\0en_LC\0en_LR\0en_LS\0"
+ "en_MG\0en_MO\0en_MS\0en_MT\0en_MU\0en_MV\0en_MW\0en_MY\0en_NA\0"
+ "en_NF\0en_NG\0en_NL\0en_NR\0en_NU\0en_NZ\0en_PG\0en_PK\0en_PN\0"
+ "en_PW\0en_RW\0en_SB\0en_SC\0en_SD\0en_SE\0en_SG\0en_SH\0en_SI\0"
+ "en_SL\0en_SS\0en_SX\0en_SZ\0en_Shaw\0en_TC\0en_TK\0en_TO\0en_TT\0"
+ "en_TV\0en_TZ\0en_UG\0en_VC\0en_VG\0en_VU\0en_WS\0en_ZA\0en_ZM\0"
+ "en_ZW\0es_419\0es_AR\0es_BO\0es_BR\0es_BZ\0es_CL\0es_CO\0es_CR\0"
+ "es_CU\0es_DO\0es_EC\0es_GT\0es_HN\0es_MX\0es_NI\0es_PA\0es_PE\0"
+ "es_PR\0es_PY\0es_SV\0es_US\0es_UY\0es_VE\0ff_Adlm\0ff_Arab\0fr_HT\0"
+ "ha_Arab\0hi_Latn\0ht\0iu_Latn\0kk_Arab\0ks_Deva\0ku_Arab\0ky_Arab\0"
+ "ky_Latn\0ml_Arab\0mn_Mong\0mni_Mtei\0ms_Arab\0nb\0nn\0no\0pa_Arab\0"
+ "pt_AO\0pt_CH\0pt_CV\0pt_FR\0pt_GQ\0pt_GW\0pt_LU\0pt_MO\0pt_MZ\0"
+ "pt_PT\0pt_ST\0pt_TL\0root\0sat_Deva\0sd_Deva\0sd_Khoj\0sd_Sind\0"
+ "shi_Latn\0so_Arab\0sr_Latn\0sw_Arab\0tg_Arab\0ug_Cyrl\0uz_Arab\0"
+ "uz_Cyrl\0vai_Latn\0wo_Arab\0yo_Arab\0yue_Hans\0zh_Hant\0zh_Hant_HK\0"
+ "zh_Hant_MO\0";
+
+const int32_t parentLocaleTable[] = {
+ 0, 1017, // az_Arab -> root
+ 8, 1017, // az_Cyrl -> root
+ 16, 1017, // bal_Latn -> root
+ 25, 1017, // blt_Latn -> root
+ 34, 1017, // bm_Nkoo -> root
+ 42, 1017, // bs_Cyrl -> root
+ 50, 1017, // byn_Latn -> root
+ 59, 1017, // cu_Glag -> root
+ 67, 1017, // dje_Arab -> root
+ 76, 1017, // dyo_Arab -> root
+ 92, 85, // en_150 -> en_001
+ 99, 85, // en_AG -> en_001
+ 105, 85, // en_AI -> en_001
+ 111, 92, // en_AT -> en_150
+ 117, 85, // en_AU -> en_001
+ 123, 85, // en_BB -> en_001
+ 129, 92, // en_BE -> en_150
+ 135, 85, // en_BM -> en_001
+ 141, 85, // en_BS -> en_001
+ 147, 85, // en_BW -> en_001
+ 153, 85, // en_BZ -> en_001
+ 159, 85, // en_CC -> en_001
+ 165, 92, // en_CH -> en_150
+ 171, 85, // en_CK -> en_001
+ 177, 85, // en_CM -> en_001
+ 183, 85, // en_CX -> en_001
+ 189, 85, // en_CY -> en_001
+ 195, 92, // en_DE -> en_150
+ 201, 85, // en_DG -> en_001
+ 207, 92, // en_DK -> en_150
+ 213, 85, // en_DM -> en_001
+ 219, 1017, // en_Dsrt -> root
+ 227, 85, // en_ER -> en_001
+ 233, 92, // en_FI -> en_150
+ 239, 85, // en_FJ -> en_001
+ 245, 85, // en_FK -> en_001
+ 251, 85, // en_FM -> en_001
+ 257, 85, // en_GB -> en_001
+ 263, 85, // en_GD -> en_001
+ 269, 85, // en_GG -> en_001
+ 275, 85, // en_GH -> en_001
+ 281, 85, // en_GI -> en_001
+ 287, 85, // en_GM -> en_001
+ 293, 85, // en_GY -> en_001
+ 299, 85, // en_HK -> en_001
+ 305, 85, // en_IE -> en_001
+ 311, 85, // en_IL -> en_001
+ 317, 85, // en_IM -> en_001
+ 323, 85, // en_IN -> en_001
+ 329, 85, // en_IO -> en_001
+ 335, 85, // en_JE -> en_001
+ 341, 85, // en_JM -> en_001
+ 347, 85, // en_KE -> en_001
+ 353, 85, // en_KI -> en_001
+ 359, 85, // en_KN -> en_001
+ 365, 85, // en_KY -> en_001
+ 371, 85, // en_LC -> en_001
+ 377, 85, // en_LR -> en_001
+ 383, 85, // en_LS -> en_001
+ 389, 85, // en_MG -> en_001
+ 395, 85, // en_MO -> en_001
+ 401, 85, // en_MS -> en_001
+ 407, 85, // en_MT -> en_001
+ 413, 85, // en_MU -> en_001
+ 419, 85, // en_MV -> en_001
+ 425, 85, // en_MW -> en_001
+ 431, 85, // en_MY -> en_001
+ 437, 85, // en_NA -> en_001
+ 443, 85, // en_NF -> en_001
+ 449, 85, // en_NG -> en_001
+ 455, 92, // en_NL -> en_150
+ 461, 85, // en_NR -> en_001
+ 467, 85, // en_NU -> en_001
+ 473, 85, // en_NZ -> en_001
+ 479, 85, // en_PG -> en_001
+ 485, 85, // en_PK -> en_001
+ 491, 85, // en_PN -> en_001
+ 497, 85, // en_PW -> en_001
+ 503, 85, // en_RW -> en_001
+ 509, 85, // en_SB -> en_001
+ 515, 85, // en_SC -> en_001
+ 521, 85, // en_SD -> en_001
+ 527, 92, // en_SE -> en_150
+ 533, 85, // en_SG -> en_001
+ 539, 85, // en_SH -> en_001
+ 545, 92, // en_SI -> en_150
+ 551, 85, // en_SL -> en_001
+ 557, 85, // en_SS -> en_001
+ 563, 85, // en_SX -> en_001
+ 569, 85, // en_SZ -> en_001
+ 575, 1017, // en_Shaw -> root
+ 583, 85, // en_TC -> en_001
+ 589, 85, // en_TK -> en_001
+ 595, 85, // en_TO -> en_001
+ 601, 85, // en_TT -> en_001
+ 607, 85, // en_TV -> en_001
+ 613, 85, // en_TZ -> en_001
+ 619, 85, // en_UG -> en_001
+ 625, 85, // en_VC -> en_001
+ 631, 85, // en_VG -> en_001
+ 637, 85, // en_VU -> en_001
+ 643, 85, // en_WS -> en_001
+ 649, 85, // en_ZA -> en_001
+ 655, 85, // en_ZM -> en_001
+ 661, 85, // en_ZW -> en_001
+ 674, 667, // es_AR -> es_419
+ 680, 667, // es_BO -> es_419
+ 686, 667, // es_BR -> es_419
+ 692, 667, // es_BZ -> es_419
+ 698, 667, // es_CL -> es_419
+ 704, 667, // es_CO -> es_419
+ 710, 667, // es_CR -> es_419
+ 716, 667, // es_CU -> es_419
+ 722, 667, // es_DO -> es_419
+ 728, 667, // es_EC -> es_419
+ 734, 667, // es_GT -> es_419
+ 740, 667, // es_HN -> es_419
+ 746, 667, // es_MX -> es_419
+ 752, 667, // es_NI -> es_419
+ 758, 667, // es_PA -> es_419
+ 764, 667, // es_PE -> es_419
+ 770, 667, // es_PR -> es_419
+ 776, 667, // es_PY -> es_419
+ 782, 667, // es_SV -> es_419
+ 788, 667, // es_US -> es_419
+ 794, 667, // es_UY -> es_419
+ 800, 667, // es_VE -> es_419
+ 806, 1017, // ff_Adlm -> root
+ 814, 1017, // ff_Arab -> root
+ 828, 1017, // ha_Arab -> root
+ 836, 323, // hi_Latn -> en_IN
+ 844, 822, // ht -> fr_HT
+ 847, 1017, // iu_Latn -> root
+ 855, 1017, // kk_Arab -> root
+ 863, 1017, // ks_Deva -> root
+ 871, 1017, // ku_Arab -> root
+ 879, 1017, // ky_Arab -> root
+ 887, 1017, // ky_Latn -> root
+ 895, 1017, // ml_Arab -> root
+ 903, 1017, // mn_Mong -> root
+ 911, 1017, // mni_Mtei -> root
+ 920, 1017, // ms_Arab -> root
+ 928, 934, // nb -> no
+ 931, 934, // nn -> no
+ 937, 1017, // pa_Arab -> root
+ 945, 999, // pt_AO -> pt_PT
+ 951, 999, // pt_CH -> pt_PT
+ 957, 999, // pt_CV -> pt_PT
+ 963, 999, // pt_FR -> pt_PT
+ 969, 999, // pt_GQ -> pt_PT
+ 975, 999, // pt_GW -> pt_PT
+ 981, 999, // pt_LU -> pt_PT
+ 987, 999, // pt_MO -> pt_PT
+ 993, 999, // pt_MZ -> pt_PT
+ 1005, 999, // pt_ST -> pt_PT
+ 1011, 999, // pt_TL -> pt_PT
+ 1022, 1017, // sat_Deva -> root
+ 1031, 1017, // sd_Deva -> root
+ 1039, 1017, // sd_Khoj -> root
+ 1047, 1017, // sd_Sind -> root
+ 1055, 1017, // shi_Latn -> root
+ 1064, 1017, // so_Arab -> root
+ 1072, 1017, // sr_Latn -> root
+ 1080, 1017, // sw_Arab -> root
+ 1088, 1017, // tg_Arab -> root
+ 1096, 1017, // ug_Cyrl -> root
+ 1104, 1017, // uz_Arab -> root
+ 1112, 1017, // uz_Cyrl -> root
+ 1120, 1017, // vai_Latn -> root
+ 1129, 1017, // wo_Arab -> root
+ 1137, 1017, // yo_Arab -> root
+ 1145, 1017, // yue_Hans -> root
+ 1154, 1017, // zh_Hant -> root
+ 1173, 1162, // zh_Hant_MO -> zh_Hant_HK
+};
+
+
+#endif // INCLUDED_FROM_URESBUND_CPP
diff --git a/thirdparty/icu4c/common/localematcher.cpp b/thirdparty/icu4c/common/localematcher.cpp
index 2cad708d99..2f8664b6f7 100644
--- a/thirdparty/icu4c/common/localematcher.cpp
+++ b/thirdparty/icu4c/common/localematcher.cpp
@@ -60,7 +60,7 @@ LocaleMatcher::Result::Result(LocaleMatcher::Result &&src) U_NOEXCEPT :
if (desiredIsOwned) {
src.desiredLocale = nullptr;
src.desiredIndex = -1;
- src.desiredIsOwned = FALSE;
+ src.desiredIsOwned = false;
}
}
@@ -82,7 +82,7 @@ LocaleMatcher::Result &LocaleMatcher::Result::operator=(LocaleMatcher::Result &&
if (desiredIsOwned) {
src.desiredLocale = nullptr;
src.desiredIndex = -1;
- src.desiredIsOwned = FALSE;
+ src.desiredIsOwned = false;
}
return *this;
}
@@ -287,10 +287,10 @@ LocaleMatcher::Builder &LocaleMatcher::Builder::internalSetThresholdDistance(int
#endif
UBool LocaleMatcher::Builder::copyErrorTo(UErrorCode &outErrorCode) const {
- if (U_FAILURE(outErrorCode)) { return TRUE; }
- if (U_SUCCESS(errorCode_)) { return FALSE; }
+ if (U_FAILURE(outErrorCode)) { return true; }
+ if (U_SUCCESS(errorCode_)) { return false; }
outErrorCode = errorCode_;
- return TRUE;
+ return true;
}
LocaleMatcher LocaleMatcher::Builder::build(UErrorCode &errorCode) const {
@@ -632,30 +632,30 @@ const Locale *LocaleMatcher::getBestMatchForListString(
LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
const Locale &desiredLocale, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode)) {
- return Result(nullptr, defaultLocale, -1, -1, FALSE);
+ return Result(nullptr, defaultLocale, -1, -1, false);
}
int32_t suppIndex = getBestSuppIndex(
getMaximalLsrOrUnd(likelySubtags, desiredLocale, errorCode),
nullptr, errorCode);
if (U_FAILURE(errorCode) || suppIndex < 0) {
- return Result(nullptr, defaultLocale, -1, -1, FALSE);
+ return Result(nullptr, defaultLocale, -1, -1, false);
} else {
- return Result(&desiredLocale, supportedLocales[suppIndex], 0, suppIndex, FALSE);
+ return Result(&desiredLocale, supportedLocales[suppIndex], 0, suppIndex, false);
}
}
LocaleMatcher::Result LocaleMatcher::getBestMatchResult(
Locale::Iterator &desiredLocales, UErrorCode &errorCode) const {
if (U_FAILURE(errorCode) || !desiredLocales.hasNext()) {
- return Result(nullptr, defaultLocale, -1, -1, FALSE);
+ return Result(nullptr, defaultLocale, -1, -1, false);
}
LocaleLsrIterator lsrIter(likelySubtags, desiredLocales, ULOCMATCH_TEMPORARY_LOCALES);
int32_t suppIndex = getBestSuppIndex(lsrIter.next(errorCode), &lsrIter, errorCode);
if (U_FAILURE(errorCode) || suppIndex < 0) {
- return Result(nullptr, defaultLocale, -1, -1, FALSE);
+ return Result(nullptr, defaultLocale, -1, -1, false);
} else {
return Result(lsrIter.orphanRemembered(), supportedLocales[suppIndex],
- lsrIter.getBestDesiredIndex(), suppIndex, TRUE);
+ lsrIter.getBestDesiredIndex(), suppIndex, true);
}
}
diff --git a/thirdparty/icu4c/common/localeprioritylist.cpp b/thirdparty/icu4c/common/localeprioritylist.cpp
index 4455eedb75..e5ba0a3c77 100644
--- a/thirdparty/icu4c/common/localeprioritylist.cpp
+++ b/thirdparty/icu4c/common/localeprioritylist.cpp
@@ -234,7 +234,7 @@ void LocalePriorityList::sort(UErrorCode &errorCode) {
// The comparator forces a stable sort via the item index.
if (U_FAILURE(errorCode) || getLength() <= 1 || !hasWeights) { return; }
uprv_sortArray(list->array.getAlias(), listLength, sizeof(LocaleAndWeight),
- compareLocaleAndWeight, nullptr, FALSE, &errorCode);
+ compareLocaleAndWeight, nullptr, false, &errorCode);
}
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/locavailable.cpp b/thirdparty/icu4c/common/locavailable.cpp
index e8ec512e37..cf341e1f74 100644
--- a/thirdparty/icu4c/common/locavailable.cpp
+++ b/thirdparty/icu4c/common/locavailable.cpp
@@ -37,7 +37,7 @@ U_NAMESPACE_BEGIN
static icu::Locale* availableLocaleList = NULL;
static int32_t availableLocaleListCount;
-static icu::UInitOnce gInitOnceLocale = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gInitOnceLocale {};
U_NAMESPACE_END
@@ -54,7 +54,7 @@ static UBool U_CALLCONV locale_available_cleanup(void)
availableLocaleListCount = 0;
gInitOnceLocale.reset();
- return TRUE;
+ return true;
}
U_CDECL_END
@@ -102,7 +102,7 @@ namespace {
// Enough capacity for the two lists in the res_index.res file
const char** gAvailableLocaleNames[2] = {};
int32_t gAvailableLocaleCounts[2] = {};
-icu::UInitOnce ginstalledLocalesInitOnce = U_INITONCE_INITIALIZER;
+icu::UInitOnce ginstalledLocalesInitOnce {};
class AvailableLocalesSink : public ResourceSink {
public:
@@ -203,7 +203,7 @@ static UBool U_CALLCONV uloc_cleanup(void) {
gAvailableLocaleCounts[i] = 0;
}
ginstalledLocalesInitOnce.reset();
- return TRUE;
+ return true;
}
// Load Installed Locales. This function will be called exactly once
diff --git a/thirdparty/icu4c/common/locdispnames.cpp b/thirdparty/icu4c/common/locdispnames.cpp
index c512a0164c..637556cc71 100644
--- a/thirdparty/icu4c/common/locdispnames.cpp
+++ b/thirdparty/icu4c/common/locdispnames.cpp
@@ -514,11 +514,11 @@ uloc_getDisplayName(const char *locale,
UChar formatCloseParen = 0x0029; // )
UChar formatReplaceCloseParen = 0x005D; // ]
- UBool haveLang = TRUE; /* assume true, set false if we find we don't have
+ UBool haveLang = true; /* assume true, set false if we find we don't have
a lang component in the locale */
- UBool haveRest = TRUE; /* assume true, set false if we find we don't have
+ UBool haveRest = true; /* assume true, set false if we find we don't have
any other component in the locale */
- UBool retry = FALSE; /* set true if we need to retry, see below */
+ UBool retry = false; /* set true if we need to retry, see below */
int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
@@ -625,7 +625,7 @@ uloc_getDisplayName(const char *locale,
}
for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
- UBool subdone = FALSE; /* set true when ready to move to next substitution */
+ UBool subdone = false; /* set true when ready to move to next substitution */
/* prep p and cap for calls to get display components, pin cap to 0 since
they complain if cap is negative */
@@ -643,10 +643,10 @@ uloc_getDisplayName(const char *locale,
length+=langLen;
haveLang=langLen>0;
}
- subdone=TRUE;
+ subdone=true;
} else { /* {1} */
if(!haveRest) {
- subdone=TRUE;
+ subdone=true;
} else {
int32_t len; /* length of component (plus other stuff) we just fetched */
switch(resti++) {
@@ -667,7 +667,7 @@ uloc_getDisplayName(const char *locale,
const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
if (kw == NULL) {
len=0; /* mark that we didn't add a component */
- subdone=TRUE;
+ subdone=true;
} else {
/* incorporating this behavior into the loop made it even more complex,
so just special case it here */
@@ -772,7 +772,7 @@ uloc_getDisplayName(const char *locale,
/* would have fit, but didn't because of pattern prefix. */
sub0Pos=0; /* stops initial padding (and a second retry,
so we won't end up here again) */
- retry=TRUE;
+ retry=true;
}
}
}
diff --git a/thirdparty/icu4c/common/locdistance.cpp b/thirdparty/icu4c/common/locdistance.cpp
index ff8892791b..fb22fe79ed 100644
--- a/thirdparty/icu4c/common/locdistance.cpp
+++ b/thirdparty/icu4c/common/locdistance.cpp
@@ -45,13 +45,13 @@ enum {
};
LocaleDistance *gLocaleDistance = nullptr;
-UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
+UInitOnce gInitOnce {};
UBool U_CALLCONV cleanup() {
delete gLocaleDistance;
gLocaleDistance = nullptr;
gInitOnce.reset();
- return TRUE;
+ return true;
}
} // namespace
diff --git a/thirdparty/icu4c/common/locdspnm.cpp b/thirdparty/icu4c/common/locdspnm.cpp
index f73cedd728..401f1fecbf 100644
--- a/thirdparty/icu4c/common/locdspnm.cpp
+++ b/thirdparty/icu4c/common/locdspnm.cpp
@@ -403,7 +403,7 @@ struct LocaleDisplayNamesImpl::CapitalizationContextSink : public ResourceSink {
LocaleDisplayNamesImpl& parent;
CapitalizationContextSink(LocaleDisplayNamesImpl& _parent)
- : hasCapitalizationUsage(FALSE), parent(_parent) {}
+ : hasCapitalizationUsage(false), parent(_parent) {}
virtual ~CapitalizationContextSink();
virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
@@ -437,8 +437,8 @@ struct LocaleDisplayNamesImpl::CapitalizationContextSink : public ResourceSink {
int32_t titlecaseInt = (parent.capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU) ? intVector[0] : intVector[1];
if (titlecaseInt == 0) { continue; }
- parent.fCapitalization[usageEnum] = TRUE;
- hasCapitalizationUsage = TRUE;
+ parent.fCapitalization[usageEnum] = true;
+ hasCapitalizationUsage = true;
}
}
};
@@ -490,7 +490,7 @@ LocaleDisplayNamesImpl::initialize(void) {
#if !UCONFIG_NO_BREAK_ITERATION
// Only get the context data if we need it! This is a const object so we know now...
// Also check whether we will need a break iterator (depends on the data)
- UBool needBrkIter = FALSE;
+ UBool needBrkIter = false;
if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
LocalUResourceBundlePointer resource(ures_open(NULL, locale.getName(), &status));
if (U_FAILURE(status)) { return; }
@@ -593,8 +593,8 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0);
localeIdName(buffer, resultName, false);
if (!resultName.isBogus()) {
- hasScript = FALSE;
- hasCountry = FALSE;
+ hasScript = false;
+ hasCountry = false;
break;
}
}
@@ -602,7 +602,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0);
localeIdName(buffer, resultName, false);
if (!resultName.isBogus()) {
- hasScript = FALSE;
+ hasScript = false;
break;
}
}
@@ -610,11 +610,11 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0);
localeIdName(buffer, resultName, false);
if (!resultName.isBogus()) {
- hasCountry = FALSE;
+ hasCountry = false;
break;
}
}
- } while (FALSE);
+ } while (false);
}
if (resultName.isBogus() || resultName.isEmpty()) {
localeIdName(lang, resultName, substitute == UDISPCTX_SUBSTITUTE);
@@ -629,7 +629,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
UErrorCode status = U_ZERO_ERROR;
if (hasScript) {
- UnicodeString script_str = scriptDisplayName(script, temp, TRUE);
+ UnicodeString script_str = scriptDisplayName(script, temp, true);
if (script_str.isBogus()) {
result.setToBogus();
return result;
@@ -637,7 +637,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
resultRemainder.append(script_str);
}
if (hasCountry) {
- UnicodeString region_str = regionDisplayName(country, temp, TRUE);
+ UnicodeString region_str = regionDisplayName(country, temp, true);
if (region_str.isBogus()) {
result.setToBogus();
return result;
@@ -645,7 +645,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
appendWithSep(resultRemainder, region_str);
}
if (hasVariant) {
- UnicodeString variant_str = variantDisplayName(variant, temp, TRUE);
+ UnicodeString variant_str = variantDisplayName(variant, temp, true);
if (variant_str.isBogus()) {
result.setToBogus();
return result;
@@ -666,10 +666,10 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
return result;
}
- keyDisplayName(key, temp, TRUE);
+ keyDisplayName(key, temp, true);
temp.findAndReplace(formatOpenParen, formatReplaceOpenParen);
temp.findAndReplace(formatCloseParen, formatReplaceCloseParen);
- keyValueDisplayName(key, value, temp2, TRUE);
+ keyValueDisplayName(key, value, temp2, true);
temp2.findAndReplace(formatOpenParen, formatReplaceOpenParen);
temp2.findAndReplace(formatCloseParen, formatReplaceCloseParen);
if (temp2 != UnicodeString(value, -1, US_INV)) {
@@ -797,13 +797,13 @@ LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
UnicodeString&
LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
UnicodeString& result) const {
- return scriptDisplayName(script, result, FALSE);
+ return scriptDisplayName(script, result, false);
}
UnicodeString&
LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode,
UnicodeString& result) const {
- return scriptDisplayName(uscript_getName(scriptCode), result, FALSE);
+ return scriptDisplayName(uscript_getName(scriptCode), result, false);
}
UnicodeString&
@@ -827,7 +827,7 @@ LocaleDisplayNamesImpl::regionDisplayName(const char* region,
UnicodeString&
LocaleDisplayNamesImpl::regionDisplayName(const char* region,
UnicodeString& result) const {
- return regionDisplayName(region, result, FALSE);
+ return regionDisplayName(region, result, false);
}
@@ -847,7 +847,7 @@ LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
UnicodeString&
LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
UnicodeString& result) const {
- return variantDisplayName(variant, result, FALSE);
+ return variantDisplayName(variant, result, false);
}
UnicodeString&
@@ -866,7 +866,7 @@ LocaleDisplayNamesImpl::keyDisplayName(const char* key,
UnicodeString&
LocaleDisplayNamesImpl::keyDisplayName(const char* key,
UnicodeString& result) const {
- return keyDisplayName(key, result, FALSE);
+ return keyDisplayName(key, result, false);
}
UnicodeString&
@@ -908,7 +908,7 @@ UnicodeString&
LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
const char* value,
UnicodeString& result) const {
- return keyValueDisplayName(key, value, result, FALSE);
+ return keyValueDisplayName(key, value, result, false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/thirdparty/icu4c/common/locid.cpp b/thirdparty/icu4c/common/locid.cpp
index 73bb8d8aec..5cd083866c 100644
--- a/thirdparty/icu4c/common/locid.cpp
+++ b/thirdparty/icu4c/common/locid.cpp
@@ -64,7 +64,7 @@ U_CDECL_END
U_NAMESPACE_BEGIN
static Locale *gLocaleCache = NULL;
-static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gLocaleCacheInitOnce {};
// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
static UMutex gDefaultLocaleMutex;
@@ -128,7 +128,7 @@ static UBool U_CALLCONV locale_cleanup(void)
gDefaultLocalesHashT = NULL;
}
gDefaultLocale = NULL;
- return TRUE;
+ return true;
}
@@ -171,7 +171,7 @@ Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
// Synchronize this entire function.
Mutex lock(&gDefaultLocaleMutex);
- UBool canonicalize = FALSE;
+ UBool canonicalize = false;
// If given a NULL string for the locale id, grab the default
// name from the system.
@@ -179,7 +179,7 @@ Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
// the current ICU default locale.)
if (id == NULL) {
id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify.
- canonicalize = TRUE; // always canonicalize host ID
+ canonicalize = true; // always canonicalize host ID
}
CharString localeNameBuf;
@@ -212,7 +212,7 @@ Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
status = U_MEMORY_ALLOCATION_ERROR;
return gDefaultLocale;
}
- newDefault->init(localeNameBuf.data(), FALSE);
+ newDefault->init(localeNameBuf.data(), false);
uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status);
if (U_FAILURE(status)) {
return gDefaultLocale;
@@ -269,7 +269,7 @@ Locale::~Locale()
Locale::Locale()
: UObject(), fullName(fullNameBuffer), baseName(NULL)
{
- init(NULL, FALSE);
+ init(NULL, false);
}
/*
@@ -292,7 +292,7 @@ Locale::Locale( const char * newLanguage,
{
if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
{
- init(NULL, FALSE); /* shortcut */
+ init(NULL, false); /* shortcut */
}
else
{
@@ -397,7 +397,7 @@ Locale::Locale( const char * newLanguage,
}
// Parse it, because for example 'language' might really be a complete
// string.
- init(togo.data(), FALSE);
+ init(togo.data(), false);
}
}
@@ -491,7 +491,7 @@ Locale::operator==( const Locale& other) const
namespace {
-UInitOnce gKnownCanonicalizedInitOnce = U_INITONCE_INITIALIZER;
+UInitOnce gKnownCanonicalizedInitOnce {};
UHashtable *gKnownCanonicalized = nullptr;
static const char* const KNOWN_CANONICALIZED[] = {
@@ -521,7 +521,7 @@ static const char* const KNOWN_CANONICALIZED[] = {
static UBool U_CALLCONV cleanupKnownCanonicalized() {
gKnownCanonicalizedInitOnce.reset();
if (gKnownCanonicalized) { uhash_close(gKnownCanonicalized); }
- return TRUE;
+ return true;
}
static void U_CALLCONV loadKnownCanonicalized(UErrorCode &status) {
@@ -682,14 +682,14 @@ private:
const AliasData* AliasData::gSingleton = nullptr;
-UInitOnce AliasData::gInitOnce = U_INITONCE_INITIALIZER;
+UInitOnce AliasData::gInitOnce {};
UBool U_CALLCONV
AliasData::cleanup()
{
gInitOnce.reset();
delete gSingleton;
- return TRUE;
+ return true;
}
void
@@ -716,20 +716,19 @@ AliasDataBuilder::readAlias(
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
- int i = 0;
- while (ures_hasNext(alias)) {
+ for (int i = 0; U_SUCCESS(status) && ures_hasNext(alias); i++) {
LocalUResourceBundlePointer res(
ures_getNextResource(alias, nullptr, &status));
const char* aliasFrom = ures_getKey(res.getAlias());
UnicodeString aliasTo =
ures_getUnicodeStringByKey(res.getAlias(), "replacement", &status);
+ if (U_FAILURE(status)) return;
checkType(aliasFrom);
checkReplacement(aliasTo);
rawTypes[i] = aliasFrom;
rawIndexes[i] = strings->add(aliasTo, status);
- i++;
}
}
@@ -1818,7 +1817,7 @@ ulocimp_isCanonicalizedLocaleForTest(const char* localeName)
/*This function initializes a Locale from a C locale ID*/
Locale& Locale::init(const char* localeID, UBool canonicalize)
{
- fIsBogus = FALSE;
+ fIsBogus = false;
/* Free our current storage */
if ((baseName != fullName) && (baseName != fullNameBuffer)) {
uprv_free(baseName);
@@ -2022,7 +2021,7 @@ Locale::setToBogus() {
*language = 0;
*script = 0;
*country = 0;
- fIsBogus = TRUE;
+ fIsBogus = true;
variantBegin = 0;
}
@@ -2072,7 +2071,7 @@ Locale::addLikelySubtags(UErrorCode& status) {
return;
}
- init(maximizedLocaleID.data(), /*canonicalize=*/FALSE);
+ init(maximizedLocaleID.data(), /*canonicalize=*/false);
if (isBogus()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -2094,7 +2093,7 @@ Locale::minimizeSubtags(UErrorCode& status) {
return;
}
- init(minimizedLocaleID.data(), /*canonicalize=*/FALSE);
+ init(minimizedLocaleID.data(), /*canonicalize=*/false);
if (isBogus()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -2113,7 +2112,7 @@ Locale::canonicalize(UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
- init(uncanonicalized.data(), /*canonicalize=*/TRUE);
+ init(uncanonicalized.data(), /*canonicalize=*/true);
if (isBogus()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -2160,7 +2159,7 @@ Locale::forLanguageTag(StringPiece tag, UErrorCode& status)
return result;
}
- result.init(localeID.data(), /*canonicalize=*/FALSE);
+ result.init(localeID.data(), /*canonicalize=*/false);
if (result.isBogus()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -2179,7 +2178,7 @@ Locale::toLanguageTag(ByteSink& sink, UErrorCode& status) const
return;
}
- ulocimp_toLanguageTag(fullName, sink, /*strict=*/FALSE, &status);
+ ulocimp_toLanguageTag(fullName, sink, /*strict=*/false, &status);
}
Locale U_EXPORT2
@@ -2187,7 +2186,7 @@ Locale::createFromName (const char *name)
{
if (name) {
Locale l("");
- l.init(name, FALSE);
+ l.init(name, false);
return l;
}
else {
@@ -2198,7 +2197,7 @@ Locale::createFromName (const char *name)
Locale U_EXPORT2
Locale::createCanonical(const char* name) {
Locale loc("");
- loc.init(name, TRUE);
+ loc.init(name, true);
return loc;
}
@@ -2241,7 +2240,7 @@ const char* const* U_EXPORT2 Locale::getISOLanguages()
// Set the locale's data based on a posix id.
void Locale::setFromPOSIXID(const char *posixID)
{
- init(posixID, TRUE);
+ init(posixID, true);
}
const Locale & U_EXPORT2
@@ -2531,7 +2530,7 @@ Locale::createKeywords(UErrorCode &status) const
if(assignment > variantStart) {
CharString keywords;
CharStringByteSink sink(&keywords);
- ulocimp_getKeywords(variantStart+1, '@', sink, FALSE, &status);
+ ulocimp_getKeywords(variantStart+1, '@', sink, false, &status);
if (U_SUCCESS(status) && !keywords.isEmpty()) {
result = new KeywordEnumeration(keywords.data(), keywords.length(), 0, status);
if (!result) {
@@ -2560,7 +2559,7 @@ Locale::createUnicodeKeywords(UErrorCode &status) const
if(assignment > variantStart) {
CharString keywords;
CharStringByteSink sink(&keywords);
- ulocimp_getKeywords(variantStart+1, '@', sink, FALSE, &status);
+ ulocimp_getKeywords(variantStart+1, '@', sink, false, &status);
if (U_SUCCESS(status) && !keywords.isEmpty()) {
result = new UnicodeKeywordEnumeration(keywords.data(), keywords.length(), 0, status);
if (!result) {
diff --git a/thirdparty/icu4c/common/loclikely.cpp b/thirdparty/icu4c/common/loclikely.cpp
index d80096b588..ec0dca28a4 100644
--- a/thirdparty/icu4c/common/loclikely.cpp
+++ b/thirdparty/icu4c/common/loclikely.cpp
@@ -201,7 +201,7 @@ createTagStringWithAlternates(
**/
char tagBuffer[ULOC_FULLNAME_CAPACITY];
int32_t tagLength = 0;
- UBool regionAppended = FALSE;
+ UBool regionAppended = false;
if (langLength > 0) {
appendTag(
@@ -209,7 +209,7 @@ createTagStringWithAlternates(
langLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/FALSE);
+ /*withSeparator=*/false);
}
else if (alternateTags == NULL) {
/*
@@ -246,7 +246,7 @@ createTagStringWithAlternates(
alternateLangLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/FALSE);
+ /*withSeparator=*/false);
}
}
@@ -256,7 +256,7 @@ createTagStringWithAlternates(
scriptLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/TRUE);
+ /*withSeparator=*/true);
}
else if (alternateTags != NULL) {
/*
@@ -281,7 +281,7 @@ createTagStringWithAlternates(
alternateScriptLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/TRUE);
+ /*withSeparator=*/true);
}
}
@@ -291,9 +291,9 @@ createTagStringWithAlternates(
regionLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/TRUE);
+ /*withSeparator=*/true);
- regionAppended = TRUE;
+ regionAppended = true;
}
else if (alternateTags != NULL) {
/*
@@ -317,9 +317,9 @@ createTagStringWithAlternates(
alternateRegionLength,
tagBuffer,
&tagLength,
- /*withSeparator=*/TRUE);
+ /*withSeparator=*/true);
- regionAppended = TRUE;
+ regionAppended = true;
}
}
@@ -622,7 +622,7 @@ createLikelySubtagsString(
likelySubtags,
sink,
err);
- return TRUE;
+ return true;
}
}
@@ -678,7 +678,7 @@ createLikelySubtagsString(
likelySubtags,
sink,
err);
- return TRUE;
+ return true;
}
}
@@ -734,7 +734,7 @@ createLikelySubtagsString(
likelySubtags,
sink,
err);
- return TRUE;
+ return true;
}
}
@@ -789,11 +789,11 @@ createLikelySubtagsString(
likelySubtags,
sink,
err);
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
error:
@@ -801,7 +801,7 @@ error:
*err = U_ILLEGAL_ARGUMENT_ERROR;
}
- return FALSE;
+ return false;
}
#define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) UPRV_BLOCK_MACRO_BEGIN { \
@@ -836,7 +836,7 @@ _uloc_addLikelySubtags(const char* localeID,
const char* trailing = "";
int32_t trailingLength = 0;
int32_t trailingIndex = 0;
- UBool success = FALSE;
+ UBool success = false;
if(U_FAILURE(*err)) {
goto error;
@@ -901,7 +901,7 @@ error:
if (!U_FAILURE(*err)) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
}
- return FALSE;
+ return false;
}
// Add likely subtags to the sink
@@ -925,7 +925,7 @@ _uloc_minimizeSubtags(const char* localeID,
const char* trailing = "";
int32_t trailingLength = 0;
int32_t trailingIndex = 0;
- UBool successGetMax = FALSE;
+ UBool successGetMax = false;
if(U_FAILURE(*err)) {
goto error;
@@ -1248,7 +1248,7 @@ _ulocimp_addLikelySubtags(const char* localeID,
if (U_SUCCESS(*status)) {
return _uloc_addLikelySubtags(localeBuffer.getBuffer(), sink, status);
} else {
- return FALSE;
+ return false;
}
}
@@ -1320,14 +1320,14 @@ uloc_isRightToLeft(const char *locale) {
char lang[8];
int32_t langLength = uloc_getLanguage(locale, lang, UPRV_LENGTHOF(lang), &errorCode);
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
- return FALSE;
+ return false;
}
if (langLength > 0) {
const char* langPtr = uprv_strstr(LANG_DIR_STRING, lang);
if (langPtr != NULL) {
switch (langPtr[langLength]) {
- case '-': return FALSE;
- case '+': return TRUE;
+ case '-': return false;
+ case '+': return true;
default: break; // partial match of a longer code
}
}
@@ -1340,12 +1340,12 @@ uloc_isRightToLeft(const char *locale) {
ulocimp_addLikelySubtags(locale, sink, &errorCode);
}
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
- return FALSE;
+ return false;
}
scriptLength = uloc_getScript(likely.data(), script, UPRV_LENGTHOF(script), &errorCode);
if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING ||
scriptLength == 0) {
- return FALSE;
+ return false;
}
}
UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script);
@@ -1392,7 +1392,7 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion,
if (U_FAILURE(*status)) {
rgLen = 0;
} else if (rgLen == 0 && inferRegion) {
- // no unicode_region_subtag but inferRegion TRUE, try likely subtags
+ // no unicode_region_subtag but inferRegion true, try likely subtags
rgStatus = U_ZERO_ERROR;
icu::CharString locBuf;
{
diff --git a/thirdparty/icu4c/common/loclikelysubtags.cpp b/thirdparty/icu4c/common/loclikelysubtags.cpp
index aa592e6ea8..e913c66a35 100644
--- a/thirdparty/icu4c/common/loclikelysubtags.cpp
+++ b/thirdparty/icu4c/common/loclikelysubtags.cpp
@@ -233,7 +233,7 @@ private:
return false;
}
for (int i = 0; i < length; ++i) {
- stringArray.getValue(i, value); // returns TRUE because i < length
+ stringArray.getValue(i, value); // returns true because i < length
rawIndexes[i] = strings.add(value.getUnicodeString(errorCode), errorCode);
if (U_FAILURE(errorCode)) { return false; }
}
@@ -245,13 +245,13 @@ private:
namespace {
XLikelySubtags *gLikelySubtags = nullptr;
-UInitOnce gInitOnce = U_INITONCE_INITIALIZER;
+UInitOnce gInitOnce {};
UBool U_CALLCONV cleanup() {
delete gLikelySubtags;
gLikelySubtags = nullptr;
gInitOnce.reset();
- return TRUE;
+ return true;
}
} // namespace
diff --git a/thirdparty/icu4c/common/locmap.cpp b/thirdparty/icu4c/common/locmap.cpp
index 29a5646385..78cfd1ca86 100644
--- a/thirdparty/icu4c/common/locmap.cpp
+++ b/thirdparty/icu4c/common/locmap.cpp
@@ -1053,7 +1053,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
{
uint16_t langID;
uint32_t localeIndex;
- UBool bLookup = TRUE;
+ UBool bLookup = true;
const char *pPosixID = NULL;
#if U_PLATFORM_HAS_WIN32_API && UCONFIG_USE_WINDOWS_LCID_MAPPING_API
@@ -1074,7 +1074,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
if (tmpLen > 1) {
int32_t i = 0;
// Only need to look up in table if have _, eg for de-de_phoneb type alternate sort.
- bLookup = FALSE;
+ bLookup = false;
for (i = 0; i < UPRV_LENGTHOF(locName); i++)
{
locName[i] = (char)(windowsLocaleName[i]);
@@ -1088,7 +1088,7 @@ uprv_convertToPosix(uint32_t hostid, char *posixID, int32_t posixIDCapacity, UEr
// TODO: Should these be mapped from _phoneb to @collation=phonebook, etc.?
locName[i] = '\0';
tmpLen = i;
- bLookup = TRUE;
+ bLookup = true;
break;
}
else if (windowsLocaleName[i] == L'-')
@@ -1201,7 +1201,7 @@ uprv_convertToLCIDPlatform(const char* localeID, UErrorCode* status)
char asciiBCP47Tag[LOCALE_NAME_MAX_LENGTH] = {};
// this will change it from de_DE@collation=phonebook to de-DE-u-co-phonebk form
- (void)uloc_toLanguageTag(mylocaleID, asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), FALSE, status);
+ (void)uloc_toLanguageTag(mylocaleID, asciiBCP47Tag, UPRV_LENGTHOF(asciiBCP47Tag), false, status);
if (U_SUCCESS(*status))
{
diff --git a/thirdparty/icu4c/common/locutil.cpp b/thirdparty/icu4c/common/locutil.cpp
index 3d9d69ff7e..6e2bd497f8 100644
--- a/thirdparty/icu4c/common/locutil.cpp
+++ b/thirdparty/icu4c/common/locutil.cpp
@@ -21,7 +21,7 @@
#include "umutex.h"
// see LocaleUtility::getAvailableLocaleNames
-static icu::UInitOnce LocaleUtilityInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce LocaleUtilityInitOnce {};
static icu::Hashtable * LocaleUtility_cache = NULL;
#define UNDERSCORE_CHAR ((UChar)0x005f)
@@ -41,7 +41,7 @@ static UBool U_CALLCONV service_cleanup(void) {
delete LocaleUtility_cache;
LocaleUtility_cache = NULL;
}
- return TRUE;
+ return true;
}
diff --git a/thirdparty/icu4c/common/messageimpl.h b/thirdparty/icu4c/common/messageimpl.h
index a56479066b..061df9189d 100644
--- a/thirdparty/icu4c/common/messageimpl.h
+++ b/thirdparty/icu4c/common/messageimpl.h
@@ -55,7 +55,7 @@ public:
UnicodeString &result);
private:
- MessageImpl(); // no constructor: all static methods
+ MessageImpl() = delete; // no constructor: all static methods
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/messagepattern.cpp b/thirdparty/icu4c/common/messagepattern.cpp
index 66fd2f4c93..52afab5f02 100644
--- a/thirdparty/icu4c/common/messagepattern.cpp
+++ b/thirdparty/icu4c/common/messagepattern.cpp
@@ -97,9 +97,9 @@ public:
UBool ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode);
UBool equals(const MessagePatternList<T, stackCapacity> &other, int32_t length) const {
for(int32_t i=0; i<length; ++i) {
- if(a[i]!=other.a[i]) { return FALSE; }
+ if(a[i]!=other.a[i]) { return false; }
}
- return TRUE;
+ return true;
}
MaybeStackArray<T, stackCapacity> a;
@@ -124,13 +124,13 @@ template<typename T, int32_t stackCapacity>
UBool
MessagePatternList<T, stackCapacity>::ensureCapacityForOneMore(int32_t oldLength, UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
if(a.getCapacity()>oldLength || a.resize(2*oldLength, oldLength)!=NULL) {
- return TRUE;
+ return true;
}
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
// MessagePatternList specializations -------------------------------------- ***
@@ -147,7 +147,7 @@ MessagePattern::MessagePattern(UErrorCode &errorCode)
: aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
partsList(NULL), parts(NULL), partsLength(0),
numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),
- hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) {
+ hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
init(errorCode);
}
@@ -155,7 +155,7 @@ MessagePattern::MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &e
: aposMode(mode),
partsList(NULL), parts(NULL), partsLength(0),
numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),
- hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) {
+ hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
init(errorCode);
}
@@ -163,7 +163,7 @@ MessagePattern::MessagePattern(const UnicodeString &pattern, UParseError *parseE
: aposMode(UCONFIG_MSGPAT_DEFAULT_APOSTROPHE_MODE),
partsList(NULL), parts(NULL), partsLength(0),
numericValuesList(NULL), numericValues(NULL), numericValuesLength(0),
- hasArgNames(FALSE), hasArgNumbers(FALSE), needsAutoQuoting(FALSE) {
+ hasArgNames(false), hasArgNumbers(false), needsAutoQuoting(false) {
if(init(errorCode)) {
parse(pattern, parseError, errorCode);
}
@@ -172,15 +172,15 @@ MessagePattern::MessagePattern(const UnicodeString &pattern, UParseError *parseE
UBool
MessagePattern::init(UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
partsList=new MessagePatternPartsList();
if(partsList==NULL) {
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
parts=partsList->a.getAlias();
- return TRUE;
+ return true;
}
MessagePattern::MessagePattern(const MessagePattern &other)
@@ -215,7 +215,7 @@ MessagePattern::operator=(const MessagePattern &other) {
UBool
MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
parts=NULL;
partsLength=0;
@@ -225,14 +225,14 @@ MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode)
partsList=new MessagePatternPartsList();
if(partsList==NULL) {
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
parts=partsList->a.getAlias();
}
if(other.partsLength>0) {
partsList->copyFrom(*other.partsList, other.partsLength, errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
parts=partsList->a.getAlias();
partsLength=other.partsLength;
@@ -242,19 +242,19 @@ MessagePattern::copyStorage(const MessagePattern &other, UErrorCode &errorCode)
numericValuesList=new MessagePatternDoubleList();
if(numericValuesList==NULL) {
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
numericValues=numericValuesList->a.getAlias();
}
numericValuesList->copyFrom(
*other.numericValuesList, other.numericValuesLength, errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
numericValues=numericValuesList->a.getAlias();
numericValuesLength=other.numericValuesLength;
}
- return TRUE;
+ return true;
}
MessagePattern::~MessagePattern() {
@@ -303,8 +303,8 @@ void
MessagePattern::clear() {
// Mostly the same as preParse().
msg.remove();
- hasArgNames=hasArgNumbers=FALSE;
- needsAutoQuoting=FALSE;
+ hasArgNames=hasArgNumbers=false;
+ needsAutoQuoting=false;
partsLength=0;
numericValuesLength=0;
}
@@ -414,8 +414,8 @@ MessagePattern::preParse(const UnicodeString &pattern, UParseError *parseError,
parseError->postContext[0]=0;
}
msg=pattern;
- hasArgNames=hasArgNumbers=FALSE;
- needsAutoQuoting=FALSE;
+ hasArgNames=hasArgNumbers=false;
+ needsAutoQuoting=false;
partsLength=0;
numericValuesLength=0;
}
@@ -458,7 +458,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
// Add a Part for auto-quoting.
addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
u_apos, errorCode); // value=char to be inserted
- needsAutoQuoting=TRUE;
+ needsAutoQuoting=true;
} else {
c=msg.charAt(index);
if(c==u_apos) {
@@ -491,7 +491,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
// Add a Part for auto-quoting.
addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
u_apos, errorCode); // value=char to be inserted
- needsAutoQuoting=TRUE;
+ needsAutoQuoting=true;
break;
}
}
@@ -500,7 +500,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
// Add a Part for auto-quoting.
addPart(UMSGPAT_PART_TYPE_INSERT_CHAR, index, 0,
u_apos, errorCode); // value=char to be inserted
- needsAutoQuoting=TRUE;
+ needsAutoQuoting=true;
}
}
} else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound) {
@@ -560,7 +560,7 @@ MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingL
errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
- hasArgNumbers=TRUE;
+ hasArgNumbers=true;
addPart(UMSGPAT_PART_TYPE_ARG_NUMBER, nameIndex, length, number, errorCode);
} else if(number==UMSGPAT_ARG_NAME_NOT_NUMBER) {
int32_t length=index-nameIndex;
@@ -569,7 +569,7 @@ MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingL
errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
- hasArgNames=TRUE;
+ hasArgNames=true;
addPart(UMSGPAT_PART_TYPE_ARG_NAME, nameIndex, length, 0, errorCode);
} else { // number<-1 (ARG_NAME_NOT_VALID)
setParseError(parseError, nameIndex); // Bad argument syntax.
@@ -727,7 +727,7 @@ MessagePattern::parseChoiceStyle(int32_t index, int32_t nestingLevel,
errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
- parseDouble(numberIndex, index, TRUE, parseError, errorCode); // adds ARG_INT or ARG_DOUBLE
+ parseDouble(numberIndex, index, true, parseError, errorCode); // adds ARG_INT or ARG_DOUBLE
if(U_FAILURE(errorCode)) {
return 0;
}
@@ -774,8 +774,8 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
return 0;
}
int32_t start=index;
- UBool isEmpty=TRUE;
- UBool hasOther=FALSE;
+ UBool isEmpty=true;
+ UBool hasOther=false;
for(;;) {
// First, collect the selector looking for a small set of terminators.
// It would be a little faster to consider the syntax of each possible
@@ -811,7 +811,7 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
return 0;
}
addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);
- parseDouble(selectorIndex+1, index, FALSE,
+ parseDouble(selectorIndex+1, index, false,
parseError, errorCode); // adds ARG_INT or ARG_DOUBLE
} else {
index=skipIdentifier(index);
@@ -845,12 +845,12 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
errorCode=U_INDEX_OUTOFBOUNDS_ERROR;
return 0;
}
- parseDouble(valueIndex, index, FALSE,
+ parseDouble(valueIndex, index, false,
parseError, errorCode); // adds ARG_INT or ARG_DOUBLE
if(U_FAILURE(errorCode)) {
return 0;
}
- isEmpty=FALSE;
+ isEmpty=false;
continue; // no message fragment after the offset
} else {
// normal selector word
@@ -861,7 +861,7 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
}
addPart(UMSGPAT_PART_TYPE_ARG_SELECTOR, selectorIndex, length, 0, errorCode);
if(0==msg.compare(selectorIndex, length, kOther, 0, 5)) {
- hasOther=TRUE;
+ hasOther=true;
}
}
}
@@ -880,7 +880,7 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
if(U_FAILURE(errorCode)) {
return 0;
}
- isEmpty=FALSE;
+ isEmpty=false;
}
}
@@ -901,11 +901,11 @@ MessagePattern::parseArgNumber(const UnicodeString &s, int32_t start, int32_t li
return 0;
} else {
number=0;
- badNumber=TRUE; // leading zero
+ badNumber=true; // leading zero
}
} else if(0x31<=c && c<=0x39) {
number=c-0x30;
- badNumber=FALSE;
+ badNumber=false;
} else {
return UMSGPAT_ARG_NAME_NOT_NUMBER;
}
@@ -913,7 +913,7 @@ MessagePattern::parseArgNumber(const UnicodeString &s, int32_t start, int32_t li
c=s.charAt(start++);
if(0x30<=c && c<=0x39) {
if(number>=INT32_MAX/10) {
- badNumber=TRUE; // overflow
+ badNumber=true; // overflow
}
number=number*10+(c-0x30);
} else {
diff --git a/thirdparty/icu4c/common/norm2_nfc_data.h b/thirdparty/icu4c/common/norm2_nfc_data.h
index a774868981..ebe3e6ba90 100644
--- a/thirdparty/icu4c/common/norm2_nfc_data.h
+++ b/thirdparty/icu4c/common/norm2_nfc_data.h
@@ -10,14 +10,14 @@
#ifdef INCLUDED_FROM_NORMALIZER2_CPP
static const UVersionInfo norm2_nfc_data_formatVersion={4,0,0,0};
-static const UVersionInfo norm2_nfc_data_dataVersion={0xe,0,0,0};
+static const UVersionInfo norm2_nfc_data_dataVersion={0xf,0,0,0};
static const int32_t norm2_nfc_data_indexes[Normalizer2Impl::IX_COUNT]={
-0x50,0x4c54,0x88bc,0x89bc,0x89bc,0x89bc,0x89bc,0x89bc,0xc0,0x300,0xae2,0x29e0,0x3c66,0xfc00,0x1288,0x3b9c,
+0x50,0x4cb8,0x8920,0x8a20,0x8a20,0x8a20,0x8a20,0x8a20,0xc0,0x300,0xae2,0x29e0,0x3c66,0xfc00,0x1288,0x3b9c,
0x3c34,0x3c66,0x300,0
};
-static const uint16_t norm2_nfc_data_trieIndex[1748]={
+static const uint16_t norm2_nfc_data_trieIndex[1788]={
0,0x40,0x7b,0xbb,0xfb,0x13a,0x17a,0x1b2,0x1f2,0x226,0x254,0x226,0x294,0x2d4,0x313,0x353,
0x393,0x3d2,0x40f,0x44e,0x226,0x226,0x488,0x4c8,0x4f8,0x530,0x226,0x570,0x59f,0x5de,0x226,0x5f3,
0x631,0x65f,0x687,0x6bd,0x6fd,0x73a,0x75a,0x799,0x7d8,0x815,0x834,0x871,0x75a,0x8aa,0x8d8,0x917,
@@ -82,14 +82,14 @@ static const uint16_t norm2_nfc_data_trieIndex[1748]={
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x1880,0x18c0,0x1900,0x1940,0x1980,0x19c0,0x1a00,0x1a40,0x1a63,0x1aa3,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1ac3,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x657,0x666,0x67e,0x69d,0x6b2,0x6b2,0x6b2,0x6b6,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x67e,0x68e,0x6a6,0x6c5,0x6da,0x6da,0x6da,0x6de,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0xc0b,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x54f,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x40c,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1af6,0x226,0x226,0x1b06,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0xdf7,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1b16,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1607,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1607,0x226,0x226,0x226,0x226,0x66b,0x226,0x226,0x226,
0x226,0x1b20,0x54f,0x226,0x226,0x1b30,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x81c,0x226,0x226,
0x1b40,0x226,0x1b50,0x1b5d,0x1b69,0x226,0x226,0x226,0x226,0x414,0x226,0x1b74,0x1b84,0x226,0x226,0x226,
0x811,0x226,0x226,0x226,0x226,0x1b94,0x226,0x226,0x226,0x1b9f,0x226,0x226,0x226,0x226,0x226,0x226,
@@ -104,33 +104,35 @@ static const uint16_t norm2_nfc_data_trieIndex[1748]={
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x9eb,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0xc05,0x226,0x226,0x226,
0x226,0x81b,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x1c3d,0x226,0x226,0x226,0xf2c,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0xc08,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0x1c3d,0x226,0x226,0x226,0xf2c,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x1c4d,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1c4f,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1c4d,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x1c4f,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1c5e,0x1c6e,0x1c7c,0x1c89,0x226,
+0x1c95,0x1ca3,0x1cb3,0x226,0x226,0x226,0x226,0xd1b,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x226,0x1c5e,0x1c6e,0x1c7c,0x1c89,0x226,0x1c95,0x1ca3,0x1cb3,0x226,0x226,
-0x226,0x226,0xd1b,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1cc3,0x1ccb,
-0x1cd9,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0xf2c,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x7c9,0x226,
-0x226,0x226,0x4fc,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x1ce9,0x226,0x226,0x226,0x226,0x226,0x226,0x1cf5,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1d05,0x1d15,0x1d25,0x1d35,0x1d45,0x1d55,0x1d65,0x1d75,0x1d85,
-0x1d95,0x1da5,0x1db5,0x1dc5,0x1dd5,0x1de5,0x1df5,0x1e05,0x1e15,0x1e25,0x1e35,0x1e45,0x1e55,0x1e65,0x1e75,0x1e85,
-0x1e95,0x1ea5,0x1eb5,0x1ec5,0x1ed5,0x1ee5,0x1ef5,0x1f05,0x1f15,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x1cc3,0x1ccb,0x1cd9,0x226,0x226,0x226,0x226,0x226,0x4f9,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0xf2c,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x7c9,0x226,0x226,0x226,0x4fc,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1ce4,0x226,0x226,0x226,0x226,0x226,0x226,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1cf4,0x226,0x226,0x226,0x226,
+0x226,0x226,0x1d00,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x1d10,0x1d20,
+0x1d30,0x1d40,0x1d50,0x1d60,0x1d70,0x1d80,0x1d90,0x1da0,0x1db0,0x1dc0,0x1dd0,0x1de0,0x1df0,0x1e00,0x1e10,0x1e20,
+0x1e30,0x1e40,0x1e50,0x1e60,0x1e70,0x1e80,0x1e90,0x1ea0,0x1eb0,0x1ec0,0x1ed0,0x1ee0,0x1ef0,0x1f00,0x1f10,0x1f20,
0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,
-0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x408,0x428,0xc4,0xc4,0xc4,0x448,0x457,0x46d,0x489,
-0x4a6,0x4c2,0x4df,0x4fc,0x51b,0x538,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
-0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0x552,0xc4,0x566,0xc4,0xc4,
+0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x226,0x408,0x428,
+0xc4,0xc4,0xc4,0x448,0x457,0x46d,0x489,0x4a6,0x4c2,0x4df,0x4fc,0x51b,0x538,0x552,0xc4,0xc4,
0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
-0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0x586,0xc4,0xc4,0xc4,
-0xc4,0xc4,0xc4,0xc4,0xc4,0x591,0x5ae,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0x5ce,0x5e4,0xc4,
-0xc4,0x5f7,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
+0xc4,0xc4,0xc4,0x567,0xc4,0x57b,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
-0xc4,0xc4,0x617,0x637
+0xc4,0xc4,0xc4,0xc4,0x59b,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0x5a6,0x5c3,0xc4,
+0xc4,0xc4,0xc4,0xc4,0xc4,0x5e3,0x5f9,0x60b,0xc4,0x61e,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
+0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,
+0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0xc4,0x63e,0x65e
};
-static const uint16_t norm2_nfc_data_trieData[7974]={
+static const uint16_t norm2_nfc_data_trieData[7984]={
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -518,7 +520,7 @@ static const uint16_t norm2_nfc_data_trieData[7974]={
1,1,1,1,1,0x3c66,1,0x3c66,0x3c66,0x3c66,0x3c66,0x3c66,0x3c66,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x3c66,
0x3c66,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,0x3c66,1,1,1,1,0x3c66,1,1,1,0x3c66,1,0x3c66,
+1,1,1,1,0x3c66,1,1,1,1,0x3c66,1,1,1,0x3c66,0x3c66,0x3c66,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
@@ -593,49 +595,49 @@ static const uint16_t norm2_nfc_data_trieData[7974]={
0x3304,0x331c,0x3334,0x334c,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,
0xffcc,0xffcc,0xffcc,0xffcc,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,1,0xffcc,0xffcc,1,0xffcc,
-0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,
-1,1,1,1,1,1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xfe0e,
-1,1,1,1,1,0x335b,0x335f,0x3363,0x3367,0x336d,0x2f4d,0x3371,0x3375,0x3379,0x337d,0x2f51,
-0x3381,0x3385,0x3389,0x2f55,0x338f,0x3393,0x3397,0x339b,0x33a1,0x33a5,0x33a9,0x33ad,0x33b3,0x33b7,0x33bb,0x33bf,
-0x303f,0x33c3,0x33c9,0x33cd,0x33d1,0x33d5,0x33d9,0x33dd,0x33e1,0x33e5,0x3053,0x2f59,0x2f5d,0x3057,0x33e9,0x33ed,
-0x2c59,0x33f1,0x2f61,0x33f5,0x33f9,0x33fd,0x3401,0x3401,0x3401,0x3405,0x340b,0x340f,0x3413,0x3417,0x341d,0x3421,
-0x3425,0x3429,0x342d,0x3431,0x3435,0x3439,0x343d,0x3441,0x3445,0x3449,0x344d,0x344d,0x305f,0x3451,0x3455,0x3459,
-0x345d,0x2f69,0x3461,0x3465,0x3469,0x2ebd,0x346d,0x3471,0x3475,0x3479,0x347d,0x3481,0x3485,0x3489,0x348d,0x3493,
-0x3497,0x349b,0x349f,0x34a3,0x34a7,0x34ab,0x34b1,0x34b7,0x34bb,0x34bf,0x34c3,0x34c7,0x34cb,0x34cf,0x34d3,0x34d7,
-0x34d7,0x34db,0x34e1,0x34e5,0x2c49,0x34e9,0x34ed,0x34f3,0x34f7,0x34fb,0x34ff,0x3503,0x3507,0x2f7d,0x350b,0x350f,
-0x3513,0x3519,0x351d,0x3523,0x3527,0x352b,0x352f,0x3533,0x3537,0x353b,0x353f,0x3543,0x3547,0x354b,0x354f,0x3555,
-0x3559,0x355d,0x3561,0x2b71,0x3565,0x356b,0x356f,0x356f,0x3575,0x3579,0x3579,0x357d,0x3581,0x3587,0x358d,0x3591,
-0x3595,0x3599,0x359d,0x35a1,0x35a5,0x35a9,0x35ad,0x35b1,0x2f81,0x35b5,0x35bb,0x35bf,0x35c3,0x308f,0x35c3,0x35c7,
-0x2f89,0x35cb,0x35cf,0x35d3,0x35d7,0x2f8d,0x2b05,0x35db,0x35df,0x35e3,0x35e7,0x35eb,0x35ef,0x35f3,0x35f9,0x35fd,
-0x3601,0x3605,0x3609,0x360d,0x3613,0x3617,0x361b,0x361f,0x3623,0x3627,0x362b,0x362f,0x3633,0x2f91,0x3637,0x363b,
-0x3641,0x3645,0x3649,0x364d,0x2f99,0x3651,0x3655,0x3659,0x365d,0x3661,0x3665,0x3669,0x366d,0x2b75,0x30af,0x3671,
-0x3675,0x3679,0x367d,0x3683,0x3687,0x368b,0x368f,0x2f9d,0x3693,0x3699,0x369d,0x36a1,0x3161,0x36a5,0x36a9,0x36ad,
-0x36b1,0x36b5,0x36bb,0x36bf,0x36c3,0x36c7,0x36cd,0x36d1,0x36d5,0x36d9,0x2c8d,0x36dd,0x36e1,0x36e7,0x36ed,0x36f3,
-0x36f7,0x36fd,0x3701,0x3705,0x3709,0x370d,0x2fa1,0x2de9,0x3711,0x3715,0x3719,0x371d,0x3723,0x3727,0x372b,0x372f,
-0x30bf,0x3733,0x3737,0x373d,0x3741,0x3745,0x374b,0x3751,0x3755,0x30c3,0x3759,0x375d,0x3761,0x3765,0x3769,0x376d,
-0x3771,0x3777,0x377b,0x3781,0x3785,0x378b,0x30cb,0x378f,0x3793,0x3799,0x379d,0x37a1,0x37a7,0x37ad,0x37b1,0x37b5,
-0x37b9,0x37bd,0x37bd,0x37c1,0x37c5,0x30d3,0x37c9,0x37cd,0x37d1,0x37d5,0x37d9,0x37df,0x37e3,0x2c55,0x37e9,0x37ef,
-0x37f3,0x37f9,0x37ff,0x3805,0x3809,0x30eb,0x380d,0x3813,0x3819,0x381f,0x3825,0x3829,0x3829,0x30ef,0x3169,0x382d,
-0x3831,0x3835,0x3839,0x383f,0x2bbd,0x30f7,0x3843,0x3847,0x2fcd,0x384d,0x3853,0x2f15,0x3859,0x385d,0x2fdd,0x3861,
-0x3865,0x3869,0x386f,0x386f,0x3875,0x3879,0x387d,0x3883,0x3887,0x388b,0x388f,0x3895,0x3899,0x389d,0x38a1,0x38a5,
-0x38a9,0x38af,0x38b3,0x38b7,0x38bb,0x38bf,0x38c3,0x38c7,0x38cd,0x38d3,0x38d7,0x38dd,0x38e1,0x38e7,0x38eb,0x2ff5,
-0x38ef,0x38f5,0x38fb,0x38ff,0x3905,0x3909,0x390f,0x3913,0x3917,0x391b,0x391f,0x3923,0x3927,0x392d,0x3933,0x3939,
-0x3575,0x393f,0x3943,0x3947,0x394b,0x394f,0x3953,0x3957,0x395b,0x395f,0x3963,0x3967,0x396b,0x2c9d,0x3971,0x3975,
-0x3979,0x397d,0x3981,0x3985,0x3001,0x3989,0x398d,0x3991,0x3995,0x3999,0x399f,0x39a5,0x39ab,0x39af,0x39b3,0x39b7,
-0x39bb,0x39c1,0x39c5,0x39cb,0x39cf,0x39d3,0x39d9,0x39df,0x39e3,0x2ba9,0x39e7,0x39eb,0x39ef,0x39f3,0x39f7,0x39fb,
-0x3113,0x39ff,0x3a03,0x3a07,0x3a0b,0x3a0f,0x3a13,0x3a17,0x3a1b,0x3a1f,0x3a23,0x3a29,0x3a2d,0x3a31,0x3a35,0x3a39,
-0x3a3d,0x3a43,0x3a49,0x3a4d,0x3a51,0x3127,0x312b,0x3a55,0x3a59,0x3a5f,0x3a63,0x3a67,0x3a6b,0x3a6f,0x3a75,0x3a7b,
-0x3a7f,0x3a83,0x3a87,0x3a8d,0x312f,0x3a91,0x3a97,0x3a9d,0x3aa1,0x3aa5,0x3aa9,0x3aaf,0x3ab3,0x3ab7,0x3abb,0x3abf,
-0x3ac3,0x3ac7,0x3acb,0x3ad1,0x3ad5,0x3ad9,0x3add,0x3ae3,0x3ae7,0x3aeb,0x3aef,0x3af3,0x3af9,0x3aff,0x3b03,0x3b07,
-0x3b0b,0x3b11,0x3b15,0x3147,0x3147,0x3b1b,0x3b1f,0x3b25,0x3b29,0x3b2d,0x3b31,0x3b35,0x3b39,0x3b3d,0x3b41,0x314b,
-0x3b47,0x3b4b,0x3b4f,0x3b53,0x3b57,0x3b5b,0x3b61,0x3b65,0x3b6b,0x3b71,0x3b77,0x3b7b,0x3b7f,0x3b83,0x3b87,0x3b8b,
-0x3b8f,0x3b93,0x3b97,1,1,1
+0xffcc,0xffcc,0xffcc,0xffcc,1,1,1,1,1,1,1,1,1,1,1,1,
+0xffd0,0xffd0,0xffb8,0xffcc,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,0xffb8,1,1,1,1,1,
+1,1,1,1,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xffcc,0xfe0e,1,1,1,1,1,
+0x335b,0x335f,0x3363,0x3367,0x336d,0x2f4d,0x3371,0x3375,0x3379,0x337d,0x2f51,0x3381,0x3385,0x3389,0x2f55,0x338f,
+0x3393,0x3397,0x339b,0x33a1,0x33a5,0x33a9,0x33ad,0x33b3,0x33b7,0x33bb,0x33bf,0x303f,0x33c3,0x33c9,0x33cd,0x33d1,
+0x33d5,0x33d9,0x33dd,0x33e1,0x33e5,0x3053,0x2f59,0x2f5d,0x3057,0x33e9,0x33ed,0x2c59,0x33f1,0x2f61,0x33f5,0x33f9,
+0x33fd,0x3401,0x3401,0x3401,0x3405,0x340b,0x340f,0x3413,0x3417,0x341d,0x3421,0x3425,0x3429,0x342d,0x3431,0x3435,
+0x3439,0x343d,0x3441,0x3445,0x3449,0x344d,0x344d,0x305f,0x3451,0x3455,0x3459,0x345d,0x2f69,0x3461,0x3465,0x3469,
+0x2ebd,0x346d,0x3471,0x3475,0x3479,0x347d,0x3481,0x3485,0x3489,0x348d,0x3493,0x3497,0x349b,0x349f,0x34a3,0x34a7,
+0x34ab,0x34b1,0x34b7,0x34bb,0x34bf,0x34c3,0x34c7,0x34cb,0x34cf,0x34d3,0x34d7,0x34d7,0x34db,0x34e1,0x34e5,0x2c49,
+0x34e9,0x34ed,0x34f3,0x34f7,0x34fb,0x34ff,0x3503,0x3507,0x2f7d,0x350b,0x350f,0x3513,0x3519,0x351d,0x3523,0x3527,
+0x352b,0x352f,0x3533,0x3537,0x353b,0x353f,0x3543,0x3547,0x354b,0x354f,0x3555,0x3559,0x355d,0x3561,0x2b71,0x3565,
+0x356b,0x356f,0x356f,0x3575,0x3579,0x3579,0x357d,0x3581,0x3587,0x358d,0x3591,0x3595,0x3599,0x359d,0x35a1,0x35a5,
+0x35a9,0x35ad,0x35b1,0x2f81,0x35b5,0x35bb,0x35bf,0x35c3,0x308f,0x35c3,0x35c7,0x2f89,0x35cb,0x35cf,0x35d3,0x35d7,
+0x2f8d,0x2b05,0x35db,0x35df,0x35e3,0x35e7,0x35eb,0x35ef,0x35f3,0x35f9,0x35fd,0x3601,0x3605,0x3609,0x360d,0x3613,
+0x3617,0x361b,0x361f,0x3623,0x3627,0x362b,0x362f,0x3633,0x2f91,0x3637,0x363b,0x3641,0x3645,0x3649,0x364d,0x2f99,
+0x3651,0x3655,0x3659,0x365d,0x3661,0x3665,0x3669,0x366d,0x2b75,0x30af,0x3671,0x3675,0x3679,0x367d,0x3683,0x3687,
+0x368b,0x368f,0x2f9d,0x3693,0x3699,0x369d,0x36a1,0x3161,0x36a5,0x36a9,0x36ad,0x36b1,0x36b5,0x36bb,0x36bf,0x36c3,
+0x36c7,0x36cd,0x36d1,0x36d5,0x36d9,0x2c8d,0x36dd,0x36e1,0x36e7,0x36ed,0x36f3,0x36f7,0x36fd,0x3701,0x3705,0x3709,
+0x370d,0x2fa1,0x2de9,0x3711,0x3715,0x3719,0x371d,0x3723,0x3727,0x372b,0x372f,0x30bf,0x3733,0x3737,0x373d,0x3741,
+0x3745,0x374b,0x3751,0x3755,0x30c3,0x3759,0x375d,0x3761,0x3765,0x3769,0x376d,0x3771,0x3777,0x377b,0x3781,0x3785,
+0x378b,0x30cb,0x378f,0x3793,0x3799,0x379d,0x37a1,0x37a7,0x37ad,0x37b1,0x37b5,0x37b9,0x37bd,0x37bd,0x37c1,0x37c5,
+0x30d3,0x37c9,0x37cd,0x37d1,0x37d5,0x37d9,0x37df,0x37e3,0x2c55,0x37e9,0x37ef,0x37f3,0x37f9,0x37ff,0x3805,0x3809,
+0x30eb,0x380d,0x3813,0x3819,0x381f,0x3825,0x3829,0x3829,0x30ef,0x3169,0x382d,0x3831,0x3835,0x3839,0x383f,0x2bbd,
+0x30f7,0x3843,0x3847,0x2fcd,0x384d,0x3853,0x2f15,0x3859,0x385d,0x2fdd,0x3861,0x3865,0x3869,0x386f,0x386f,0x3875,
+0x3879,0x387d,0x3883,0x3887,0x388b,0x388f,0x3895,0x3899,0x389d,0x38a1,0x38a5,0x38a9,0x38af,0x38b3,0x38b7,0x38bb,
+0x38bf,0x38c3,0x38c7,0x38cd,0x38d3,0x38d7,0x38dd,0x38e1,0x38e7,0x38eb,0x2ff5,0x38ef,0x38f5,0x38fb,0x38ff,0x3905,
+0x3909,0x390f,0x3913,0x3917,0x391b,0x391f,0x3923,0x3927,0x392d,0x3933,0x3939,0x3575,0x393f,0x3943,0x3947,0x394b,
+0x394f,0x3953,0x3957,0x395b,0x395f,0x3963,0x3967,0x396b,0x2c9d,0x3971,0x3975,0x3979,0x397d,0x3981,0x3985,0x3001,
+0x3989,0x398d,0x3991,0x3995,0x3999,0x399f,0x39a5,0x39ab,0x39af,0x39b3,0x39b7,0x39bb,0x39c1,0x39c5,0x39cb,0x39cf,
+0x39d3,0x39d9,0x39df,0x39e3,0x2ba9,0x39e7,0x39eb,0x39ef,0x39f3,0x39f7,0x39fb,0x3113,0x39ff,0x3a03,0x3a07,0x3a0b,
+0x3a0f,0x3a13,0x3a17,0x3a1b,0x3a1f,0x3a23,0x3a29,0x3a2d,0x3a31,0x3a35,0x3a39,0x3a3d,0x3a43,0x3a49,0x3a4d,0x3a51,
+0x3127,0x312b,0x3a55,0x3a59,0x3a5f,0x3a63,0x3a67,0x3a6b,0x3a6f,0x3a75,0x3a7b,0x3a7f,0x3a83,0x3a87,0x3a8d,0x312f,
+0x3a91,0x3a97,0x3a9d,0x3aa1,0x3aa5,0x3aa9,0x3aaf,0x3ab3,0x3ab7,0x3abb,0x3abf,0x3ac3,0x3ac7,0x3acb,0x3ad1,0x3ad5,
+0x3ad9,0x3add,0x3ae3,0x3ae7,0x3aeb,0x3aef,0x3af3,0x3af9,0x3aff,0x3b03,0x3b07,0x3b0b,0x3b11,0x3b15,0x3147,0x3147,
+0x3b1b,0x3b1f,0x3b25,0x3b29,0x3b2d,0x3b31,0x3b35,0x3b39,0x3b3d,0x3b41,0x314b,0x3b47,0x3b4b,0x3b4f,0x3b53,0x3b57,
+0x3b5b,0x3b61,0x3b65,0x3b6b,0x3b71,0x3b77,0x3b7b,0x3b7f,0x3b83,0x3b87,0x3b8b,0x3b8f,0x3b93,0x3b97,1,1
};
static const UCPTrie norm2_nfc_data_trie={
norm2_nfc_data_trieIndex,
{ norm2_nfc_data_trieData },
- 1748, 7974,
+ 1788, 7984,
0x2fc00, 0x30,
0, 0,
0, 0,
diff --git a/thirdparty/icu4c/common/normalizer2.cpp b/thirdparty/icu4c/common/normalizer2.cpp
index 6be7e0b21a..3617264490 100644
--- a/thirdparty/icu4c/common/normalizer2.cpp
+++ b/thirdparty/icu4c/common/normalizer2.cpp
@@ -62,7 +62,7 @@ Normalizer2::normalizeUTF8(uint32_t /*options*/, StringPiece src, ByteSink &sink
UBool
Normalizer2::getRawDecomposition(UChar32, UnicodeString &) const {
- return FALSE;
+ return false;
}
UChar32
@@ -142,7 +142,7 @@ class NoopNormalizer2 : public Normalizer2 {
}
virtual UBool
getDecomposition(UChar32, UnicodeString &) const U_OVERRIDE {
- return FALSE;
+ return false;
}
// No need to U_OVERRIDE the default getRawDecomposition().
virtual UBool
@@ -161,9 +161,9 @@ class NoopNormalizer2 : public Normalizer2 {
spanQuickCheckYes(const UnicodeString &s, UErrorCode &) const U_OVERRIDE {
return s.length();
}
- virtual UBool hasBoundaryBefore(UChar32) const U_OVERRIDE { return TRUE; }
- virtual UBool hasBoundaryAfter(UChar32) const U_OVERRIDE { return TRUE; }
- virtual UBool isInert(UChar32) const U_OVERRIDE { return TRUE; }
+ virtual UBool hasBoundaryBefore(UChar32) const U_OVERRIDE { return true; }
+ virtual UBool hasBoundaryAfter(UChar32) const U_OVERRIDE { return true; }
+ virtual UBool isInert(UChar32) const U_OVERRIDE { return true; }
};
NoopNormalizer2::~NoopNormalizer2() {}
@@ -183,7 +183,7 @@ static UBool U_CALLCONV uprv_normalizer2_cleanup();
U_CDECL_END
static Normalizer2 *noopSingleton;
-static icu::UInitOnce noopInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce noopInitOnce {};
static void U_CALLCONV initNoopSingleton(UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
@@ -245,7 +245,7 @@ Norm2AllModes::createNFCInstance(UErrorCode &errorCode) {
static Norm2AllModes *nfcSingleton;
-static icu::UInitOnce nfcInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce nfcInitOnce {};
static void U_CALLCONV initNFCSingleton(UErrorCode &errorCode) {
nfcSingleton=Norm2AllModes::createNFCInstance(errorCode);
@@ -299,7 +299,7 @@ static UBool U_CALLCONV uprv_normalizer2_cleanup() {
nfcSingleton = NULL;
nfcInitOnce.reset();
#endif
- return TRUE;
+ return true;
}
U_CDECL_END
@@ -423,7 +423,7 @@ unorm2_normalizeSecondAndAppend(const UNormalizer2 *norm2,
return normalizeSecondAndAppend(norm2,
first, firstLength, firstCapacity,
second, secondLength,
- TRUE, pErrorCode);
+ true, pErrorCode);
}
U_CAPI int32_t U_EXPORT2
@@ -434,7 +434,7 @@ unorm2_append(const UNormalizer2 *norm2,
return normalizeSecondAndAppend(norm2,
first, firstLength, firstCapacity,
second, secondLength,
- FALSE, pErrorCode);
+ false, pErrorCode);
}
U_CAPI int32_t U_EXPORT2
diff --git a/thirdparty/icu4c/common/normalizer2impl.cpp b/thirdparty/icu4c/common/normalizer2impl.cpp
index e6bd75e717..d7e05e44d7 100644
--- a/thirdparty/icu4c/common/normalizer2impl.cpp
+++ b/thirdparty/icu4c/common/normalizer2impl.cpp
@@ -185,7 +185,7 @@ UBool ReorderingBuffer::init(int32_t destCapacity, UErrorCode &errorCode) {
if(start==NULL) {
// getBuffer() already did str.setToBogus()
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
limit=start+length;
remainingCapacity=str.getCapacity()-length;
@@ -201,7 +201,7 @@ UBool ReorderingBuffer::init(int32_t destCapacity, UErrorCode &errorCode) {
}
reorderStart=codePointLimit;
}
- return TRUE;
+ return true;
}
UBool ReorderingBuffer::equals(const UChar *otherStart, const UChar *otherLimit) const {
@@ -217,7 +217,7 @@ UBool ReorderingBuffer::equals(const uint8_t *otherStart, const uint8_t *otherLi
int32_t otherLength = (int32_t)(otherLimit - otherStart);
// For equal strings, UTF-8 is at least as long as UTF-16, and at most three times as long.
if (otherLength < length || (otherLength / 3) > length) {
- return FALSE;
+ return false;
}
// Compare valid strings from between normalization boundaries.
// (Invalid sequences are normalization-inert.)
@@ -225,21 +225,21 @@ UBool ReorderingBuffer::equals(const uint8_t *otherStart, const uint8_t *otherLi
if (i >= length) {
return j >= otherLength;
} else if (j >= otherLength) {
- return FALSE;
+ return false;
}
// Not at the end of either string yet.
UChar32 c, other;
U16_NEXT_UNSAFE(start, i, c);
U8_NEXT_UNSAFE(otherStart, j, other);
if (c != other) {
- return FALSE;
+ return false;
}
}
}
UBool ReorderingBuffer::appendSupplementary(UChar32 c, uint8_t cc, UErrorCode &errorCode) {
if(remainingCapacity<2 && !resize(2, errorCode)) {
- return FALSE;
+ return false;
}
if(lastCC<=cc || cc==0) {
limit[0]=U16_LEAD(c);
@@ -253,17 +253,17 @@ UBool ReorderingBuffer::appendSupplementary(UChar32 c, uint8_t cc, UErrorCode &e
insert(c, cc);
}
remainingCapacity-=2;
- return TRUE;
+ return true;
}
UBool ReorderingBuffer::append(const UChar *s, int32_t length, UBool isNFD,
uint8_t leadCC, uint8_t trailCC,
UErrorCode &errorCode) {
if(length==0) {
- return TRUE;
+ return true;
}
if(remainingCapacity<length && !resize(length, errorCode)) {
- return FALSE;
+ return false;
}
remainingCapacity-=length;
if(lastCC<=leadCC || leadCC==0) {
@@ -294,13 +294,13 @@ UBool ReorderingBuffer::append(const UChar *s, int32_t length, UBool isNFD,
append(c, leadCC, errorCode);
}
}
- return TRUE;
+ return true;
}
UBool ReorderingBuffer::appendZeroCC(UChar32 c, UErrorCode &errorCode) {
int32_t cpLength=U16_LENGTH(c);
if(remainingCapacity<cpLength && !resize(cpLength, errorCode)) {
- return FALSE;
+ return false;
}
remainingCapacity-=cpLength;
if(cpLength==1) {
@@ -312,23 +312,23 @@ UBool ReorderingBuffer::appendZeroCC(UChar32 c, UErrorCode &errorCode) {
}
lastCC=0;
reorderStart=limit;
- return TRUE;
+ return true;
}
UBool ReorderingBuffer::appendZeroCC(const UChar *s, const UChar *sLimit, UErrorCode &errorCode) {
if(s==sLimit) {
- return TRUE;
+ return true;
}
int32_t length=(int32_t)(sLimit-s);
if(remainingCapacity<length && !resize(length, errorCode)) {
- return FALSE;
+ return false;
}
u_memcpy(limit, s, length);
limit+=length;
remainingCapacity-=length;
lastCC=0;
reorderStart=limit;
- return TRUE;
+ return true;
}
void ReorderingBuffer::remove() {
@@ -365,12 +365,12 @@ UBool ReorderingBuffer::resize(int32_t appendLength, UErrorCode &errorCode) {
if(start==NULL) {
// getBuffer() already did str.setToBogus()
errorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
reorderStart=start+reorderStartIndex;
limit=start+length;
remainingCapacity=str.getCapacity()-length;
- return TRUE;
+ return true;
}
void ReorderingBuffer::skipPrevious() {
@@ -728,7 +728,7 @@ UBool Normalizer2Impl::decompose(UChar32 c, uint16_t norm16,
} else {
leadCC=0;
}
- return buffer.append((const UChar *)mapping+1, length, TRUE, leadCC, trailCC, errorCode);
+ return buffer.append((const UChar *)mapping+1, length, true, leadCC, trailCC, errorCode);
}
// Dual functionality:
@@ -820,11 +820,11 @@ Normalizer2Impl::decomposeUTF8(uint32_t options,
if (U_FAILURE(errorCode)) {
break;
}
- decomposeShort(prevBoundary, src, STOP_AT_LIMIT, FALSE /* onlyContiguous */,
+ decomposeShort(prevBoundary, src, STOP_AT_LIMIT, false /* onlyContiguous */,
buffer, errorCode);
// Decompose until the next boundary.
if (buffer.getLastCC() > 1) {
- src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, FALSE /* onlyContiguous */,
+ src = decomposeShort(src, limit, STOP_AT_DECOMP_BOUNDARY, false /* onlyContiguous */,
buffer, errorCode);
}
if (U_FAILURE(errorCode)) {
@@ -931,7 +931,7 @@ Normalizer2Impl::decomposeShort(const uint8_t *src, const uint8_t *limit,
if (leadCC == 0 && stopAt == STOP_AT_DECOMP_BOUNDARY) {
return prevSrc;
}
- if (!buffer.append((const char16_t *)mapping+1, length, TRUE, leadCC, trailCC, errorCode)) {
+ if (!buffer.append((const char16_t *)mapping+1, length, true, leadCC, trailCC, errorCode)) {
return nullptr;
}
}
@@ -1052,7 +1052,7 @@ void Normalizer2Impl::decomposeAndAppend(const UChar *src, const UChar *limit,
limit=u_strchr(p, 0);
}
- if (buffer.append(src, (int32_t)(p - src), FALSE, firstCC, prevCC, errorCode)) {
+ if (buffer.append(src, (int32_t)(p - src), false, firstCC, prevCC, errorCode)) {
buffer.appendZeroCC(p, limit, errorCode);
}
}
@@ -1064,7 +1064,7 @@ UBool Normalizer2Impl::hasDecompBoundaryBefore(UChar32 c) const {
UBool Normalizer2Impl::norm16HasDecompBoundaryBefore(uint16_t norm16) const {
if (norm16 < minNoNoCompNoMaybeCC) {
- return TRUE;
+ return true;
}
if (norm16 >= limitNoNo) {
return norm16 <= MIN_NORMAL_MAYBE_YES || norm16 == JAMO_VT;
@@ -1072,23 +1072,23 @@ UBool Normalizer2Impl::norm16HasDecompBoundaryBefore(uint16_t norm16) const {
// c decomposes, get everything from the variable-length extra data
const uint16_t *mapping=getMapping(norm16);
uint16_t firstUnit=*mapping;
- // TRUE if leadCC==0 (hasFCDBoundaryBefore())
+ // true if leadCC==0 (hasFCDBoundaryBefore())
return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (*(mapping-1)&0xff00)==0;
}
UBool Normalizer2Impl::hasDecompBoundaryAfter(UChar32 c) const {
if (c < minDecompNoCP) {
- return TRUE;
+ return true;
}
if (c <= 0xffff && !singleLeadMightHaveNonZeroFCD16(c)) {
- return TRUE;
+ return true;
}
return norm16HasDecompBoundaryAfter(getNorm16(c));
}
UBool Normalizer2Impl::norm16HasDecompBoundaryAfter(uint16_t norm16) const {
if(norm16 <= minYesNo || isHangulLVT(norm16)) {
- return TRUE;
+ return true;
}
if (norm16 >= limitNoNo) {
if (isMaybeOrNonZeroCC(norm16)) {
@@ -1103,13 +1103,13 @@ UBool Normalizer2Impl::norm16HasDecompBoundaryAfter(uint16_t norm16) const {
// decomp after-boundary: same as hasFCDBoundaryAfter(),
// fcd16<=1 || trailCC==0
if(firstUnit>0x1ff) {
- return FALSE; // trailCC>1
+ return false; // trailCC>1
}
if(firstUnit<=0xff) {
- return TRUE; // trailCC==0
+ return true; // trailCC==0
}
// if(trailCC==1) test leadCC==0, same as checking for before-boundary
- // TRUE if leadCC==0 (hasFCDBoundaryBefore())
+ // true if leadCC==0 (hasFCDBoundaryBefore())
return (firstUnit&MAPPING_HAS_CCC_LCCC_WORD)==0 || (*(mapping-1)&0xff00)==0;
}
@@ -1235,7 +1235,7 @@ void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStart
// and are only initialized now to avoid compiler warnings.
compositionsList=NULL; // used as indicator for whether we have a forward-combining starter
starter=NULL;
- starterIsSupplementary=FALSE;
+ starterIsSupplementary=false;
prevCC=0;
for(;;) {
@@ -1301,7 +1301,7 @@ void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStart
*starter=(UChar)composite;
// The composite is shorter than the starter,
// move the intermediate characters forward one.
- starterIsSupplementary=FALSE;
+ starterIsSupplementary=false;
q=starter+1;
r=q+1;
while(r<pRemove) {
@@ -1312,7 +1312,7 @@ void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStart
} else if(U_IS_SUPPLEMENTARY(composite)) {
// The composite is longer than the starter,
// move the intermediate characters back one.
- starterIsSupplementary=TRUE;
+ starterIsSupplementary=true;
++starter; // temporarily increment for the loop boundary
q=pRemove;
r=++pRemove;
@@ -1366,10 +1366,10 @@ void Normalizer2Impl::recompose(ReorderingBuffer &buffer, int32_t recomposeStart
if((compositionsList=getCompositionsListForDecompYes(norm16))!=NULL) {
// It may combine with something, prepare for it.
if(U_IS_BMP(c)) {
- starterIsSupplementary=FALSE;
+ starterIsSupplementary=false;
starter=p-1;
} else {
- starterIsSupplementary=TRUE;
+ starterIsSupplementary=true;
starter=p-2;
}
}
@@ -1447,7 +1447,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
doCompose ? &buffer : NULL,
errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
limit=u_strchr(src, 0);
if (prevBoundary != src) {
@@ -1471,7 +1471,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
if (prevBoundary != limit && doCompose) {
buffer.appendZeroCC(prevBoundary, limit, errorCode);
}
- return TRUE;
+ return true;
}
if( (c=*src)<minNoMaybeCP ||
isCompYesAndZeroCC(norm16=UCPTRIE_FAST_BMP_GET(normTrie, UCPTRIE_16, c))
@@ -1503,7 +1503,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
// Medium-fast path: Handle cases that do not require full decomposition and recomposition.
if (!isMaybeOrNonZeroCC(norm16)) { // minNoNo <= norm16 < minMaybeYes
if (!doCompose) {
- return FALSE;
+ return false;
}
// Fast path for mapping a character that is immediately surrounded by boundaries.
// In this case, we need not decompose around the current character.
@@ -1559,7 +1559,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
UChar l = (UChar)(prev-Hangul::JAMO_L_BASE);
if(l<Hangul::JAMO_L_COUNT) {
if (!doCompose) {
- return FALSE;
+ return false;
}
int32_t t;
if (src != limit &&
@@ -1599,7 +1599,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
// The current character is a Jamo Trailing consonant,
// compose with previous Hangul LV that does not contain a Jamo T.
if (!doCompose) {
- return FALSE;
+ return false;
}
UChar32 syllable = prev + c - Hangul::JAMO_T_BASE;
--prevSrc; // Replace the Hangul LV as well.
@@ -1622,7 +1622,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
if (onlyContiguous /* FCC */ && getPreviousTrailCC(prevBoundary, prevSrc) > cc) {
// Fails FCD test, need to decompose and contiguously recompose.
if (!doCompose) {
- return FALSE;
+ return false;
}
} else {
// If !onlyContiguous (not FCC), then we ignore the tccc of
@@ -1634,7 +1634,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
if (doCompose) {
buffer.appendZeroCC(prevBoundary, limit, errorCode);
}
- return TRUE;
+ return true;
}
uint8_t prevCC = cc;
nextSrc = src;
@@ -1643,7 +1643,7 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
cc = getCCFromNormalYesOrMaybe(n16);
if (prevCC > cc) {
if (!doCompose) {
- return FALSE;
+ return false;
}
break;
}
@@ -1678,28 +1678,28 @@ Normalizer2Impl::compose(const UChar *src, const UChar *limit,
}
int32_t recomposeStartIndex=buffer.length();
// We know there is not a boundary here.
- decomposeShort(prevSrc, src, FALSE /* !stopAtCompBoundary */, onlyContiguous,
+ decomposeShort(prevSrc, src, false /* !stopAtCompBoundary */, onlyContiguous,
buffer, errorCode);
// Decompose until the next boundary.
- src = decomposeShort(src, limit, TRUE /* stopAtCompBoundary */, onlyContiguous,
+ src = decomposeShort(src, limit, true /* stopAtCompBoundary */, onlyContiguous,
buffer, errorCode);
if (U_FAILURE(errorCode)) {
break;
}
if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals()
errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
- return TRUE;
+ return true;
}
recompose(buffer, recomposeStartIndex, onlyContiguous);
if(!doCompose) {
if(!buffer.equals(prevSrc, src)) {
- return FALSE;
+ return false;
}
buffer.remove();
}
prevBoundary=src;
}
- return TRUE;
+ return true;
}
// Very similar to compose(): Make the same changes in both places if relevant.
@@ -1846,7 +1846,7 @@ void Normalizer2Impl::composeAndAppend(const UChar *src, const UChar *limit,
middle.append(src, (int32_t)(firstStarterInSrc-src));
const UChar *middleStart=middle.getBuffer();
compose(middleStart, middleStart+middle.length(), onlyContiguous,
- TRUE, buffer, errorCode);
+ true, buffer, errorCode);
if(U_FAILURE(errorCode)) {
return;
}
@@ -1854,7 +1854,7 @@ void Normalizer2Impl::composeAndAppend(const UChar *src, const UChar *limit,
}
}
if(doCompose) {
- compose(src, limit, onlyContiguous, TRUE, buffer, errorCode);
+ compose(src, limit, onlyContiguous, true, buffer, errorCode);
} else {
if(limit==NULL) { // appendZeroCC() needs limit!=NULL
limit=u_strchr(src, 0);
@@ -1883,7 +1883,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
ByteSinkUtil::appendUnchanged(prevBoundary, limit,
*sink, options, edits, errorCode);
}
- return TRUE;
+ return true;
}
if (*src < minNoMaybeLead) {
++src;
@@ -1904,7 +1904,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
// Medium-fast path: Handle cases that do not require full decomposition and recomposition.
if (!isMaybeOrNonZeroCC(norm16)) { // minNoNo <= norm16 < minMaybeYes
if (sink == nullptr) {
- return FALSE;
+ return false;
}
// Fast path for mapping a character that is immediately surrounded by boundaries.
// In this case, we need not decompose around the current character.
@@ -1972,7 +1972,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
UChar32 l = prev - Hangul::JAMO_L_BASE;
if ((uint32_t)l < Hangul::JAMO_L_COUNT) {
if (sink == nullptr) {
- return FALSE;
+ return false;
}
int32_t t = getJamoTMinusBase(src, limit);
if (t >= 0) {
@@ -2008,7 +2008,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
// The current character is a Jamo Trailing consonant,
// compose with previous Hangul LV that does not contain a Jamo T.
if (sink == nullptr) {
- return FALSE;
+ return false;
}
UChar32 syllable = prev + getJamoTMinusBase(prevSrc, src);
prevSrc -= 3; // Replace the Hangul LV as well.
@@ -2031,7 +2031,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
if (onlyContiguous /* FCC */ && getPreviousTrailCC(prevBoundary, prevSrc) > cc) {
// Fails FCD test, need to decompose and contiguously recompose.
if (sink == nullptr) {
- return FALSE;
+ return false;
}
} else {
// If !onlyContiguous (not FCC), then we ignore the tccc of
@@ -2044,7 +2044,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
ByteSinkUtil::appendUnchanged(prevBoundary, limit,
*sink, options, edits, errorCode);
}
- return TRUE;
+ return true;
}
uint8_t prevCC = cc;
nextSrc = src;
@@ -2053,7 +2053,7 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
cc = getCCFromNormalYesOrMaybe(n16);
if (prevCC > cc) {
if (sink == nullptr) {
- return FALSE;
+ return false;
}
break;
}
@@ -2098,12 +2098,12 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
}
if ((src - prevSrc) > INT32_MAX) { // guard before buffer.equals()
errorCode = U_INDEX_OUTOFBOUNDS_ERROR;
- return TRUE;
+ return true;
}
recompose(buffer, 0, onlyContiguous);
if (!buffer.equals(prevSrc, src)) {
if (sink == nullptr) {
- return FALSE;
+ return false;
}
if (prevBoundary != prevSrc &&
!ByteSinkUtil::appendUnchanged(prevBoundary, prevSrc,
@@ -2117,12 +2117,12 @@ Normalizer2Impl::composeUTF8(uint32_t options, UBool onlyContiguous,
prevBoundary = src;
}
}
- return TRUE;
+ return true;
}
UBool Normalizer2Impl::hasCompBoundaryBefore(const UChar *src, const UChar *limit) const {
if (src == limit || *src < minCompNoMaybeCP) {
- return TRUE;
+ return true;
}
UChar32 c;
uint16_t norm16;
@@ -2132,7 +2132,7 @@ UBool Normalizer2Impl::hasCompBoundaryBefore(const UChar *src, const UChar *limi
UBool Normalizer2Impl::hasCompBoundaryBefore(const uint8_t *src, const uint8_t *limit) const {
if (src == limit) {
- return TRUE;
+ return true;
}
uint16_t norm16;
UCPTRIE_FAST_U8_NEXT(normTrie, UCPTRIE_16, src, limit, norm16);
@@ -2142,7 +2142,7 @@ UBool Normalizer2Impl::hasCompBoundaryBefore(const uint8_t *src, const uint8_t *
UBool Normalizer2Impl::hasCompBoundaryAfter(const UChar *start, const UChar *p,
UBool onlyContiguous) const {
if (start == p) {
- return TRUE;
+ return true;
}
UChar32 c;
uint16_t norm16;
@@ -2153,7 +2153,7 @@ UBool Normalizer2Impl::hasCompBoundaryAfter(const UChar *start, const UChar *p,
UBool Normalizer2Impl::hasCompBoundaryAfter(const uint8_t *start, const uint8_t *p,
UBool onlyContiguous) const {
if (start == p) {
- return TRUE;
+ return true;
}
uint16_t norm16;
UCPTRIE_FAST_U8_PREV(normTrie, UCPTRIE_16, start, p, norm16);
@@ -2399,7 +2399,7 @@ Normalizer2Impl::makeFCD(const UChar *src, const UChar *limit,
* The source text does not fulfill the conditions for FCD.
* Decompose and reorder a limited piece of the text.
*/
- decomposeShort(prevBoundary, src, FALSE, FALSE, *buffer, errorCode);
+ decomposeShort(prevBoundary, src, false, false, *buffer, errorCode);
if (U_FAILURE(errorCode)) {
break;
}
@@ -2665,7 +2665,7 @@ UBool Normalizer2Impl::isCanonSegmentStarter(UChar32 c) const {
UBool Normalizer2Impl::getCanonStartSet(UChar32 c, UnicodeSet &set) const {
int32_t canonValue=getCanonValue(c)&~CANON_NOT_SEGMENT_STARTER;
if(canonValue==0) {
- return FALSE;
+ return false;
}
set.clear();
int32_t value=canonValue&CANON_VALUE_MASK;
@@ -2684,7 +2684,7 @@ UBool Normalizer2Impl::getCanonStartSet(UChar32 c, UnicodeSet &set) const {
addComposites(getCompositionsList(norm16), set);
}
}
- return TRUE;
+ return true;
}
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/normalizer2impl.h b/thirdparty/icu4c/common/normalizer2impl.h
index 7c85448b71..449e778384 100644
--- a/thirdparty/icu4c/common/normalizer2impl.h
+++ b/thirdparty/icu4c/common/normalizer2impl.h
@@ -131,7 +131,7 @@ public:
}
}
private:
- Hangul(); // no instantiation
+ Hangul() = delete; // no instantiation
};
class Normalizer2Impl;
@@ -730,7 +730,7 @@ private:
const uint16_t *extraData; // mappings and/or compositions for yesYes, yesNo & noNo characters
const uint8_t *smallFCD; // [0x100] one bit per 32 BMP code points, set if any FCD!=0
- UInitOnce fCanonIterDataInitOnce = U_INITONCE_INITIALIZER;
+ UInitOnce fCanonIterDataInitOnce {};
CanonIterData *fCanonIterData;
};
@@ -759,7 +759,7 @@ public:
// Must be used only when it is known that norm2 is a Normalizer2WithImpl instance.
static const Normalizer2Impl *getImpl(const Normalizer2 *norm2);
private:
- Normalizer2Factory(); // No instantiation.
+ Normalizer2Factory() = delete; // No instantiation.
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/normlzr.cpp b/thirdparty/icu4c/common/normlzr.cpp
index 1f4fa15179..58de61591f 100644
--- a/thirdparty/icu4c/common/normlzr.cpp
+++ b/thirdparty/icu4c/common/normlzr.cpp
@@ -205,7 +205,7 @@ Normalizer::isNormalized(const UnicodeString& source,
return n2->isNormalized(source, status);
}
} else {
- return FALSE;
+ return false;
}
}
@@ -483,7 +483,7 @@ Normalizer::nextNormalize() {
currentIndex=nextIndex;
text->setIndex(nextIndex);
if(!text->hasNext()) {
- return FALSE;
+ return false;
}
// Skip at least one character so we make progress.
UnicodeString segment(text->next32PostInc());
@@ -507,7 +507,7 @@ Normalizer::previousNormalize() {
nextIndex=currentIndex;
text->setIndex(currentIndex);
if(!text->hasPrevious()) {
- return FALSE;
+ return false;
}
UnicodeString segment;
while(text->hasPrevious()) {
diff --git a/thirdparty/icu4c/common/patternprops.cpp b/thirdparty/icu4c/common/patternprops.cpp
index c38a7e276d..da3243d301 100644
--- a/thirdparty/icu4c/common/patternprops.cpp
+++ b/thirdparty/icu4c/common/patternprops.cpp
@@ -118,49 +118,49 @@ static const uint32_t syntaxOrWhiteSpace2000[]={
UBool
PatternProps::isSyntax(UChar32 c) {
if(c<0) {
- return FALSE;
+ return false;
} else if(c<=0xff) {
return (UBool)(latin1[c]>>1)&1;
} else if(c<0x2010) {
- return FALSE;
+ return false;
} else if(c<=0x3030) {
uint32_t bits=syntax2000[index2000[(c-0x2000)>>5]];
return (UBool)((bits>>(c&0x1f))&1);
} else if(0xfd3e<=c && c<=0xfe46) {
return c<=0xfd3f || 0xfe45<=c;
} else {
- return FALSE;
+ return false;
}
}
UBool
PatternProps::isSyntaxOrWhiteSpace(UChar32 c) {
if(c<0) {
- return FALSE;
+ return false;
} else if(c<=0xff) {
return (UBool)(latin1[c]&1);
} else if(c<0x200e) {
- return FALSE;
+ return false;
} else if(c<=0x3030) {
uint32_t bits=syntaxOrWhiteSpace2000[index2000[(c-0x2000)>>5]];
return (UBool)((bits>>(c&0x1f))&1);
} else if(0xfd3e<=c && c<=0xfe46) {
return c<=0xfd3f || 0xfe45<=c;
} else {
- return FALSE;
+ return false;
}
}
UBool
PatternProps::isWhiteSpace(UChar32 c) {
if(c<0) {
- return FALSE;
+ return false;
} else if(c<=0xff) {
return (UBool)(latin1[c]>>2)&1;
} else if(0x200e<=c && c<=0x2029) {
return c<=0x200f || 0x2028<=c;
} else {
- return FALSE;
+ return false;
}
}
@@ -207,15 +207,15 @@ PatternProps::trimWhiteSpace(const UChar *s, int32_t &length) {
UBool
PatternProps::isIdentifier(const UChar *s, int32_t length) {
if(length<=0) {
- return FALSE;
+ return false;
}
const UChar *limit=s+length;
do {
if(isSyntaxOrWhiteSpace(*s++)) {
- return FALSE;
+ return false;
}
} while(s<limit);
- return TRUE;
+ return true;
}
const UChar *
diff --git a/thirdparty/icu4c/common/patternprops.h b/thirdparty/icu4c/common/patternprops.h
index 95898d580c..4ead56e1cd 100644
--- a/thirdparty/icu4c/common/patternprops.h
+++ b/thirdparty/icu4c/common/patternprops.h
@@ -90,7 +90,7 @@ public:
static const UChar *skipIdentifier(const UChar *s, int32_t length);
private:
- PatternProps(); // no constructor: all static methods
+ PatternProps() = delete; // no constructor: all static methods
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/propname.cpp b/thirdparty/icu4c/common/propname.cpp
index a12eb7d913..8f0045fdac 100644
--- a/thirdparty/icu4c/common/propname.cpp
+++ b/thirdparty/icu4c/common/propname.cpp
@@ -218,7 +218,7 @@ const char *PropNameData::getName(const char *nameGroup, int32_t nameIndex) {
UBool PropNameData::containsName(BytesTrie &trie, const char *name) {
if(name==NULL) {
- return FALSE;
+ return false;
}
UStringTrieResult result=USTRINGTRIE_NO_VALUE;
char c;
@@ -229,7 +229,7 @@ UBool PropNameData::containsName(BytesTrie &trie, const char *name) {
continue;
}
if(!USTRINGTRIE_HAS_NEXT(result)) {
- return FALSE;
+ return false;
}
result=trie.next((uint8_t)c);
}
diff --git a/thirdparty/icu4c/common/propname_data.h b/thirdparty/icu4c/common/propname_data.h
index c98a0f790b..1e247874b6 100644
--- a/thirdparty/icu4c/common/propname_data.h
+++ b/thirdparty/icu4c/common/propname_data.h
@@ -11,9 +11,9 @@
U_NAMESPACE_BEGIN
-const int32_t PropNameData::indexes[8]={0x20,0x163c,0x521b,0xab62,0xab62,0xab62,0x31,0};
+const int32_t PropNameData::indexes[8]={0x20,0x1660,0x5294,0xacd0,0xacd0,0xacd0,0x31,0};
-const int32_t PropNameData::valueMaps[1415]={
+const int32_t PropNameData::valueMaps[1424]={
6,0,0x48,0,0xf1,0x368,0xf1,0x37e,0xf1,0x393,0xf1,0x3a9,0xf1,0x3b4,0xf1,0x3d5,
0xf1,0x3e5,0xf1,0x3f4,0xf1,0x402,0xf1,0x426,0xf1,0x43d,0xf1,0x455,0xf1,0x46c,0xf1,0x47b,
0xf1,0x48a,0xf1,0x49b,0xf1,0x4a9,0xf1,0x4bb,0xf1,0x4d5,0xf1,0x4f0,0xf1,0x505,0xf1,0x522,
@@ -23,12 +23,12 @@ const int32_t PropNameData::valueMaps[1415]={
0xf1,0x71a,0xf1,0x722,0xf1,0x72b,0xf1,0x738,0xf1,0x74b,0xf1,0x768,0xf1,0x785,0xf1,0x7a2,
0xf1,0x7c0,0xf1,0x7de,0xf1,0x802,0xf1,0x80f,0xf1,0x829,0xf1,0x83e,0xf1,0x859,0xf1,0x870,
0xf1,0x887,0xf1,0x8a9,0xf1,0x8c8,0xf1,0x8e1,0xf1,0x90e,0xf1,0x947,0xf1,0x978,0xf1,0x9a7,
-0xf1,0x9d6,0xf1,0x1000,0x1019,0x9eb,0x16d,0xc0b,0x188,0x3196,0xf7,0x31b5,0x2cd,0x32f3,0x2e3,0x334d,
-0x2ed,0x35aa,0x30f,0x3ed5,0x37b,0x3f45,0x385,0x41df,0x3b4,0x421d,0x3bc,0x4d50,0x486,0x4dce,0x490,0x4df3,
-0x496,0x4e0d,0x49c,0x4e2e,0x4a3,0x4e48,0xf7,0x4e6d,0xf7,0x4e93,0x4aa,0x4f3d,0x4c0,0x4fb6,0x4d3,0x5068,
-0x4ee,0x509f,0x4f5,0x527f,0x509,0x56ff,0x531,0x2000,0x2001,0x575e,0x539,0x3000,0x3001,0x57ea,0,0x4000,
-0x400e,0x57fc,0,0x5805,0,0x581f,0,0x5830,0,0x5841,0,0x5857,0,0x5860,0,0x587d,
-0,0x589b,0,0x58b9,0,0x58d7,0,0x58ed,0,0x5901,0,0x5917,0,0x7000,0x7001,0x5930,
+0xf1,0x9d6,0xf1,0x1000,0x1019,0x9eb,0x16d,0xc0b,0x188,0x3279,0xf7,0x3298,0x2d4,0x33d6,0x2ea,0x3430,
+0x2f4,0x368d,0x316,0x3fb8,0x382,0x4028,0x38c,0x42c2,0x3bb,0x4300,0x3c3,0x4e45,0x48f,0x4ec3,0x499,0x4ee8,
+0x49f,0x4f02,0x4a5,0x4f23,0x4ac,0x4f3d,0xf7,0x4f62,0xf7,0x4f88,0x4b3,0x5032,0x4c9,0x50ab,0x4dc,0x515d,
+0x4f7,0x5194,0x4fe,0x5374,0x512,0x57f4,0x53a,0x2000,0x2001,0x5853,0x542,0x3000,0x3001,0x58df,0,0x4000,
+0x400e,0x58f1,0,0x58fa,0,0x5914,0,0x5925,0,0x5936,0,0x594c,0,0x5955,0,0x5972,
+0,0x5990,0,0x59ae,0,0x59cc,0,0x59e2,0,0x59f6,0,0x5a0c,0,0x7000,0x7001,0x5a25,
0,0x844,0x12,0,1,0x12,0x20,0x862,0x4a,0,1,6,7,8,9,0xa,
0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,
0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x54,0x5b,0x67,0x6b,0x76,0x7a,
@@ -38,7 +38,7 @@ const int32_t PropNameData::valueMaps[1415]={
0x1af,0x1bc,0x1c9,0x1d6,0x1e3,0x1f0,0x1fd,0x20c,0x21b,0x22a,0x239,0x248,0x257,0x266,0x275,0x28f,
0x2a3,0x2b7,0x2d2,0x2e1,0x2ea,0x2fa,0x302,0x30b,0x31a,0x323,0x333,0x344,0x355,0xa03,1,0,
0x17,0x9fa,0xa0b,0xa1c,0xa30,0xa47,0xa5f,0xa71,0xa86,0xa9d,0xab2,0xac2,0xad4,0xaf1,0xb0d,0xb1f,
-0xb3c,0xb58,0xb74,0xb89,0xb9e,0xbb8,0xbd3,0xbee,0xba5,1,0,0x141,0xc16,0xc23,0xc36,0xc5e,
+0xb3c,0xb58,0xb74,0xb89,0xb9e,0xbb8,0xbd3,0xbee,0xba5,1,0,0x148,0xc16,0xc23,0xc36,0xc5e,
0xc7c,0xc9a,0xcb2,0xcdd,0xd07,0xd1f,0xd32,0xd45,0xd54,0xd63,0xd72,0xd81,0xd98,0xda9,0xdbc,0xdcf,
0xddc,0xde9,0xdf8,0xe09,0xe1e,0xe2f,0xe3a,0xe43,0xe54,0xe65,0xe78,0xe8a,0xe9d,0xeb0,0xeef,0xefc,
0xf09,0xf16,0xf2b,0xf5b,0xf75,0xf96,0xfc1,0xfe4,0x1042,0x1069,0x1084,0x1093,0x10ba,0x10e2,0x1105,0x1128,
@@ -58,54 +58,54 @@ const int32_t PropNameData::valueMaps[1415]={
0x2a34,0x2a51,0x2a93,0x2aba,0x2ac7,0x2adc,0x2b00,0x2b26,0x2b5f,0x2b70,0x2b94,0x2b9f,0x2bac,0x2bbb,0x2be0,0x2c0e,
0x2c2a,0x2c47,0x2c54,0x2c65,0x2c83,0x2ca6,0x2cc3,0x2cd0,0x2cf0,0x2d0d,0x2d2e,0x2d57,0x2d68,0x2d87,0x2da0,0x2db9,
0x2dca,0x2e13,0x2e24,0x2e3d,0x2e6c,0x2e99,0x2ebe,0x2f00,0x2f1c,0x2f2b,0x2f42,0x2f70,0x2f89,0x2fb2,0x2fcc,0x3007,
-0x3025,0x3034,0x3054,0x306f,0x3093,0x30af,0x30cd,0x30eb,0x3102,0x3111,0x311c,0x3159,0x316c,0x1f6b,1,0,
-0x12,0x31cc,0x31dc,0x31ef,0x31ff,0x320f,0x321e,0x322e,0x3240,0x3253,0x3265,0x3275,0x3285,0x3294,0x32a3,0x32b3,
-0x32c0,0x32cf,0x32e3,0x2029,1,0,6,0x3308,0x3313,0x3320,0x332d,0x333a,0x3345,0x206d,1,0,
-0x1e,0x3362,0x3371,0x3386,0x339b,0x33b0,0x33c4,0x33d5,0x33e9,0x33fc,0x340d,0x3426,0x3438,0x3449,0x345d,0x3470,
-0x3488,0x349a,0x34a5,0x34b5,0x34c3,0x34d8,0x34ed,0x3503,0x351d,0x3533,0x3543,0x3557,0x356b,0x357c,0x3594,0x2298,
-1,0,0x68,0x35bc,0x35df,0x35e8,0x35f5,0x3600,0x3609,0x3614,0x361d,0x3636,0x363b,0x3644,0x3661,0x366a,
-0x3677,0x3680,0x36a4,0x36ab,0x36b4,0x36c7,0x36d2,0x36db,0x36e6,0x36ff,0x3708,0x3717,0x3722,0x372b,0x3736,0x373f,
-0x3746,0x374f,0x375a,0x3763,0x377c,0x3785,0x3792,0x379d,0x37ae,0x37b9,0x37ce,0x37e5,0x37ee,0x37f7,0x3810,0x381b,
-0x3824,0x382d,0x3844,0x3861,0x386c,0x387d,0x3888,0x388f,0x389c,0x38a9,0x38d6,0x38eb,0x38f4,0x390f,0x3932,0x3953,
-0x3974,0x3999,0x39c0,0x39e1,0x3a04,0x3a25,0x3a4c,0x3a6d,0x3a92,0x3ab1,0x3ad0,0x3aef,0x3b0c,0x3b2d,0x3b4e,0x3b71,
-0x3b96,0x3bb5,0x3bd4,0x3bf5,0x3c1c,0x3c41,0x3c60,0x3c81,0x3ca4,0x3cbf,0x3cd8,0x3cf3,0x3d0c,0x3d29,0x3d44,0x3d61,
-0x3d80,0x3d9d,0x3dba,0x3dd9,0x3df6,0x3e11,0x3e2e,0x3e4b,0x3e7e,0x3ea5,0x3eb8,0x25fb,1,0,6,0x3ee6,
-0x3ef5,0x3f05,0x3f15,0x3f25,0x3f36,0x2659,1,0,0x2b,0x3f54,0x3f60,0x3f6e,0x3f7d,0x3f8c,0x3f9c,0x3fad,
-0x3fc1,0x3fd6,0x3fec,0x3fff,0x4013,0x4023,0x402c,0x4037,0x4047,0x4063,0x4075,0x4083,0x4092,0x409e,0x40b3,0x40c7,
-0x40da,0x40e8,0x40fc,0x410a,0x4114,0x4126,0x4132,0x4140,0x4150,0x4157,0x415e,0x4165,0x416c,0x4173,0x4189,0x41aa,
-0x870,0x41bc,0x41c7,0x41d6,0x28b2,1,0,4,0x41f0,0x41fb,0x4207,0x4211,0x28d8,1,0,0xc6,
-0x4228,0x4235,0x424a,0x4257,0x4266,0x4274,0x4283,0x4292,0x42a4,0x42b3,0x42c1,0x42d2,0x42e1,0x42f0,0x42fd,0x4309,
-0x4318,0x4327,0x4331,0x433e,0x434b,0x435a,0x4368,0x4377,0x4383,0x438d,0x4399,0x43a9,0x43b9,0x43c7,0x43d3,0x43e4,
-0x43f0,0x43fc,0x440a,0x4417,0x4423,0x4430,0xe2f,0x443d,0x444b,0x4465,0x446e,0x447c,0x448a,0x4496,0x44a5,0x44b3,
-0x44c1,0x44cd,0x44dc,0x44ea,0x44f8,0x4505,0x4514,0x452f,0x453e,0x454f,0x4560,0x4573,0x4585,0x4594,0x45a6,0x45b5,
-0x45c1,0x45cc,0x1f3f,0x45d9,0x45e4,0x45ef,0x45fa,0x4605,0x4620,0x462b,0x4636,0x4641,0x4654,0x4668,0x4673,0x4682,
-0x4691,0x469c,0x46a7,0x46b4,0x46c3,0x46d1,0x46dc,0x46f7,0x4701,0x4712,0x4723,0x4732,0x4743,0x474e,0x4759,0x4764,
-0x476f,0x477a,0x4785,0x4790,0x479a,0x47a5,0x47b5,0x47c0,0x47ce,0x47db,0x47e6,0x47f5,0x4802,0x480f,0x481e,0x482b,
-0x483c,0x484e,0x485e,0x4869,0x487c,0x4893,0x48a1,0x48ae,0x48b9,0x48c6,0x48d7,0x48f3,0x4909,0x4914,0x4931,0x4941,
-0x4950,0x495b,0x4966,0x2059,0x4972,0x497d,0x4995,0x49a5,0x49b4,0x49c2,0x49d0,0x49db,0x49e6,0x49fa,0x4a11,0x4a29,
-0x4a39,0x4a49,0x4a59,0x4a6b,0x4a76,0x4a81,0x4a8b,0x4a97,0x4aa5,0x4ab8,0x4ac4,0x4ad1,0x4adc,0x4af8,0x4b05,0x4b13,
-0x4b2c,0x2959,0x4b3b,0x277a,0x4b48,0x4b56,0x4b68,0x4b76,0x4b82,0x4b92,0x2b94,0x4ba0,0x4bac,0x4bb7,0x4bc2,0x4bcd,
-0x4be1,0x4bef,0x4c06,0x4c12,0x4c26,0x4c34,0x4c46,0x4c5c,0x4c6a,0x4c7c,0x4c8a,0x4ca7,0x4cb9,0x4cc6,0x4cd7,0x4ce9,
-0x4d03,0x4d10,0x4d23,0x4d34,0x3111,0x4d41,0x331b,1,0,6,0x4d6a,0x4d7d,0x4d8d,0x4d9b,0x4dac,0x4dbc,
-0x3377,0x12,0,1,0x4de6,0x4dec,0x3384,0x12,0,1,0x4de6,0x4dec,0x3391,1,0,3,
-0x4de6,0x4dec,0x4e25,0x33a7,1,0,3,0x4de6,0x4dec,0x4e25,0x33bd,1,0,0x12,0x4eaf,0x4eb9,
-0x4ec5,0x4ecc,0x4ed7,0x4edc,0x4ee3,0x4eea,0x4ef3,0x4ef8,0x4efd,0x4f0d,0x870,0x41bc,0x4f19,0x41c7,0x4f29,0x41d6,
-0x3466,1,0,0xf,0x4eaf,0x4f50,0x4f5a,0x4f64,0x4f6f,0x4092,0x4f79,0x4f85,0x4f8d,0x4f94,0x4f9e,0x4ec5,
-0x4ecc,0x4edc,0x4fa8,0x34ed,1,0,0x17,0x4eaf,0x4fc5,0x4f64,0x4fd1,0x4fde,0x4fec,0x4092,0x4ff7,0x4ec5,
-0x5008,0x4edc,0x5017,0x5025,0x870,0x41aa,0x5031,0x5042,0x41bc,0x4f19,0x41c7,0x4f29,0x41d6,0x5053,0x360a,1,
-0,3,0x5086,0x508e,0x5096,0x3623,1,0,0x10,0x50bf,0x50c6,0x50d5,0x50f6,0x5119,0x5124,0x5143,
-0x515a,0x5167,0x5170,0x518f,0x51c2,0x51dd,0x520c,0x5229,0x524e,0x36bc,1,0,0x24,0x529d,0x52aa,0x52bd,
-0x52ca,0x52f7,0x531c,0x5331,0x5350,0x5371,0x539e,0x53d7,0x53fa,0x541d,0x544a,0x547f,0x54a6,0x54cf,0x5506,0x5535,
-0x5556,0x557b,0x558a,0x55ad,0x55c4,0x55d1,0x55e0,0x55fd,0x5616,0x5639,0x565e,0x5677,0x568c,0x569b,0x56ac,0x56b9,
-0x56da,0x388c,1,0,4,0x5718,0x5723,0x573b,0x5753,0x38c8,0x36,1,2,4,8,0xe,
-0x10,0x20,0x3e,0x40,0x80,0x100,0x1c0,0x200,0x400,0x800,0xe00,0x1000,0x2000,0x4000,0x7000,0x8000,
-0x10000,0x20000,0x40000,0x78001,0x80000,0x100000,0x200000,0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000,0xf000000,0x10000000,0x20000000,
-0x30f80000,0x3362,0x3371,0x3386,0x339b,0x578c,0x33b0,0x33c4,0x5782,0x33d5,0x33e9,0x33fc,0x579d,0x340d,0x3426,0x3438,
-0x57b4,0x3449,0x345d,0x3470,0x57dd,0x3488,0x349a,0x34a5,0x34b5,0x5779,0x34c3,0x34d8,0x34ed,0x3503,0x351d,0x3533,
-0x3543,0x3557,0x356b,0x57d3,0x357c,0x3594,0x57be
+0x3025,0x3034,0x3054,0x306f,0x3093,0x30af,0x30cd,0x30eb,0x3102,0x3111,0x311c,0x3159,0x316c,0x3196,0x31b6,0x31e4,
+0x3208,0x3230,0x3255,0x3260,0x1fa9,1,0,0x12,0x32af,0x32bf,0x32d2,0x32e2,0x32f2,0x3301,0x3311,0x3323,
+0x3336,0x3348,0x3358,0x3368,0x3377,0x3386,0x3396,0x33a3,0x33b2,0x33c6,0x2067,1,0,6,0x33eb,0x33f6,
+0x3403,0x3410,0x341d,0x3428,0x20ab,1,0,0x1e,0x3445,0x3454,0x3469,0x347e,0x3493,0x34a7,0x34b8,0x34cc,
+0x34df,0x34f0,0x3509,0x351b,0x352c,0x3540,0x3553,0x356b,0x357d,0x3588,0x3598,0x35a6,0x35bb,0x35d0,0x35e6,0x3600,
+0x3616,0x3626,0x363a,0x364e,0x365f,0x3677,0x22d6,1,0,0x68,0x369f,0x36c2,0x36cb,0x36d8,0x36e3,0x36ec,
+0x36f7,0x3700,0x3719,0x371e,0x3727,0x3744,0x374d,0x375a,0x3763,0x3787,0x378e,0x3797,0x37aa,0x37b5,0x37be,0x37c9,
+0x37e2,0x37eb,0x37fa,0x3805,0x380e,0x3819,0x3822,0x3829,0x3832,0x383d,0x3846,0x385f,0x3868,0x3875,0x3880,0x3891,
+0x389c,0x38b1,0x38c8,0x38d1,0x38da,0x38f3,0x38fe,0x3907,0x3910,0x3927,0x3944,0x394f,0x3960,0x396b,0x3972,0x397f,
+0x398c,0x39b9,0x39ce,0x39d7,0x39f2,0x3a15,0x3a36,0x3a57,0x3a7c,0x3aa3,0x3ac4,0x3ae7,0x3b08,0x3b2f,0x3b50,0x3b75,
+0x3b94,0x3bb3,0x3bd2,0x3bef,0x3c10,0x3c31,0x3c54,0x3c79,0x3c98,0x3cb7,0x3cd8,0x3cff,0x3d24,0x3d43,0x3d64,0x3d87,
+0x3da2,0x3dbb,0x3dd6,0x3def,0x3e0c,0x3e27,0x3e44,0x3e63,0x3e80,0x3e9d,0x3ebc,0x3ed9,0x3ef4,0x3f11,0x3f2e,0x3f61,
+0x3f88,0x3f9b,0x2639,1,0,6,0x3fc9,0x3fd8,0x3fe8,0x3ff8,0x4008,0x4019,0x2697,1,0,0x2b,
+0x4037,0x4043,0x4051,0x4060,0x406f,0x407f,0x4090,0x40a4,0x40b9,0x40cf,0x40e2,0x40f6,0x4106,0x410f,0x411a,0x412a,
+0x4146,0x4158,0x4166,0x4175,0x4181,0x4196,0x41aa,0x41bd,0x41cb,0x41df,0x41ed,0x41f7,0x4209,0x4215,0x4223,0x4233,
+0x423a,0x4241,0x4248,0x424f,0x4256,0x426c,0x428d,0x870,0x429f,0x42aa,0x42b9,0x28f0,1,0,4,0x42d3,
+0x42de,0x42ea,0x42f4,0x2916,1,0,0xc8,0x430b,0x4318,0x432d,0x433a,0x4349,0x4357,0x4366,0x4375,0x4387,
+0x4396,0x43a4,0x43b5,0x43c4,0x43d3,0x43e0,0x43ec,0x43fb,0x440a,0x4414,0x4421,0x442e,0x443d,0x444b,0x445a,0x4466,
+0x4470,0x447c,0x448c,0x449c,0x44aa,0x44b6,0x44c7,0x44d3,0x44df,0x44ed,0x44fa,0x4506,0x4513,0xe2f,0x4520,0x452e,
+0x4548,0x4551,0x455f,0x456d,0x4579,0x4588,0x4596,0x45a4,0x45b0,0x45bf,0x45cd,0x45db,0x45e8,0x45f7,0x4612,0x4621,
+0x4632,0x4643,0x4656,0x4668,0x4677,0x4689,0x4698,0x46a4,0x46af,0x1f3f,0x46bc,0x46c7,0x46d2,0x46dd,0x46e8,0x4703,
+0x470e,0x4719,0x4724,0x4737,0x474b,0x4756,0x4765,0x4774,0x477f,0x478a,0x4797,0x47a6,0x47b4,0x47bf,0x47da,0x47e4,
+0x47f5,0x4806,0x4815,0x4826,0x4831,0x483c,0x4847,0x4852,0x485d,0x4868,0x4873,0x487d,0x4888,0x4898,0x48a3,0x48b1,
+0x48be,0x48c9,0x48d8,0x48e5,0x48f2,0x4901,0x490e,0x491f,0x4931,0x4941,0x494c,0x495f,0x4976,0x4984,0x4991,0x499c,
+0x49a9,0x49ba,0x49d6,0x49ec,0x49f7,0x4a14,0x4a24,0x4a33,0x4a3e,0x4a49,0x2059,0x4a55,0x4a60,0x4a78,0x4a88,0x4a97,
+0x4aa5,0x4ab3,0x4abe,0x4ac9,0x4add,0x4af4,0x4b0c,0x4b1c,0x4b2c,0x4b3c,0x4b4e,0x4b59,0x4b64,0x4b6e,0x4b7a,0x4b88,
+0x4b9b,0x4ba7,0x4bb4,0x4bbf,0x4bdb,0x4be8,0x4bf6,0x4c0f,0x2959,0x4c1e,0x277a,0x4c2b,0x4c39,0x4c4b,0x4c59,0x4c65,
+0x4c75,0x2b94,0x4c83,0x4c8f,0x4c9a,0x4ca5,0x4cb0,0x4cc4,0x4cd2,0x4ce9,0x4cf5,0x4d09,0x4d17,0x4d29,0x4d3f,0x4d4d,
+0x4d5f,0x4d6d,0x4d8a,0x4d9c,0x4da9,0x4dba,0x4dcc,0x4de6,0x4df3,0x4e06,0x4e17,0x3111,0x4e24,0x3255,0x4e33,0x3370,
+1,0,6,0x4e5f,0x4e72,0x4e82,0x4e90,0x4ea1,0x4eb1,0x33cc,0x12,0,1,0x4edb,0x4ee1,0x33d9,
+0x12,0,1,0x4edb,0x4ee1,0x33e6,1,0,3,0x4edb,0x4ee1,0x4f1a,0x33fc,1,0,3,
+0x4edb,0x4ee1,0x4f1a,0x3412,1,0,0x12,0x4fa4,0x4fae,0x4fba,0x4fc1,0x4fcc,0x4fd1,0x4fd8,0x4fdf,0x4fe8,
+0x4fed,0x4ff2,0x5002,0x870,0x429f,0x500e,0x42aa,0x501e,0x42b9,0x34bb,1,0,0xf,0x4fa4,0x5045,0x504f,
+0x5059,0x5064,0x4175,0x506e,0x507a,0x5082,0x5089,0x5093,0x4fba,0x4fc1,0x4fd1,0x509d,0x3542,1,0,0x17,
+0x4fa4,0x50ba,0x5059,0x50c6,0x50d3,0x50e1,0x4175,0x50ec,0x4fba,0x50fd,0x4fd1,0x510c,0x511a,0x870,0x428d,0x5126,
+0x5137,0x429f,0x500e,0x42aa,0x501e,0x42b9,0x5148,0x365f,1,0,3,0x517b,0x5183,0x518b,0x3678,1,
+0,0x10,0x51b4,0x51bb,0x51ca,0x51eb,0x520e,0x5219,0x5238,0x524f,0x525c,0x5265,0x5284,0x52b7,0x52d2,0x5301,
+0x531e,0x5343,0x3711,1,0,0x24,0x5392,0x539f,0x53b2,0x53bf,0x53ec,0x5411,0x5426,0x5445,0x5466,0x5493,
+0x54cc,0x54ef,0x5512,0x553f,0x5574,0x559b,0x55c4,0x55fb,0x562a,0x564b,0x5670,0x567f,0x56a2,0x56b9,0x56c6,0x56d5,
+0x56f2,0x570b,0x572e,0x5753,0x576c,0x5781,0x5790,0x57a1,0x57ae,0x57cf,0x38e1,1,0,4,0x580d,0x5818,
+0x5830,0x5848,0x391d,0x36,1,2,4,8,0xe,0x10,0x20,0x3e,0x40,0x80,0x100,0x1c0,
+0x200,0x400,0x800,0xe00,0x1000,0x2000,0x4000,0x7000,0x8000,0x10000,0x20000,0x40000,0x78001,0x80000,0x100000,0x200000,
+0x400000,0x800000,0x1000000,0x2000000,0x4000000,0x8000000,0xf000000,0x10000000,0x20000000,0x30f80000,0x3445,0x3454,0x3469,0x347e,0x5881,0x3493,
+0x34a7,0x5877,0x34b8,0x34cc,0x34df,0x5892,0x34f0,0x3509,0x351b,0x58a9,0x352c,0x3540,0x3553,0x58d2,0x356b,0x357d,
+0x3588,0x3598,0x586e,0x35a6,0x35bb,0x35d0,0x35e6,0x3600,0x3616,0x3626,0x363a,0x364e,0x58c8,0x365f,0x3677,0x58b3
};
-const uint8_t PropNameData::bytesTries[15327]={
+const uint8_t PropNameData::bytesTries[15412]={
0,0x15,0x6d,0xc3,0xc7,0x73,0xc2,0x12,0x76,0x7a,0x76,0x6a,0x77,0xa2,0x52,0x78,
1,0x64,0x50,0x69,0x10,0x64,1,0x63,0x30,0x73,0x62,0x13,0x74,0x61,0x72,0x74,
0x63,0x60,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x61,0x13,0x69,0x67,0x69,0x74,
@@ -292,7 +292,7 @@ const uint8_t PropNameData::bytesTries[15327]={
0x74,0x6f,0x72,0x2d,2,0x6c,0x3b,0x6e,0x2b,0x72,0x13,0x61,0x62,0x69,0x63,1,
0x6c,0x30,0x6e,0x14,0x75,0x6d,0x62,0x65,0x72,0x2b,0x14,0x65,0x74,0x74,0x65,0x72,
0x3b,0x2e,1,0x6e,0x45,0x6f,0x1c,0x75,0x6e,0x64,0x61,0x72,0x79,0x6e,0x65,0x75,
-0x74,0x72,0x61,0x6c,0x45,0,0x16,0x6d,0xc9,0x14,0x74,0xc2,0x30,0x77,0x89,0x77,
+0x74,0x72,0x61,0x6c,0x45,0,0x16,0x6d,0xc9,0x20,0x74,0xc2,0x30,0x77,0x89,0x77,
0x86,0x79,0xa2,0x46,0x7a,1,0x61,0x58,0x6e,0x1a,0x61,0x6d,0x65,0x6e,0x6e,0x79,
0x6d,0x75,0x73,0x69,0x63,0xa4,0x40,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69,
0x6f,0x6e,0xa5,0x40,0x1c,0x6e,0x61,0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75,0x61,
@@ -436,637 +436,643 @@ const uint8_t PropNameData::bytesTries[15327]={
0x6e,0x67,0xa5,0x27,0x10,0x6f,0xa3,0x92,0x14,0x62,0x6c,0x6f,0x63,0x6b,0x21,1,
0x6d,0x2c,0x73,0x11,0x68,0x75,0xa5,0x15,0x17,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,
0x73,0x7b,0x61,0x44,0x62,0x21,0x65,0x10,0x77,1,0x61,0xa5,0xe,0x74,0x14,0x61,
-0x69,0x6c,0x75,0x65,0xa3,0x8b,1,0x62,0x38,0x6e,0x17,0x64,0x69,0x6e,0x61,0x67,
-0x61,0x72,0x69,0xa5,0x26,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0xef,0x67,0xc4,
-0x43,0x6a,0xc1,0xca,0x6a,0xa2,0xdf,0x6b,0xa2,0xf8,0x6c,4,0x61,0x54,0x65,0xa2,
-0x6b,0x69,0xa2,0x82,0x6f,0xa2,0xc1,0x79,1,0x63,0x2e,0x64,0x12,0x69,0x61,0x6e,
-0xa3,0xa9,0x12,0x69,0x61,0x6e,0xa3,0xa7,1,0x6f,0x55,0x74,0x11,0x69,0x6e,1,
-0x31,0x96,0x65,0x11,0x78,0x74,6,0x64,0x21,0x64,0xa3,0x95,0x65,0x2c,0x66,0xa5,
-0x39,0x67,0xa5,0x3a,0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,6,0x64,0xc,0x64,0xa3,
-0x95,0x65,0xa3,0xe7,0x66,0xa5,0x39,0x67,0xa5,0x3a,0x61,0x2a,0x62,0x29,0x63,0xa3,
-0x94,0x26,0x18,0x64,0x64,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24,0x12,0x73,
-0x75,0x70,0x24,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x25,1,0x70,0x42,0x74,
-0x1d,0x74,0x65,0x72,0x6c,0x69,0x6b,0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x79,
-0x12,0x63,0x68,0x61,0xa3,0x9c,2,0x6d,0x4e,0x6e,0x54,0x73,0x10,0x75,0xa2,0xb0,
-0x12,0x73,0x75,0x70,0xa4,0x31,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x31,
-0x11,0x62,0x75,0xa3,0x6f,0x12,0x65,0x61,0x72,1,0x61,0xa3,0xe8,0x62,1,0x69,
-0x38,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x75,0x17,0x64,0x65,
-0x6f,0x67,0x72,0x61,0x6d,0x73,0xa3,0x76,0x1a,0x77,0x73,0x75,0x72,0x72,0x6f,0x67,
-0x61,0x74,0x65,0x73,0xa3,0x4d,0x10,0x61,1,0x6d,0x32,0x76,0x14,0x61,0x6e,0x65,
-0x73,0x65,0xa3,0xb5,0x10,0x6f,0x5c,0x12,0x65,0x78,0x74,1,0x61,0xa3,0xb4,0x62,
-0xa3,0xb9,1,0x61,0xa2,0x43,0x68,4,0x61,0x40,0x69,0x50,0x6d,0x6e,0x6f,0x86,
-0x75,0x15,0x64,0x61,0x77,0x61,0x64,0x69,0xa3,0xe6,0x16,0x72,0x6f,0x73,0x68,0x74,
-0x68,0x69,0xa3,0x89,0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,
-0x69,0x70,0x74,0xa5,0x30,0x11,0x65,0x72,0x68,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,
-0x73,0xa3,0x71,0x12,0x6a,0x6b,0x69,0xa3,0xe5,3,0x69,0x3a,0x6e,0x42,0x74,0xa2,
-0x58,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,0xa2,0x12,0x74,0x68,0x69,0xa3,0xc1,3,
-0x61,0x34,0x62,0x84,0x67,0x8a,0x6e,0x12,0x61,0x64,0x61,0x4d,1,0x65,0x40,0x73,
-0x11,0x75,0x70,0xa2,0xcb,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xcb,0x11,
-0x78,0x74,2,0x61,0xa5,0x13,0x62,0xa5,0x38,0x65,0x13,0x6e,0x64,0x65,0x64,1,
-0x61,0xa5,0x13,0x62,0xa5,0x38,0x11,0x75,0x6e,0xa3,0x42,0x11,0x78,0x69,0x96,0x17,
-0x72,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x97,0x14,0x61,0x6b,0x61,0x6e,0x61,0x9e,
-1,0x65,0x4c,0x70,0x10,0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78,0x74,
-0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x67,0xa2,
-0xb5,0x68,0xa4,0x84,0x69,3,0x64,0x4c,0x6d,0xa2,0x55,0x6e,0xa2,0x62,0x70,0x13,
-0x61,0x65,0x78,0x74,0x2a,0x16,0x65,0x6e,0x73,0x69,0x6f,0x6e,0x73,0x2b,1,0x63,
-0x99,0x65,0x17,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,1,0x64,0x56,0x73,0x15,
-0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa4,0xb,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,
-0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa5,0xb,0x13,0x65,0x73,0x63,0x72,0x1f,0x69,
-0x70,0x74,0x69,0x6f,0x6e,0x63,0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,0x73,0x99,
-0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0xba,
-1,0x64,0x62,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70,
-0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0xbd,0x13,0x6c,0x61,
-0x76,0x69,0xa3,0xbe,0x11,0x69,0x63,1,0x6e,0x3e,0x73,0x1a,0x69,0x79,0x61,0x71,
-0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa5,0x1e,0x19,0x75,0x6d,0x62,0x65,0x72,0x66,
-0x6f,0x72,0x6d,0x73,0xa3,0xb2,4,0x65,0x74,0x6c,0xa2,0x82,0x6f,0xa2,0x9a,0x72,
-0xa2,0x9e,0x75,2,0x6a,0x34,0x6e,0x3e,0x72,0x14,0x6d,0x75,0x6b,0x68,0x69,0x43,
-0x14,0x61,0x72,0x61,0x74,0x69,0x45,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,
-0x69,0xa5,0x1c,1,0x6e,0xa2,0x46,0x6f,1,0x6d,0x6e,0x72,0x13,0x67,0x69,0x61,
-0x6e,0x5a,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0x87,0x16,0x70,0x6c,0x65,0x6d,
-0x65,0x6e,0x74,0xa3,0x87,0x11,0x78,0x74,0xa4,0x1b,0x14,0x65,0x6e,0x64,0x65,0x64,
-0xa5,0x1b,0x1a,0x65,0x74,0x72,0x69,0x63,0x73,0x68,0x61,0x70,0x65,0x73,0x8c,0x12,
-0x65,0x78,0x74,0xa2,0xe3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe3,0x1e,0x65,0x72,
-0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x71,0x17,0x61,
-0x67,0x6f,0x6c,0x69,0x74,0x69,0x63,0xa2,0x88,0x12,0x73,0x75,0x70,0xa4,0xa,0x16,
-0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xa,0x13,0x74,0x68,0x69,0x63,0xa3,0x59,
-1,0x61,0x5c,0x65,0x11,0x65,0x6b,0x30,1,0x61,0x38,0x65,0x11,0x78,0x74,0x6e,
-0x14,0x65,0x6e,0x64,0x65,0x64,0x6f,0x17,0x6e,0x64,0x63,0x6f,0x70,0x74,0x69,0x63,
-0x31,0x13,0x6e,0x74,0x68,0x61,0xa3,0xe4,2,0x61,0xa2,0x48,0x65,0xa2,0xdf,0x69,
-1,0x67,0x30,0x72,0x14,0x61,0x67,0x61,0x6e,0x61,0x9d,0x10,0x68,1,0x70,0x3a,
-0x73,0x18,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4b,1,0x72,0x3c,
-0x75,0x19,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,0x11,0x69,
-0x76,0x1f,0x61,0x74,0x65,0x75,0x73,0x65,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,
-0x65,0x73,0xa3,0x4c,2,0x6c,0x32,0x6e,0x9a,0x74,0x12,0x72,0x61,0x6e,0xa5,2,
-0x10,0x66,2,0x61,0x58,0x6d,0x70,0x77,0x14,0x69,0x64,0x74,0x68,0x61,0x1f,0x6e,
-0x64,0x66,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x66,0x6f,0x72,0x6d,0x73,0xa3,
-0x57,0x1a,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x13,
-0x61,0x72,0x6b,0x73,0xa3,0x52,2,0x67,0x34,0x69,0xa2,0x45,0x75,0x12,0x6e,0x6f,
-0x6f,0xa3,0x63,0x11,0x75,0x6c,0xa2,0x4a,2,0x63,0x3c,0x6a,0x5e,0x73,0x17,0x79,
-0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x4a,0x1f,0x6f,0x6d,0x70,0x61,0x74,0x69,
-0x62,0x69,0x6c,0x69,0x74,0x79,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x12,0x61,0x6d,0x6f,
-0x5c,0x17,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,1,0x61,0xa3,0xb4,0x62,0xa3,
-0xb9,0x19,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa5,0x1d,0x13,0x62,
-0x72,0x65,0x77,0x37,0x61,0xa4,0xc,0x62,0xa6,0x53,0x63,0xa8,0x28,0x64,0xac,0xd3,
-0x65,5,0x6d,0xa9,0x6d,0x94,0x6e,0xa2,0x41,0x74,0x15,0x68,0x69,0x6f,0x70,0x69,
-0x63,0x5e,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0x86,0x16,0x70,0x6c,0x65,0x6d,
-0x65,0x6e,0x74,0xa3,0x86,0x11,0x78,0x74,0xa2,0x85,2,0x61,0xa3,0xc8,0x62,0xa5,
-0x37,0x65,0x13,0x6e,0x64,0x65,0x64,0xa2,0x85,1,0x61,0xa3,0xc8,0x62,0xa5,0x37,
-0x16,0x6f,0x74,0x69,0x63,0x6f,0x6e,0x73,0xa3,0xce,0x15,0x63,0x6c,0x6f,0x73,0x65,
-0x64,2,0x61,0x5a,0x63,0x9e,0x69,0x1c,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,
-0x69,0x63,0x73,0x75,0x70,0xa2,0xc4,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,
-0xc4,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0x86,1,0x65,0x2c,0x73,0x11,0x75,
-0x70,0xa3,0xc3,0x13,0x72,0x69,0x63,0x73,0x86,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,
-0x65,0x6e,0x74,0xa3,0xc3,0x11,0x6a,0x6b,0xa2,0x44,0x1f,0x6c,0x65,0x74,0x74,0x65,
-0x72,0x73,0x61,0x6e,0x64,0x6d,0x6f,0x6e,0x74,0x68,0x73,0xa3,0x44,0x61,0x4a,0x67,
-0x76,0x6c,1,0x62,0x30,0x79,0x13,0x6d,0x61,0x69,0x63,0xa5,0x25,0x13,0x61,0x73,
-0x61,0x6e,0xa3,0xe2,0x13,0x72,0x6c,0x79,0x64,0x1f,0x79,0x6e,0x61,0x73,0x74,0x69,
-0x63,0x63,0x75,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa5,1,0x1f,0x79,0x70,0x74,
-0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,1,0x66,0x26,
-0x73,0xa3,0xc2,0x1c,0x6f,0x72,0x6d,0x61,0x74,0x63,0x6f,0x6e,0x74,0x72,0x6f,0x6c,
-0x73,0xa5,0x24,7,0x6e,0xc0,0xec,0x6e,0x3e,0x72,0xa2,0x5d,0x73,0xa2,0xdf,0x76,
-0x14,0x65,0x73,0x74,0x61,0x6e,0xa3,0xbc,1,0x61,0x92,0x63,0x13,0x69,0x65,0x6e,
-0x74,1,0x67,0x34,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xa5,0x13,0x72,
-0x65,0x65,0x6b,1,0x6d,0x34,0x6e,0x15,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x7f,
-0x13,0x75,0x73,0x69,0x63,0xa2,0x7e,0x19,0x61,0x6c,0x6e,0x6f,0x74,0x61,0x74,0x69,
-0x6f,0x6e,0xa3,0x7e,0x10,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,
-0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xfe,2,0x61,0x32,0x6d,0xa2,0x78,0x72,
-0x12,0x6f,0x77,0x73,0x7d,0x12,0x62,0x69,0x63,0x38,3,0x65,0x4a,0x6d,0x74,0x70,
-0xa2,0x4a,0x73,0x11,0x75,0x70,0xa2,0x80,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,
-0xa3,0x80,0x11,0x78,0x74,2,0x61,0xa3,0xd2,0x62,0xa5,0x35,0x65,0x13,0x6e,0x64,
-0x65,0x64,1,0x61,0xa3,0xd2,0x62,0xa5,0x35,0x12,0x61,0x74,0x68,0xa2,0xd3,0x18,
-0x65,0x6d,0x61,0x74,0x69,0x63,0x61,0x6c,0x61,0x1f,0x6c,0x70,0x68,0x61,0x62,0x65,
-0x74,0x69,0x63,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd3,1,0x66,0x42,0x72,
-0x1e,0x65,0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,
-1,0x61,0xa3,0x51,0x62,0xa3,0x55,0x14,0x65,0x6e,0x69,0x61,0x6e,0x35,0x12,0x63,
-0x69,0x69,0x23,0x64,0x9e,0x65,0xa2,0x42,0x68,0xa2,0x4d,0x6c,1,0x63,0x62,0x70,
-0x17,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x70,1,0x66,0xa3,0x50,0x72,0x1e,0x65,
-0x73,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x50,
-0x16,0x68,0x65,0x6d,0x69,0x63,0x61,0x6c,0xa2,0xd0,0x16,0x73,0x79,0x6d,0x62,0x6f,
-0x6c,0x73,0xa3,0xd0,0x12,0x6c,0x61,0x6d,0xa5,7,0x1a,0x67,0x65,0x61,0x6e,0x6e,
-0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0x77,0x11,0x6f,0x6d,0xa3,0xfd,7,0x6f,0x71,
-0x6f,0x64,0x72,0xa2,0x41,0x75,0xa2,0x58,0x79,0x1b,0x7a,0x61,0x6e,0x74,0x69,0x6e,
-0x65,0x6d,0x75,0x73,0x69,0x63,0xa2,0x5b,0x18,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,
-0x6c,0x73,0xa3,0x5b,1,0x70,0x34,0x78,0x16,0x64,0x72,0x61,0x77,0x69,0x6e,0x67,
-0x89,0x14,0x6f,0x6d,0x6f,0x66,0x6f,0xa0,0x12,0x65,0x78,0x74,0xa2,0x43,0x14,0x65,
-0x6e,0x64,0x65,0x64,0xa3,0x43,0x10,0x61,1,0x68,0x40,0x69,0x12,0x6c,0x6c,0x65,
-0x92,0x17,0x70,0x61,0x74,0x74,0x65,0x72,0x6e,0x73,0x93,0x11,0x6d,0x69,0xa3,0xc9,
-1,0x67,0x2c,0x68,0x11,0x69,0x64,0xa3,0x64,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,
-0x81,0x61,0x48,0x65,0xa2,0x4e,0x68,0xa2,0x52,0x6c,0x1a,0x6f,0x63,0x6b,0x65,0x6c,
-0x65,0x6d,0x65,0x6e,0x74,0x73,0x8b,3,0x6c,0x34,0x6d,0x40,0x73,0x66,0x74,0x11,
-0x61,0x6b,0xa3,0xc7,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x93,0x11,0x75,0x6d,0xa2,
-0xb1,0x12,0x73,0x75,0x70,0xa2,0xca,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,
-0xca,1,0x69,0x30,0x73,0x13,0x61,0x76,0x61,0x68,0xa3,0xdd,0x15,0x63,0x6c,0x61,
-0x74,0x69,0x6e,0x23,0x14,0x6e,0x67,0x61,0x6c,0x69,0x41,0x16,0x61,0x69,0x6b,0x73,
-0x75,0x6b,0x69,0xa5,8,5,0x6f,0xc1,0x59,0x6f,0xa2,0x62,0x75,0xa4,0x1d,0x79,
-1,0x70,0x9c,0x72,0x14,0x69,0x6c,0x6c,0x69,0x63,0x32,1,0x65,0x4c,0x73,0x11,
-0x75,0x70,0xa2,0x61,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa2,0x61,0x12,0x61,
-0x72,0x79,0xa3,0x61,0x11,0x78,0x74,3,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5,
-9,0x65,0x13,0x6e,0x64,0x65,0x64,2,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5,
-9,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e,0x6f,0x61,0x6e,0xa5,0x36,
-0x1a,0x6f,0x74,0x73,0x79,0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x7b,3,0x6d,
-0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0,0x75,0x17,0x6e,0x74,0x69,0x6e,0x67,0x72,0x6f,
-0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0xa3,0x9a,2,0x62,
-0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61,0x74,0x6a,0x61,0x6d,0x6f,0xa3,0x41,0x14,0x69,
-0x6e,0x69,0x6e,0x67,2,0x64,0x46,0x68,0x9e,0x6d,0x1d,0x61,0x72,0x6b,0x73,0x66,
-0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x1e,0x69,0x61,0x63,0x72,0x69,
-0x74,0x69,0x63,0x61,0x6c,0x6d,0x61,0x72,0x6b,0x73,0x2e,2,0x65,0x40,0x66,0xa6,
-0x41,0x73,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x83,0x16,0x78,
-0x74,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe0,0x17,0x61,0x6c,0x66,0x6d,0x61,0x72,0x6b,
-0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f,0x69,0x6e,0x64,0x69,0x63,0x6e,0x75,0x6d,0x62,
-0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2,0x1b,0x74,0x72,0x6f,0x6c,0x70,0x69,
-0x63,0x74,0x75,0x72,0x65,0x73,0x83,0x12,0x74,0x69,0x63,0xa2,0x84,0x1b,0x65,0x70,
-0x61,0x63,0x74,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xdf,1,0x6e,0x3e,0x72,
-0x1b,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x75,0x15,0x65,
-0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98,0x16,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa2,
-0x99,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,
-0xa3,0x99,0x61,0xa2,0xe1,0x68,0xa4,0xb,0x6a,0x10,0x6b,0xa2,0x47,4,0x63,0x8c,
-0x65,0xa2,0x80,0x72,0xa2,0x98,0x73,0xa2,0xaa,0x75,0x1f,0x6e,0x69,0x66,0x69,0x65,
-0x64,0x69,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x47,0x18,0x65,0x78,
-0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,6,0x64,0x6b,0x64,0xa3,0xd1,0x65,0xa5,0,
-0x66,0xa5,0x12,0x67,0xa5,0x2e,0x14,0x6f,0x6d,0x70,0x61,0x74,0xa2,0x45,1,0x66,
-0x96,0x69,1,0x62,0x44,0x64,0x17,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,
-0x4f,0x12,0x73,0x75,0x70,0xa3,0x5f,0x14,0x69,0x6c,0x69,0x74,0x79,0xa2,0x45,1,
-0x66,0x54,0x69,0x18,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x4f,0x19,
-0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x5f,0x13,0x6f,0x72,0x6d,
-0x73,0xa3,0x53,0x11,0x78,0x74,6,0x64,0xc,0x64,0xa3,0xd1,0x65,0xa5,0,0x66,
-0xa5,0x12,0x67,0xa5,0x2e,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3,0xc5,0x19,0x61,
-0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94,0x16,0x70,0x6c,0x65,0x6d,0x65,
-0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62,0x6f,0x6c,0x73,0x9a,0x1d,0x61,
-0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x9b,0x14,0x72,
-0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72,0x64,0x75,0x1d,0x63,0x61,0x73,
-0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0xde,0x1d,0x61,0x64,
-0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,0x63,0x73,0x63,0x12,0x69,0x61,
-0x6e,0xa3,0xa8,2,0x61,0x3a,0x65,0x4c,0x6f,0x16,0x72,0x61,0x73,0x6d,0x69,0x61,
-0x6e,0xa5,0x2d,1,0x6b,0x26,0x6d,0xa3,0xa4,0x11,0x6d,0x61,0xa3,0xd4,1,0x72,
-0x38,0x73,0x17,0x73,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa5,0x19,0x13,0x6f,0x6b,
-0x65,0x65,0x60,0x12,0x73,0x75,0x70,0xa2,0xff,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,
-0x74,0xa3,0xff,3,0x65,0x3e,0x69,0x7e,0x6f,0xa2,0x69,0x75,0x15,0x70,0x6c,0x6f,
-0x79,0x61,0x6e,0xa3,0xe1,1,0x73,0x50,0x76,0x16,0x61,0x6e,0x61,0x67,0x61,0x72,
-0x69,0x3e,0x12,0x65,0x78,0x74,0xa2,0xb3,0x14,0x65,0x6e,0x64,0x65,0x64,0xa3,0xb3,
-0x13,0x65,0x72,0x65,0x74,0xa3,0x5a,2,0x61,0x3a,0x6e,0x82,0x76,0x16,0x65,0x73,
-0x61,0x6b,0x75,0x72,0x75,0xa5,0x2f,0x18,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,
-0x73,0x2e,2,0x65,0x30,0x66,0x36,0x73,0x11,0x75,0x70,0xa3,0x83,0x11,0x78,0x74,
-0xa3,0xe0,0x18,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x14,0x67,0x62,
-0x61,0x74,0x73,0x91,1,0x67,0x3e,0x6d,0x12,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,
-0x69,0x6c,0x65,0x73,0xa3,0xab,0x11,0x72,0x61,0xa5,0x1a,8,0x6d,0x5f,0x6d,0x3a,
-0x6e,0x48,0x73,0x7a,0x76,0xa2,0x4b,0x77,0x12,0x69,0x64,0x65,0x43,0x11,0x65,0x64,
-0x32,0x12,0x69,0x61,0x6c,0x33,2,0x61,0x40,0x62,0x37,0x6f,1,0x62,0x28,0x6e,
-0x10,0x65,0x21,0x13,0x72,0x65,0x61,0x6b,0x37,0x10,0x72,0x34,0x12,0x72,0x6f,0x77,
-0x35,2,0x6d,0x38,0x71,0x46,0x75,1,0x62,0x3d,0x70,0x3e,0x11,0x65,0x72,0x3f,
-1,0x61,0x24,0x6c,0x39,0x11,0x6c,0x6c,0x39,1,0x72,0x3b,0x75,0x12,0x61,0x72,
-0x65,0x3b,0x12,0x65,0x72,0x74,0x40,0x13,0x69,0x63,0x61,0x6c,0x41,0x63,0x58,0x65,
-0x92,0x66,0x96,0x69,1,0x6e,0x36,0x73,0x10,0x6f,0x30,0x14,0x6c,0x61,0x74,0x65,
-0x64,0x31,0x11,0x69,0x74,0x2e,0x12,0x69,0x61,0x6c,0x2f,2,0x61,0x36,0x69,0x48,
-0x6f,0x10,0x6d,0x24,0x12,0x70,0x61,0x74,0x25,0x10,0x6e,0x22,0x15,0x6f,0x6e,0x69,
-0x63,0x61,0x6c,0x23,0x13,0x72,0x63,0x6c,0x65,0x27,0x11,0x6e,0x63,0x27,2,0x69,
-0x3a,0x6f,0x44,0x72,0x10,0x61,0x2c,0x14,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x10,0x6e,
-0x28,0x11,0x61,0x6c,0x29,0x11,0x6e,0x74,0x2b,4,0x61,0x3a,0x66,0x4c,0x68,0x5e,
-0x6e,0x70,0x77,0x2a,0x12,0x69,0x64,0x65,0x2b,0x22,0x17,0x6d,0x62,0x69,0x67,0x75,
-0x6f,0x75,0x73,0x23,0x26,0x17,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x27,0x24,
-0x17,0x61,0x6c,0x66,0x77,0x69,0x64,0x74,0x68,0x25,0x20,1,0x61,0x30,0x65,0x14,
-0x75,0x74,0x72,0x61,0x6c,0x21,0x28,0x13,0x72,0x72,0x6f,0x77,0x29,0xd,0x6e,0xc0,
-0xfb,0x73,0x6d,0x73,0x3a,0x74,0x98,0x75,0xa2,0x49,0x7a,2,0x6c,0x3b,0x70,0x3d,
-0x73,0x39,5,0x6f,0x28,0x6f,0x57,0x70,0x34,0x75,0x16,0x72,0x72,0x6f,0x67,0x61,
-0x74,0x65,0x45,0x11,0x61,0x63,1,0x65,0x32,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,
-0x6b,0x31,0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x39,0x63,0x53,0x6b,
-0x55,0x6d,0x51,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,
-0x65,0x72,0x27,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,
-0x65,0x74,0x74,0x65,0x72,0x23,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x21,
-0x6e,0x8a,0x6f,0xa2,0x47,0x70,8,0x66,0x14,0x66,0x5b,0x69,0x59,0x6f,0x4f,0x72,
-0x24,0x73,0x49,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x43,0x61,0x2c,0x63,
-0x4d,0x64,0x47,0x65,0x4b,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,
-0x61,0x72,0x61,0x74,0x6f,0x72,0x3d,2,0x64,0x33,0x6c,0x35,0x6f,0x36,0x1b,0x6e,
-0x73,0x70,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2d,1,0x70,0x7c,0x74,
-0x12,0x68,0x65,0x72,3,0x6c,0x38,0x6e,0x42,0x70,0x4c,0x73,0x14,0x79,0x6d,0x62,
-0x6f,0x6c,0x57,0x14,0x65,0x74,0x74,0x65,0x72,0x2b,0x14,0x75,0x6d,0x62,0x65,0x72,
-0x37,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x1c,0x65,0x6e,
-0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,0x66,0x9e,0x66,0x88,
-0x69,0xa2,0x4b,0x6c,0xa2,0x5c,0x6d,4,0x61,0x60,0x63,0x31,0x65,0x2f,0x6e,0x2d,
-0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x30,0x73,0x14,0x79,0x6d,0x62,
-0x6f,0x6c,0x55,0x14,0x65,0x74,0x74,0x65,0x72,0x29,0x17,0x74,0x68,0x73,0x79,0x6d,
-0x62,0x6f,0x6c,0x51,1,0x69,0x2e,0x6f,0x13,0x72,0x6d,0x61,0x74,0x41,0x1d,0x6e,
-0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x5b,0x10,0x6e,
-0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,
-0x6e,0x59,6,0x6d,0x18,0x6d,0x29,0x6f,0x28,0x74,0x27,0x75,0x23,0x2a,0x1c,0x77,
-0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x25,0x65,0x28,0x69,
-0x3c,0x6c,0x25,0x19,0x74,0x74,0x65,0x72,0x6e,0x75,0x6d,0x62,0x65,0x72,0x35,0x1a,
-0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x3b,0x63,0x44,0x64,0xa2,
-0x60,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2f,
-6,0x6e,0x39,0x6e,0x46,0x6f,0x4e,0x73,0x45,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,
-0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x53,0x20,0x12,0x74,0x72,0x6c,0x3f,0x42,0x10,
-0x6e,1,0x6e,0x2c,0x74,0x12,0x72,0x6f,0x6c,0x3f,0x1f,0x65,0x63,0x74,0x6f,0x72,
-0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4d,0x63,0x3f,0x66,0x41,
-0x6c,0x1d,0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,
-0x4b,2,0x61,0x30,0x65,0x4a,0x69,0x12,0x67,0x69,0x74,0x33,0x1c,0x73,0x68,0x70,
-0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x47,0x1a,0x63,0x69,0x6d,0x61,
-0x6c,0x6e,0x75,0x6d,0x62,0x65,0x72,0x33,0,0x13,0x6e,0xc1,0xf,0x74,0x76,0x74,
-0x4c,0x76,0x9a,0x77,0xa2,0x48,0x79,0xa2,0x49,0x7a,1,0x61,0x2c,0x68,0x12,0x61,
-0x69,0x6e,0x8b,0x11,0x69,0x6e,0x85,2,0x61,0x36,0x65,0x3c,0x68,0x14,0x69,0x6e,
-0x79,0x65,0x68,0xa3,0x66,1,0x68,0x71,0x77,0x73,1,0x68,0x28,0x74,0x10,0x68,
-0x77,0x16,0x6d,0x61,0x72,0x62,0x75,0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,
-0x1a,0x65,0x72,0x74,0x69,0x63,0x61,0x6c,0x74,0x61,0x69,0x6c,0xa3,0x67,0x11,0x61,
-0x77,0x79,1,0x65,0x32,0x75,0x11,0x64,0x68,0x80,0x11,0x68,0x65,0x83,0x10,0x68,
-0x7a,1,0x62,0x34,0x77,0x16,0x69,0x74,0x68,0x74,0x61,0x69,0x6c,0x7f,0x14,0x61,
-0x72,0x72,0x65,0x65,0x7d,0x6e,0xa2,0x4c,0x70,0xa2,0x69,0x71,0xa2,0x69,0x72,0xa2,
-0x6f,0x73,5,0x74,0x22,0x74,0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,
-0x61,0x77,0x6f,0x18,0x72,0x61,0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,
-0x61,0x73,0x68,0x6b,0x61,0x66,0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,
-0x10,0x64,0x62,0x11,0x68,0x65,0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,
-0x69,0x10,0x6e,0x67,2,0x6f,0x2c,0x75,0x50,0x79,0x10,0x61,0x91,1,0x6a,0x28,
-0x6f,0x10,0x6e,0x55,0x1a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x67,0x72,0x6f,0x75,0x70,
-0x21,0x10,0x6e,0x57,0x10,0x65,0x59,0x10,0x61,1,0x66,0x5b,0x70,0x10,0x68,0x5d,
-1,0x65,0x38,0x6f,0x18,0x68,0x69,0x6e,0x67,0x79,0x61,0x79,0x65,0x68,0x93,1,
-0x68,0x5f,0x76,0x16,0x65,0x72,0x73,0x65,0x64,0x70,0x65,0x61,0x67,0xc1,0xc7,0x67,
-0xa4,0x52,0x68,0xa4,0x59,0x6b,0xa4,0x99,0x6c,0xa4,0xb2,0x6d,2,0x61,0x2e,0x65,
-0xa4,0x3e,0x69,0x10,0x6d,0x53,1,0x6c,0xa2,0xe7,0x6e,0x16,0x69,0x63,0x68,0x61,
-0x65,0x61,0x6e,0,0x12,0x6e,0x76,0x73,0x51,0x73,0x3e,0x74,0x5c,0x77,0xa0,0x79,
-0xa2,0x42,0x7a,0x13,0x61,0x79,0x69,0x6e,0xa3,0x54,0x10,0x61,1,0x64,0x2e,0x6d,
-0x12,0x65,0x6b,0x68,0xa3,0x4c,0x11,0x68,0x65,0xa3,0x4b,3,0x61,0x38,0x65,0x3c,
-0x68,0x4a,0x77,0x13,0x65,0x6e,0x74,0x79,0xa3,0x51,0x10,0x77,0xa3,0x4d,1,0x6e,
-0xa3,0x4e,0x74,0x10,0x68,0xa3,0x4f,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x50,0x11,
-0x61,0x77,0xa3,0x52,0x12,0x6f,0x64,0x68,0xa3,0x53,0x6e,0x3a,0x6f,0x40,0x70,0x46,
-0x71,0x4a,0x72,0x12,0x65,0x73,0x68,0xa3,0x4a,0x11,0x75,0x6e,0xa3,0x46,0x11,0x6e,
-0x65,0xa3,0x47,0x10,0x65,0xa3,0x48,0x12,0x6f,0x70,0x68,0xa3,0x49,0x67,0x33,0x67,
-0x38,0x68,0x40,0x6b,0x5e,0x6c,0x66,0x6d,0x11,0x65,0x6d,0xa3,0x45,0x13,0x69,0x6d,
-0x65,0x6c,0xa1,1,0x65,0x32,0x75,0x14,0x6e,0x64,0x72,0x65,0x64,0xa3,0x42,0x11,
-0x74,0x68,0xa3,0x41,0x12,0x61,0x70,0x68,0xa3,0x43,0x14,0x61,0x6d,0x65,0x64,0x68,
-0xa3,0x44,0x61,0x34,0x62,0x4a,0x64,0x50,0x66,0x12,0x69,0x76,0x65,0x9f,1,0x6c,
-0x2a,0x79,0x11,0x69,0x6e,0x97,0x12,0x65,0x70,0x68,0x95,0x12,0x65,0x74,0x68,0x99,
-1,0x61,0x30,0x68,0x14,0x61,0x6d,0x65,0x64,0x68,0x9d,0x13,0x6c,0x65,0x74,0x68,
-0x9b,0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,6,0x6e,0x2c,0x6e,0x34,0x72,0x5e,0x73,
-0x62,0x74,0x11,0x74,0x61,0xa3,0x63,2,0x67,0x2e,0x6e,0x32,0x79,0x10,0x61,0xa3,
-0x60,0x10,0x61,0xa3,0x5d,1,0x61,0xa3,0x5e,0x6e,0x10,0x61,0xa3,0x5f,0x10,0x61,
-0xa3,0x61,0x11,0x73,0x61,0xa3,0x62,0x62,0x3c,0x6a,0x42,0x6c,0x10,0x6c,1,0x61,
-0xa3,0x5b,0x6c,0x10,0x61,0xa3,0x5c,0x11,0x68,0x61,0xa3,0x59,0x10,0x61,0xa3,0x5a,
-0x11,0x65,0x6d,0x51,0x10,0x61,1,0x66,0x37,0x6d,0x11,0x61,0x6c,0x39,1,0x61,
-0x40,0x65,0x3e,1,0x68,0x28,0x74,0x10,0x68,0x45,0x40,0x13,0x67,0x6f,0x61,0x6c,
-0x43,2,0x68,0x3b,0x6d,0x5c,0x6e,0x1a,0x69,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,
-0x67,0x79,0x61,1,0x6b,0x2a,0x70,0x10,0x61,0xa3,0x65,0x15,0x69,0x6e,0x6e,0x61,
-0x79,0x61,0xa3,0x64,0x1a,0x7a,0x61,0x6f,0x6e,0x68,0x65,0x68,0x67,0x6f,0x61,0x6c,
-0x3d,2,0x61,0x3a,0x68,0x44,0x6e,0x17,0x6f,0x74,0x74,0x65,0x64,0x68,0x65,0x68,
-0x4b,1,0x66,0x47,0x70,0x10,0x68,0x49,0x12,0x61,0x70,0x68,0x89,0x11,0x61,0x6d,
-0x4c,0x12,0x61,0x64,0x68,0x4f,0x61,0x6e,0x62,0xa2,0x54,0x64,0xa2,0x70,0x65,0x31,
-0x66,2,0x61,0x3e,0x65,0x4a,0x69,0x19,0x6e,0x61,0x6c,0x73,0x65,0x6d,0x6b,0x61,
-0x74,0x68,0x35,0x15,0x72,0x73,0x69,0x79,0x65,0x68,0x8f,0x86,0x10,0x68,0x33,2,
-0x66,0x3c,0x69,0x70,0x6c,1,0x61,0x28,0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,
-0x14,0x72,0x69,0x63,0x61,0x6e,2,0x66,0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,
-0x58,0x11,0x65,0x68,0xa3,0x56,0x12,0x6f,0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,
-0x65,0x4a,0x75,0x10,0x72,0x1f,0x75,0x73,0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,
-0x62,0x61,0x72,0x72,0x65,0x65,0x8d,1,0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,
-0x6c,0x2c,0x16,0x61,0x74,0x68,0x72,0x69,0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,
-0x72,0x3e,0x74,0x56,0x75,0x21,0x18,0x6f,0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,
-0x21,0x28,0x1a,0x69,0x67,0x68,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,
-0x19,0x72,0x61,0x6e,0x73,0x70,0x61,0x72,0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,
-0x6a,0x56,0x6c,0x26,0x19,0x65,0x66,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,
-0x24,0x19,0x75,0x61,0x6c,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,
-0x6e,0x63,0x61,0x75,0x73,0x69,0x6e,0x67,0x23,0,0x13,0x6e,0xc0,0xd0,0x73,0x49,
-0x73,0x48,0x75,0x78,0x77,0x84,0x78,0x9c,0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,
-0x13,0x70,0x61,0x63,0x65,0x59,4,0x61,0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79,
-0x57,0x54,0x12,0x61,0x63,0x65,0x55,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53,
-0x15,0x6e,0x6b,0x6e,0x6f,0x77,0x6e,0x21,1,0x6a,0x5d,0x6f,0x17,0x72,0x64,0x6a,
-0x6f,0x69,0x6e,0x65,0x72,0x5d,0x10,0x78,0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,
-0x50,0x71,0xa2,0x6e,0x72,1,0x65,0x24,0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,
-0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,
-0x6f,0x46,0x73,0x45,0x75,0x46,0x14,0x6d,0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,
-0x6c,0x69,0x6e,0x65,0x5b,0x17,0x6e,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,
-0x70,0x48,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,
-0x49,1,0x6f,0x3e,0x72,0x4c,0x1a,0x65,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,
-0x69,0x63,0x4d,0x4a,0x1b,0x73,0x74,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,
-0x63,0x4b,0x10,0x75,0x4e,0x16,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,
-0x68,0x50,0x69,0x86,0x6a,0xa2,0x61,0x6c,0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,
-0x74,0x6f,0x72,0x79,0x62,0x72,0x65,0x61,0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,
-0x34,0x6c,0x6d,0x79,0x3a,0x13,0x70,0x68,0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,
-0x6c,0x65,0x74,0x74,0x65,0x72,0x6d,2,0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,
-0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,
-0x65,0x70,1,0x61,0x22,0x65,0x14,0x72,0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,
-0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x41,2,0x6c,0x63,0x74,0x65,0x76,0x67,1,
-0x66,0x43,0x69,0x15,0x6e,0x65,0x66,0x65,0x65,0x64,0x43,0x61,0x40,0x62,0x70,0x63,
-0xa2,0x55,0x65,0xa2,0xdb,0x67,0x10,0x6c,0x38,0x11,0x75,0x65,0x39,2,0x69,0x23,
-0x6c,0x34,0x6d,0x16,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x24,0x17,0x70,0x68,
-0x61,0x62,0x65,0x74,0x69,0x63,0x25,4,0x32,0x27,0x61,0x29,0x62,0x2b,0x6b,0x2d,
-0x72,0x12,0x65,0x61,0x6b,2,0x61,0x36,0x62,0x3e,0x73,0x15,0x79,0x6d,0x62,0x6f,
-0x6c,0x73,0x57,0x13,0x66,0x74,0x65,0x72,0x29,1,0x65,0x2a,0x6f,0x11,0x74,0x68,
-0x27,0x13,0x66,0x6f,0x72,0x65,0x2b,7,0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70,0x69,
-0x72,0x35,1,0x6d,0x76,0x6e,1,0x64,0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65,0x6e,
-0x74,0x62,0x72,0x65,0x61,0x6b,0x2f,0x15,0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f,0x6c,
-0x6a,0x61,0x70,0x61,0x6e,0x65,0x73,0x65,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x6b,
-1,0x62,0x3a,0x70,0x19,0x6c,0x65,0x78,0x63,0x6f,0x6e,0x74,0x65,0x78,0x74,0x51,
-0x18,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f,0x6a,
-0x6b,0x6c,0x30,0x13,0x6f,0x73,0x65,0x70,1,0x61,0x38,0x75,0x18,0x6e,0x63,0x74,
-0x75,0x61,0x74,0x69,0x6f,0x6e,0x31,0x18,0x72,0x65,0x6e,0x74,0x68,0x65,0x73,0x69,
-0x73,0x69,0x1b,0x72,0x72,0x69,0x61,0x67,0x65,0x72,0x65,0x74,0x75,0x72,0x6e,0x35,
-2,0x62,0x3e,0x6d,0x46,0x78,0x36,0x18,0x63,0x6c,0x61,0x6d,0x61,0x74,0x69,0x6f,
-0x6e,0x37,0x70,0x12,0x61,0x73,0x65,0x71,0x72,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,
-0x72,0x73,1,0x64,0x42,0x6e,1,0x6f,0x32,0x75,0x26,0x14,0x6d,0x65,0x72,0x69,
-0x63,0x27,0x11,0x6e,0x65,0x21,1,0x65,0x2e,0x69,0x24,0x12,0x67,0x69,0x74,0x25,
-0x22,0x14,0x63,0x69,0x6d,0x61,0x6c,0x23,0,0x18,0x6e,0xc4,0x60,0x74,0xc1,0x91,
-0x77,0x96,0x77,0xa2,0x4c,0x78,0xa2,0x70,0x79,0xa2,0x7a,0x7a,6,0x73,0x1e,0x73,
-0x34,0x78,0x42,0x79,0x48,0x7a,0x11,0x7a,0x7a,0xa3,0x67,0x10,0x79,1,0x65,0xa3,
-0xae,0x6d,0xa3,0x81,0x11,0x78,0x78,0xa3,0x66,0x11,0x79,0x79,0x21,0x61,0x30,0x69,
-0x58,0x6d,0x11,0x74,0x68,0xa3,0x80,0x10,0x6e,1,0x61,0x26,0x62,0xa3,0xb1,0x1a,
-0x62,0x61,0x7a,0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e,0x68,
-0x23,2,0x61,0x30,0x63,0x5a,0x6f,0x11,0x6c,0x65,0xa3,0x9b,1,0x6e,0x3c,0x72,
-0x10,0x61,0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0x92,0x12,0x63,0x68,
-0x6f,0xa3,0xbc,0x11,0x68,0x6f,0xa3,0xbc,1,0x70,0x2c,0x73,0x11,0x75,0x78,0xa3,
-0x65,0x11,0x65,0x6f,0x9b,1,0x65,0x2c,0x69,0x72,0x11,0x69,0x69,0x73,0x11,0x7a,
-0x69,0xa2,0xc0,0x11,0x64,0x69,0xa3,0xc0,0x74,0x66,0x75,0xa2,0xde,0x76,1,0x61,
-0x48,0x69,1,0x73,0x38,0x74,0x10,0x68,0xa2,0xc5,0x13,0x6b,0x75,0x71,0x69,0xa3,
-0xc5,0x10,0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,7,0x68,0x3e,
-0x68,0x34,0x69,0x48,0x6e,0x86,0x6f,0x11,0x74,0x6f,0xa3,0xc4,0x10,0x61,1,0x61,
-0x24,0x69,0x6d,0x6a,0x11,0x6e,0x61,0x6b,2,0x62,0x3a,0x66,0x4a,0x72,0x10,0x68,
-0xa2,0x9e,0x12,0x75,0x74,0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74,0x61,
-0x6e,0x6f,0x14,0x69,0x6e,0x61,0x67,0x68,0x99,0x11,0x73,0x61,0xa3,0xc3,0x61,0x36,
-0x65,0xa2,0x65,0x66,0xa2,0x71,0x67,0x11,0x6c,0x67,0x75,6,0x6c,0x28,0x6c,0x32,
-0x6d,0x38,0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1,0x65,0x89,0x75,0x97,1,0x69,
-0x24,0x6c,0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a,1,0x73,0x2a,0x75,0x10,0x74,
-0xa3,0x9a,0x10,0x61,0xa3,0xc3,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99,0x10,
-0x69,0xa3,0x99,1,0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12,0x6c,
-0x6f,0x67,0x75,2,0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f,0x10,
-0x65,0x89,0x12,0x68,0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3,0x62,
-0x10,0x75,0x68,0x11,0x67,0x75,0x69,0x11,0x6e,0x67,0x99,1,0x67,0x32,0x6e,0x14,
-0x6b,0x6e,0x6f,0x77,0x6e,0xa3,0x67,0x11,0x61,0x72,0x8a,0x13,0x69,0x74,0x69,0x63,
-0x8b,0x71,0xc1,0x13,0x71,0xa2,0xde,0x72,0xa2,0xe3,0x73,6,0x69,0x8a,0x69,0x72,
-0x6f,0xa2,0x4c,0x75,0xa2,0x75,0x79,1,0x6c,0x46,0x72,4,0x63,0x65,0x65,0xa3,
-0x5f,0x69,0x2c,0x6a,0xa3,0x60,0x6e,0xa3,0x61,0x11,0x61,0x63,0x65,0x10,0x6f,0x94,
-0x16,0x74,0x69,0x6e,0x61,0x67,0x72,0x69,0x95,2,0x64,0x3c,0x67,0x4c,0x6e,1,
-0x64,0xa3,0x91,0x68,0x62,0x12,0x61,0x6c,0x61,0x63,0x10,0x64,0xa2,0xa6,0x12,0x68,
-0x61,0x6d,0xa3,0xa6,0x17,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa3,0x70,2,
-0x67,0x3a,0x72,0x52,0x79,0x10,0x6f,0xa2,0xb0,0x12,0x6d,0x62,0x6f,0xa3,0xb0,1,
-0x64,0x26,0x6f,0xa3,0xb8,0xa2,0xb7,0x12,0x69,0x61,0x6e,0xa3,0xb7,0x10,0x61,0xa2,
-0x98,0x16,0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2,0x71,
-0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0x71,0x61,0x5c,0x67,0xa2,0x43,0x68,1,0x61,
-0x2a,0x72,0x10,0x64,0xa3,0x97,2,0x72,0x28,0x76,0x30,0x77,0x87,0x12,0x61,0x64,
-0x61,0xa3,0x97,0x12,0x69,0x61,0x6e,0x87,2,0x6d,0x40,0x72,0x58,0x75,0x10,0x72,
-0xa2,0x6f,0x15,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0x6f,1,0x61,0x26,0x72,0xa3,
-0x7e,0x14,0x72,0x69,0x74,0x61,0x6e,0xa3,0x7e,1,0x61,0xa3,0x5e,0x62,0xa3,0x85,
-0x11,0x6e,0x77,0xa3,0x70,0x11,0x61,0x61,1,0x63,0x2f,0x69,0x23,3,0x65,0x3e,
-0x6a,0x48,0x6f,0x4e,0x75,0x10,0x6e,1,0x69,0x24,0x72,0x61,0x10,0x63,0x61,0x13,
-0x6a,0x61,0x6e,0x67,0xa3,0x6e,0x11,0x6e,0x67,0xa3,0x6e,1,0x68,0x2a,0x72,0x10,
-0x6f,0xa3,0x5d,0x10,0x67,0xa3,0xb6,0x6e,0xa2,0x83,0x6f,0xa2,0xf2,0x70,5,0x6c,
-0x1e,0x6c,0x44,0x72,0x4a,0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68,0x6c,
-0x61,0x76,0x69,0xa3,0x7b,0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d,0x61,
-0x7c,0x65,0xa2,0x54,0x68,3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65,0x6e,
-0x69,0x63,0x69,0x61,0x6e,0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61,0xa3,
-0x5a,2,0x69,0xa3,0x7a,0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b,2,
-0x68,0x3e,0x6c,0x50,0x75,0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75,0xa3,
-0xa5,0x17,0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2,0x90,
-0x14,0x79,0x72,0x65,0x6e,0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,6,0x6b,0x36,
-0x6b,0x56,0x73,0x6e,0x75,0x74,0x79,0x11,0x69,0x61,0x1f,0x6b,0x65,0x6e,0x67,0x70,
-0x75,0x61,0x63,0x68,0x75,0x65,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xba,1,0x67,0x2e,
-0x6f,0xa2,0x57,0x10,0x6f,0xa3,0x57,0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3,0x96,
-0x12,0x73,0x68,0x75,0xa3,0x96,0x61,0x42,0x62,0x80,0x65,0x10,0x77,1,0x61,0xa3,
-0xaa,0x74,0x14,0x61,0x69,0x6c,0x75,0x65,0x97,2,0x62,0x2e,0x6e,0x3c,0x72,0x10,
-0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0x8f,0x10,0x64,0xa2,0xbb,
-0x16,0x69,0x6e,0x61,0x67,0x61,0x72,0x69,0xa3,0xbb,0x11,0x61,0x74,0xa3,0x8f,4,
-0x67,0x3c,0x6c,0x4e,0x72,0xa2,0x8e,0x73,0xa2,0x9c,0x75,0x11,0x67,0x72,0xa3,0xc2,
-1,0x61,0x2a,0x68,0x11,0x61,0x6d,0x5b,0x10,0x6d,0x5b,1,0x63,0xa2,0x6a,0x64,
-6,0x70,0x41,0x70,0x3a,0x73,0x58,0x74,0x86,0x75,0x14,0x79,0x67,0x68,0x75,0x72,
-0xa3,0xc2,0x11,0x65,0x72,1,0x6d,0x2c,0x73,0x12,0x69,0x61,0x6e,0x9b,0x11,0x69,
-0x63,0xa3,0x59,0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62,
-0x69,0x61,0x6e,0xa3,0x85,0x13,0x64,0x69,0x61,0x6e,0xa3,0xb8,0x14,0x75,0x72,0x6b,
-0x69,0x63,0xa3,0x58,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,
-0x61,0x62,0x69,0x61,0x6e,0xa3,0x8e,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,
-0xa3,0x4c,0x14,0x74,0x61,0x6c,0x69,0x63,0x5d,1,0x68,0x26,0x6b,0xa3,0x6d,0x12,
-0x69,0x6b,0x69,0xa3,0x6d,2,0x69,0x2c,0x6b,0x30,0x79,0x10,0x61,0x5f,0x11,0x79,
-0x61,0x5f,0x10,0x68,0xa3,0x58,2,0x61,0x36,0x67,0x3c,0x6d,0x10,0x61,0x84,0x12,
-0x6e,0x79,0x61,0x85,0x11,0x67,0x65,0xa3,0xab,0x10,0x65,0xa3,0xab,0x68,0xc3,0xd,
-0x6b,0xc2,0x24,0x6b,0xa4,0x17,0x6c,0xa4,0xb2,0x6d,8,0x6f,0x46,0x6f,0x48,0x72,
-0x74,0x74,0x80,0x75,0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e,0x6d,
-0x61,0x72,0x59,2,0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69,0xa3,
-0xa3,0x10,0x67,0x56,0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95,0x10,
-0x6f,0xa3,0x95,0x11,0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61,0x6e,
-0x69,0xa3,0xa4,0x61,0x36,0x65,0xa2,0x67,0x69,0xa2,0xbd,0x6c,0x11,0x79,0x6d,0x55,
-6,0x6e,0x38,0x6e,0x32,0x72,0x5c,0x73,0x6c,0x79,0x10,0x61,0xa3,0x55,1,0x64,
-0x38,0x69,0xa2,0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0x79,0xa2,0x54,0x12,
-0x61,0x69,0x63,0xa3,0x54,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e,0xa3,0xa9,0x18,
-0x61,0x72,0x61,0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x36,0x6b,0x4c,0x6c,
-0x15,0x61,0x79,0x61,0x6c,0x61,0x6d,0x55,1,0x61,0x26,0x6a,0xa3,0xa0,0x13,0x6a,
-0x61,0x6e,0x69,0xa3,0xa0,0x10,0x61,0xa2,0xb4,0x12,0x73,0x61,0x72,0xa3,0xb4,3,
-0x64,0x78,0x65,0x94,0x6e,0xa2,0x42,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56,0x13,
-0x69,0x74,0x69,0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,
-0x70,0x68,0x73,0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,1,0x65,
-0x26,0x66,0xa3,0xb5,0x16,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa3,0xb5,0x17,0x74,
-0x65,0x69,0x6d,0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65,0x6b,
-0x69,0x6b,0x61,0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,6,0x6e,0x1a,
-0x6e,0x34,0x6f,0x38,0x70,0x3e,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x64,0x61,0x4b,
-0x11,0x72,0x65,0xa3,0x77,0x11,0x65,0x6c,0xa3,0x8a,0x61,0x30,0x68,0x9a,0x69,0x11,
-0x74,0x73,0xa3,0xbf,4,0x69,0x3c,0x6c,0x44,0x6e,0x48,0x74,0x56,0x79,0x13,0x61,
-0x68,0x6c,0x69,0xa3,0x4f,0x12,0x74,0x68,0x69,0xa3,0x78,0x10,0x69,0xa3,0x4f,1,
-0x61,0x4d,0x6e,0x12,0x61,0x64,0x61,0x4b,0x14,0x61,0x6b,0x61,0x6e,0x61,0x4c,0x19,
-0x6f,0x72,0x68,0x69,0x72,0x61,0x67,0x61,0x6e,0x61,0x8d,4,0x61,0x40,0x69,0x52,
-0x6d,0x70,0x6f,0x7c,0x75,0x15,0x64,0x61,0x77,0x61,0x64,0x69,0xa3,0x91,0x10,0x72,
-0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69,0x93,0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,
-0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74,0xa3,0xbf,1,0x65,0x24,0x72,0x4f,0x10,
-0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b,0x69,0xa3,0x9d,4,0x61,0x5c,0x65,0x90,
-0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63,0x34,0x64,0x10,0x69,0xa2,0x6c,0x11,0x61,
-0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11,0x61,0x6e,0xa3,0x6b,2,0x6e,0x42,0x6f,
-0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3,0x51,0x69,0x24,0x6e,0x53,0x10,0x6e,0x53,
-0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51,0x11,0x70,0x63,0xa2,0x52,0x11,0x68,0x61,
-0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73,0x10,0x75,0xa3,0x83,0x10,0x62,0x80,0x10,
-0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83,0x65,0x11,0x61,0x72,1,0x61,0xa3,0x53,
-0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68,0x6e,0x69,0xa2,0x95,0x6a,2,0x61,0x30,
-0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94,1,0x6d,0x38,0x76,0x10,0x61,0xa2,0x4e,
-0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10,0x6f,0xa3,0xad,0x11,0x61,0x6e,0xa3,0x69,
-6,0x6c,0x1e,0x6c,0x34,0x6d,0x3a,0x72,0x48,0x75,0x11,0x6e,0x67,0xa3,0x4c,0x11,
-0x75,0x77,0xa3,0x9c,0x10,0x6e,1,0x67,0xa3,0x4b,0x70,0xa3,0xba,0x11,0x6b,0x74,
-0x8d,0x61,0x3c,0x65,0xa2,0x43,0x69,0x11,0x72,0x61,0x48,0x13,0x67,0x61,0x6e,0x61,
-0x49,1,0x6e,0x34,0x74,0x10,0x72,0xa2,0xa2,0x11,0x61,0x6e,0xa3,0xa2,0x42,6,
-0x6f,0xe,0x6f,0x77,0x73,0xa3,0x49,0x74,0xa3,0x4a,0x75,0x12,0x6e,0x6f,0x6f,0x77,
-0x62,0xa3,0xac,0x67,0x3e,0x69,0x42,0x19,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,
-0x79,0x61,0xa3,0xb6,0x44,0x11,0x75,0x6c,0x45,0x11,0x62,0x72,0x46,0x11,0x65,0x77,
-0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11,0x61,0x6c,0x5d,0x1c,0x70,0x65,0x72,0x69,
-0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0x74,2,0x64,0x66,0x68,0x6a,
-0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1,0x68,
-0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0x7d,0x13,0x6c,0x61,0x76,0x69,0xa3,
-0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72,0x69,0x74,0x65,0x64,0x23,0x64,0xc1,0xd,
-0x64,0xa2,0x7a,0x65,0xa2,0xc1,0x67,4,0x65,0x82,0x6c,0x9a,0x6f,0xa2,0x46,0x72,
-0xa2,0x55,0x75,2,0x6a,0x3c,0x6e,0x4e,0x72,1,0x6d,0x24,0x75,0x41,0x13,0x75,
-0x6b,0x68,0x69,0x41,1,0x61,0x24,0x72,0x3f,0x13,0x72,0x61,0x74,0x69,0x3f,0x18,
-0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xb3,0x10,0x6f,1,0x6b,0xa3,
-0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e,0x39,0x11,0x61,0x67,0x90,0x15,0x6f,0x6c,
-0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30,0x74,0x10,0x68,0x3a,0x11,0x69,0x63,0x3b,
-1,0x67,0xa3,0xb3,0x6d,0xa3,0xaf,1,0x61,0x32,0x65,1,0x65,0x24,0x6b,0x3d,
-0x10,0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12,0x74,0x68,0x61,0xa3,0x89,4,0x65,0x46,
-0x69,0x6c,0x6f,0x8c,0x73,0x9a,0x75,0x11,0x70,0x6c,0xa2,0x87,0x13,0x6f,0x79,0x61,
-0x6e,0xa3,0x87,1,0x73,0x38,0x76,0x10,0x61,0x34,0x15,0x6e,0x61,0x67,0x61,0x72,
-0x69,0x35,0x13,0x65,0x72,0x65,0x74,0x33,1,0x61,0x36,0x76,0x16,0x65,0x73,0x61,
-0x6b,0x75,0x72,0x75,0xa3,0xbe,0x10,0x6b,0xa3,0xbe,0x11,0x67,0x72,0xa2,0xb2,0x10,
-0x61,0xa3,0xb2,0x11,0x72,0x74,0x33,2,0x67,0x3a,0x6c,0x72,0x74,0x11,0x68,0x69,
-0x36,0x13,0x6f,0x70,0x69,0x63,0x37,0x10,0x79,2,0x64,0xa3,0x45,0x68,0xa3,0x46,
-0x70,0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,
-0x70,0x68,0x73,0xa3,0x47,1,0x62,0x36,0x79,0x10,0x6d,0xa2,0xb9,0x12,0x61,0x69,
-0x63,0xa3,0xb9,0x10,0x61,0xa2,0x88,0x12,0x73,0x61,0x6e,0xa3,0x88,0x61,0xa2,0xc9,
-0x62,0xa4,0x2e,0x63,6,0x6f,0x52,0x6f,0x76,0x70,0x92,0x75,0xa2,0x41,0x79,1,
-0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31,0x73,0xa3,0x44,0x13,0x6c,0x6c,0x69,0x63,
-0x31,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e,0x6f,0x61,0x6e,0xa3,0xc1,
-0x11,0x6f,0x74,0x7f,1,0x6d,0x30,0x70,0x10,0x74,0x2e,0x11,0x69,0x63,0x2f,0x12,
-0x6d,0x6f,0x6e,0x21,1,0x6d,0x28,0x72,0x10,0x74,0x7f,0x10,0x6e,0xa3,0xc1,0x16,
-0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa3,0x65,0x61,0x32,0x68,0xa2,0x41,0x69,0x11,
-0x72,0x74,0xa3,0x43,3,0x6b,0x4c,0x6e,0x50,0x72,0x76,0x75,0x1d,0x63,0x61,0x73,
-0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,0xa3,0x9f,0x10,0x6d,0xa3,
-0x76,1,0x61,0x24,0x73,0x71,0x1d,0x64,0x69,0x61,0x6e,0x61,0x62,0x6f,0x72,0x69,
-0x67,0x69,0x6e,0x61,0x6c,0x71,0x10,0x69,0xa2,0x68,0x11,0x61,0x6e,0xa3,0x68,3,
-0x61,0x32,0x65,0x44,0x6f,0x52,0x72,0x10,0x73,0xa3,0xbd,1,0x6b,0x26,0x6d,0xa3,
-0x42,0x11,0x6d,0x61,0xa3,0x76,0x10,0x72,0x2c,0x13,0x6f,0x6b,0x65,0x65,0x2d,0x16,
-0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa3,0xbd,6,0x68,0x4a,0x68,0x48,0x6e,0x4e,
-0x72,0x76,0x76,1,0x65,0x2a,0x73,0x10,0x74,0xa3,0x75,0x13,0x73,0x74,0x61,0x6e,
-0xa3,0x75,0x11,0x6f,0x6d,0xa3,0xa1,0x11,0x61,0x74,0x1f,0x6f,0x6c,0x69,0x61,0x6e,
-0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x9c,1,0x61,0x3e,
-0x6d,2,0x65,0x2a,0x69,0xa3,0x74,0x6e,0x27,0x13,0x6e,0x69,0x61,0x6e,0x27,0x10,
-0x62,0x24,0x11,0x69,0x63,0x25,0x64,0x30,0x66,0x44,0x67,0x11,0x68,0x62,0xa3,0x9f,
-0x10,0x6c,1,0x61,0x26,0x6d,0xa3,0xa7,0x10,0x6d,0xa3,0xa7,0x11,0x61,0x6b,0xa3,
-0x93,6,0x6c,0x3c,0x6c,0x52,0x6f,0x56,0x72,0x66,0x75,1,0x67,0x30,0x68,1,
-0x64,0x79,0x69,0x10,0x64,0x79,0x10,0x69,0x8e,0x13,0x6e,0x65,0x73,0x65,0x8f,0x11,
-0x69,0x73,0xa1,0x11,0x70,0x6f,0x2a,0x13,0x6d,0x6f,0x66,0x6f,0x2b,0x10,0x61,1,
-0x68,0x2e,0x69,0x7c,0x12,0x6c,0x6c,0x65,0x7d,0xa2,0x41,0x11,0x6d,0x69,0xa3,0x41,
-0x61,0x48,0x65,0x9c,0x68,1,0x61,0x2a,0x6b,0x10,0x73,0xa3,0xa8,0x15,0x69,0x6b,
-0x73,0x75,0x6b,0x69,0xa3,0xa8,3,0x6c,0x3a,0x6d,0x48,0x73,0x54,0x74,1,0x61,
-0x24,0x6b,0x9f,0x10,0x6b,0x9f,0x10,0x69,0x9c,0x13,0x6e,0x65,0x73,0x65,0x9d,0x10,
-0x75,0xa2,0x82,0x10,0x6d,0xa3,0x82,0x10,0x73,0xa2,0x86,0x13,0x61,0x76,0x61,0x68,
-0xa3,0x86,0x11,0x6e,0x67,0x28,0x12,0x61,0x6c,0x69,0x29,3,0x6c,0x42,0x6e,0x90,
-0x74,0xa2,0x46,0x76,0x24,0x17,0x6f,0x77,0x65,0x6c,0x6a,0x61,0x6d,0x6f,0x25,0x22,
-1,0x65,0x54,0x76,0x28,1,0x73,0x38,0x74,0x2a,0x17,0x73,0x79,0x6c,0x6c,0x61,
-0x62,0x6c,0x65,0x2b,0x16,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x29,0x18,0x61,0x64,
-0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x23,1,0x61,0x21,0x6f,0x1a,0x74,0x61,0x70,
-0x70,0x6c,0x69,0x63,0x61,0x62,0x6c,0x65,0x21,0x26,0x1a,0x72,0x61,0x69,0x6c,0x69,
-0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x27,1,0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,
-0x20,0x10,0x6f,0x21,1,0x6e,0x2c,0x79,0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,
-0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,
-0x62,0x65,0x25,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,
-0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,0xb,0x72,0x39,
-0x76,0xc,0x76,0x33,0x78,0x2a,0x7a,0x11,0x77,0x6a,0x43,0x10,0x78,0x21,0x72,0x28,
-0x73,0x50,0x74,0x31,1,0x65,0x24,0x69,0x39,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,
-0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x39,1,0x6d,0x35,0x70,0x18,0x61,
-0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x35,0x6c,0x1f,0x6c,0x3c,0x6f,0x4a,0x70,
-1,0x70,0x37,0x72,0x14,0x65,0x70,0x65,0x6e,0x64,0x37,0x28,1,0x66,0x2b,0x76,
-0x2c,0x10,0x74,0x2f,0x13,0x74,0x68,0x65,0x72,0x21,0x63,0x4c,0x65,0x64,0x67,1,
-0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x41,0x10,
-0x7a,0x41,2,0x6e,0x23,0x6f,0x24,0x72,0x25,0x14,0x6e,0x74,0x72,0x6f,0x6c,0x23,
-2,0x62,0x34,0x6d,0x4e,0x78,0x26,0x13,0x74,0x65,0x6e,0x64,0x27,0x3a,1,0x61,
-0x24,0x67,0x3d,0x11,0x73,0x65,0x3a,0x12,0x67,0x61,0x7a,0x3d,0x3e,0x16,0x6f,0x64,
-0x69,0x66,0x69,0x65,0x72,0x3f,9,0x6e,0x4a,0x6e,0x34,0x6f,0x44,0x73,0x60,0x75,
-0x94,0x78,0x10,0x78,0x21,0x10,0x75,0x2a,0x14,0x6d,0x65,0x72,0x69,0x63,0x2b,1,
-0x6c,0x2c,0x74,0x12,0x68,0x65,0x72,0x21,0x14,0x65,0x74,0x74,0x65,0x72,0x2d,3,
-0x63,0x36,0x65,0x46,0x70,0x31,0x74,0x32,0x12,0x65,0x72,0x6d,0x33,0x3c,0x16,0x6f,
-0x6e,0x74,0x69,0x6e,0x75,0x65,0x3d,0x2e,0x10,0x70,0x2f,0x10,0x70,0x34,0x12,0x70,
-0x65,0x72,0x35,0x61,0x46,0x63,0x52,0x65,0x64,0x66,0x72,0x6c,2,0x65,0x2d,0x66,
-0x3b,0x6f,0x28,0x12,0x77,0x65,0x72,0x29,0x10,0x74,0x22,0x12,0x65,0x72,0x6d,0x23,
-1,0x6c,0x24,0x72,0x37,0x24,0x12,0x6f,0x73,0x65,0x25,0x10,0x78,0x38,0x13,0x74,
-0x65,0x6e,0x64,0x39,0x10,0x6f,0x26,0x13,0x72,0x6d,0x61,0x74,0x27,0,0x10,0x6c,
-0x88,0x72,0x40,0x72,0x36,0x73,0x5e,0x77,0x7a,0x78,0x8a,0x7a,0x11,0x77,0x6a,0x4b,
-1,0x65,0x24,0x69,0x3b,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,
-0x63,0x61,0x74,0x6f,0x72,0x3b,1,0x69,0x24,0x71,0x3f,0x18,0x6e,0x67,0x6c,0x65,
-0x71,0x75,0x6f,0x74,0x65,0x3f,0x17,0x73,0x65,0x67,0x73,0x70,0x61,0x63,0x65,0x4d,
-0x10,0x78,0x21,0x6c,0x36,0x6d,0x3c,0x6e,0x76,0x6f,0x13,0x74,0x68,0x65,0x72,0x21,
-1,0x65,0x23,0x66,0x35,3,0x62,0x37,0x69,0x28,0x6c,0x29,0x6e,0x2b,0x10,0x64,
-1,0x6c,0x34,0x6e,0x11,0x75,0x6d,0x2a,0x12,0x6c,0x65,0x74,0x37,0x14,0x65,0x74,
-0x74,0x65,0x72,0x29,2,0x65,0x36,0x6c,0x39,0x75,0x2c,0x14,0x6d,0x65,0x72,0x69,
-0x63,0x2d,0x14,0x77,0x6c,0x69,0x6e,0x65,0x39,0x66,0x3f,0x66,0x40,0x67,0x4e,0x68,
-0x70,0x6b,0x10,0x61,0x26,0x15,0x74,0x61,0x6b,0x61,0x6e,0x61,0x27,0x10,0x6f,0x24,
-0x13,0x72,0x6d,0x61,0x74,0x25,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,
-0x65,0x72,0x7a,0x77,0x6a,0x49,0x10,0x7a,0x49,1,0x65,0x24,0x6c,0x3d,0x19,0x62,
-0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,0x61,0x86,0x63,0x92,0x64,0x94,
-0x65,2,0x62,0x44,0x6d,0x5e,0x78,0x2e,0x13,0x74,0x65,0x6e,0x64,0x32,0x15,0x6e,
-0x75,0x6d,0x6c,0x65,0x74,0x2f,0x42,1,0x61,0x24,0x67,0x45,0x11,0x73,0x65,0x42,
-0x12,0x67,0x61,0x7a,0x45,0x46,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x47,0x15,
-0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x10,0x72,0x31,1,0x6f,0x24,0x71,0x41,0x18,
-0x75,0x62,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x41,2,0x63,0x32,0x6e,0x3c,0x6f,
-0x22,0x12,0x70,0x65,0x6e,0x23,0x24,0x13,0x6c,0x6f,0x73,0x65,0x25,0x20,0x12,0x6f,
-0x6e,0x65,0x21,6,0x6f,0x65,0x6f,0x4a,0x72,0x5c,0x74,0x64,0x76,0x1d,0x69,0x73,
-0x75,0x61,0x6c,0x6f,0x72,0x64,0x65,0x72,0x6c,0x65,0x66,0x74,0x3d,0x18,0x76,0x65,
-0x72,0x73,0x74,0x72,0x75,0x63,0x6b,0x2d,0x13,0x69,0x67,0x68,0x74,0x2f,0x11,0x6f,
-0x70,0x30,0x12,0x61,0x6e,0x64,2,0x62,0x32,0x6c,0x62,0x72,0x13,0x69,0x67,0x68,
-0x74,0x3b,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x32,0x12,0x61,0x6e,0x64,1,0x6c,0x2e,
-0x72,0x13,0x69,0x67,0x68,0x74,0x35,0x12,0x65,0x66,0x74,0x3f,0x12,0x65,0x66,0x74,
-0x36,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74,0x39,0x62,0x2c,0x6c,0x5c,0x6e,
-0x10,0x61,0x21,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x22,0x12,0x61,0x6e,0x64,1,0x6c,
-0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x27,0x12,0x65,0x66,0x74,0x25,0x12,0x65,0x66,
-0x74,0x28,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74,0x2b,0xd,0x6e,0xaa,0x72,
-0x70,0x72,0x92,0x73,0xa2,0x46,0x74,0xa2,0x54,0x76,1,0x69,0x60,0x6f,0x12,0x77,
-0x65,0x6c,0x62,1,0x64,0x3a,0x69,0x19,0x6e,0x64,0x65,0x70,0x65,0x6e,0x64,0x65,
-0x6e,0x74,0x67,0x17,0x65,0x70,0x65,0x6e,0x64,0x65,0x6e,0x74,0x65,1,0x72,0x2e,
-0x73,0x13,0x61,0x72,0x67,0x61,0x61,0x12,0x61,0x6d,0x61,0x5f,0x1d,0x65,0x67,0x69,
-0x73,0x74,0x65,0x72,0x73,0x68,0x69,0x66,0x74,0x65,0x72,0x57,0x1e,0x79,0x6c,0x6c,
-0x61,0x62,0x6c,0x65,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x59,0x12,0x6f,0x6e,
-0x65,1,0x6c,0x2c,0x6d,0x12,0x61,0x72,0x6b,0x5d,0x14,0x65,0x74,0x74,0x65,0x72,
-0x5b,0x6e,0x3c,0x6f,0x7c,0x70,0x18,0x75,0x72,0x65,0x6b,0x69,0x6c,0x6c,0x65,0x72,
-0x55,1,0x6f,0x4c,0x75,1,0x6b,0x3c,0x6d,0x12,0x62,0x65,0x72,0x50,0x15,0x6a,
-0x6f,0x69,0x6e,0x65,0x72,0x53,0x11,0x74,0x61,0x4f,0x16,0x6e,0x6a,0x6f,0x69,0x6e,
-0x65,0x72,0x4d,0x13,0x74,0x68,0x65,0x72,0x21,0x67,0x3e,0x67,0x4a,0x69,0x64,0x6a,
-0x82,0x6d,0x1d,0x6f,0x64,0x69,0x66,0x79,0x69,0x6e,0x67,0x6c,0x65,0x74,0x74,0x65,
-0x72,0x4b,0x1c,0x65,0x6d,0x69,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x6d,0x61,0x72,0x6b,
-0x45,0x1e,0x6e,0x76,0x69,0x73,0x69,0x62,0x6c,0x65,0x73,0x74,0x61,0x63,0x6b,0x65,
-0x72,0x47,0x14,0x6f,0x69,0x6e,0x65,0x72,0x49,0x61,0xa2,0xba,0x62,0xa2,0xc0,0x63,
-1,0x61,0xa2,0xa2,0x6f,0x16,0x6e,0x73,0x6f,0x6e,0x61,0x6e,0x74,0x2a,8,0x6b,
-0x67,0x6b,0x48,0x6d,0x52,0x70,0x5c,0x73,0xa2,0x42,0x77,0x19,0x69,0x74,0x68,0x73,
-0x74,0x61,0x63,0x6b,0x65,0x72,0x43,0x14,0x69,0x6c,0x6c,0x65,0x72,0x35,0x14,0x65,
-0x64,0x69,0x61,0x6c,0x37,1,0x6c,0x52,0x72,0x10,0x65,1,0x63,0x2e,0x66,0x13,
-0x69,0x78,0x65,0x64,0x3d,0x19,0x65,0x64,0x69,0x6e,0x67,0x72,0x65,0x70,0x68,0x61,
-0x3b,0x18,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,0x39,0x10,0x75,1,0x62,
-0x3e,0x63,0x1b,0x63,0x65,0x65,0x64,0x69,0x6e,0x67,0x72,0x65,0x70,0x68,0x61,0x41,
-0x15,0x6a,0x6f,0x69,0x6e,0x65,0x64,0x3f,0x64,0x4c,0x66,0x52,0x68,0x5a,0x69,0x1e,
-0x6e,0x69,0x74,0x69,0x61,0x6c,0x70,0x6f,0x73,0x74,0x66,0x69,0x78,0x65,0x64,0x33,
-0x12,0x65,0x61,0x64,0x2d,0x13,0x69,0x6e,0x61,0x6c,0x2f,0x18,0x65,0x61,0x64,0x6c,
-0x65,0x74,0x74,0x65,0x72,0x31,0x1d,0x6e,0x74,0x69,0x6c,0x6c,0x61,0x74,0x69,0x6f,
-0x6e,0x6d,0x61,0x72,0x6b,0x29,0x16,0x76,0x61,0x67,0x72,0x61,0x68,0x61,0x23,1,
-0x69,0x4a,0x72,0x10,0x61,0x1f,0x68,0x6d,0x69,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,
-0x6e,0x75,0x6d,0x62,0x65,0x72,0x27,0x12,0x6e,0x64,0x75,0x25,2,0x72,0x38,0x74,
-0x46,0x75,0x26,0x15,0x70,0x72,0x69,0x67,0x68,0x74,0x27,0x20,0x15,0x6f,0x74,0x61,
-0x74,0x65,0x64,0x21,1,0x72,0x24,0x75,0x25,0x22,0x18,0x61,0x6e,0x73,0x66,0x6f,
-0x72,0x6d,0x65,0x64,1,0x72,0x32,0x75,0x15,0x70,0x72,0x69,0x67,0x68,0x74,0x25,
-0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x23,0xd,0x6e,0xc1,0x86,0x73,0xa8,0x73,0x4c,
-0x74,0xa2,0x76,0x75,0xa2,0x83,0x7a,0xd8,0x70,0,2,0x6c,0xd9,0x20,0,0x70,
-0xd9,0x40,0,0x73,0xc3,0,0xfe,0xf,0,0,0,7,0x6f,0x3c,0x6f,0xff,
-8,0,0,0,0x70,0x3a,0x75,0x6e,0x79,0x13,0x6d,0x62,0x6f,0x6c,0xff,0xf,
-0,0,0,0x11,0x61,0x63,1,0x65,0x34,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,
-0x6b,0xa5,0,0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xc3,0,0x16,
-0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0xe1,0,0,0x63,0xff,2,0,0,0,
-0x65,0x38,0x6b,0xff,4,0,0,0,0x6d,0xff,1,0,0,0,0x16,0x70,
-0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x70,0,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,
-0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,1,0x6e,0x40,0x70,0x1c,0x70,0x65,
-0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x25,0x17,0x61,0x73,0x73,
-0x69,0x67,0x6e,0x65,0x64,0x23,0x6e,0xa2,0x69,0x6f,0xa2,0x89,0x70,0xfe,0x30,0xf8,
-0,0,9,0x69,0x33,0x69,0xff,0x10,0,0,0,0x6f,0xfd,0x80,0,0,
-0x72,0x54,0x73,0xf9,0,0,0x75,0x12,0x6e,0x63,0x74,0xfe,0x30,0xf8,0,0,
-0x15,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x30,0xf8,0,0,0x17,0x69,0x76,0x61,
-0x74,0x65,0x75,0x73,0x65,0xdd,0,0,0x61,0x48,0x63,0xfd,0x40,0,0,0x64,
-0xe9,0,0,0x65,0xfd,0x20,0,0,0x66,0xff,0x20,0,0,0,0x1f,0x72,
-0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,
-0x40,0,0xbe,0,3,0x64,0xa7,0,0x6c,0xab,0,0x6f,0x30,0x75,0x13,0x6d,
-0x62,0x65,0x72,0xbf,0,0xb2,0,0x1b,0x6e,0x73,0x70,0x61,0x63,0x69,0x6e,0x67,
-0x6d,0x61,0x72,0x6b,0xa1,1,0x70,0x92,0x74,0x12,0x68,0x65,0x72,0xe6,0x80,1,
-3,0x6c,0x40,0x6e,0x4a,0x70,0x56,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,8,
-0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x61,0x14,0x75,0x6d,0x62,0x65,0x72,
-0xb3,0,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x80,0,
-0,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xf9,
-0,0,0x66,0xc0,0xc4,0x66,0xa2,0x47,0x69,0xa2,0x64,0x6c,0xa2,0x79,0x6d,0xa4,
-0xc0,4,0x61,0x6c,0x63,0xa5,0,0x65,0xa3,0x80,0x6e,0xa1,0x6f,0x15,0x64,0x69,
-0x66,0x69,0x65,0x72,1,0x6c,0x38,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,0xff,4,
-0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x41,1,0x72,0x3c,0x74,0x16,0x68,
-0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,1,0,0,0,0x10,0x6b,0xa5,0xc0,1,
-0x69,0x32,0x6f,0x13,0x72,0x6d,0x61,0x74,0xdb,0,0,0x1d,0x6e,0x61,0x6c,0x70,
-0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x20,0,0,0,0x10,
-0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,
-0x6f,0x6e,0xff,0x10,0,0,0,0x9c,7,0x6d,0x18,0x6d,0x41,0x6f,0x28,0x74,
-0x31,0x75,0x25,0x60,0x1c,0x77,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,
-0x65,0x72,0x29,0x63,0x3d,0x65,0x28,0x69,0x42,0x6c,0x29,0x13,0x74,0x74,0x65,0x72,
-0x9c,0x15,0x6e,0x75,0x6d,0x62,0x65,0x72,0xab,0,0x1a,0x6e,0x65,0x73,0x65,0x70,
-0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x20,0,0x63,0x46,0x64,0xa2,0x96,0x65,0x1b,
-0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa3,0x80,0xe6,0x80,
-1,7,0x6e,0x57,0x6e,0x52,0x6f,0x5e,0x73,0xe1,0,0,0x75,0x1b,0x72,0x72,
-0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,2,0,0,0,0x22,
-0x12,0x74,0x72,0x6c,0xd9,0x80,0,0xdc,0,0,1,0x6d,0x62,0x6e,1,0x6e,
-0x30,0x74,0x12,0x72,0x6f,0x6c,0xd9,0x80,0,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,
-0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x40,0,0,0x19,0x62,
-0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0xc0,0x61,0x58,0x63,0xd9,0x80,
-0,0x66,0xdb,0,0,0x6c,0x1d,0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,
-0x61,0x74,0x69,0x6f,0x6e,0xfd,0x20,0,0,0x18,0x73,0x65,0x64,0x6c,0x65,0x74,
-0x74,0x65,0x72,0x3d,2,0x61,0x32,0x65,0x50,0x69,0x12,0x67,0x69,0x74,0xa7,0,
-0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xe9,0,
-0,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62,0x65,0x72,0xa7,0
+0x69,0x6c,0x75,0x65,0xa3,0x8b,2,0x62,0x3c,0x67,0x4a,0x6e,0x17,0x64,0x69,0x6e,
+0x61,0x67,0x61,0x72,0x69,0xa5,0x26,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0xef,
+0x16,0x6d,0x75,0x6e,0x64,0x61,0x72,0x69,0xa5,0x47,0x67,0xc4,0x5d,0x6a,0xc1,0xe4,
+0x6a,0xa2,0xdf,0x6b,0xa2,0xf8,0x6c,4,0x61,0x54,0x65,0xa2,0x6b,0x69,0xa2,0x82,
+0x6f,0xa2,0xc1,0x79,1,0x63,0x2e,0x64,0x12,0x69,0x61,0x6e,0xa3,0xa9,0x12,0x69,
+0x61,0x6e,0xa3,0xa7,1,0x6f,0x55,0x74,0x11,0x69,0x6e,1,0x31,0x96,0x65,0x11,
+0x78,0x74,6,0x64,0x21,0x64,0xa3,0x95,0x65,0x2c,0x66,0xa5,0x39,0x67,0xa5,0x3a,
+0xa2,0xe7,0x13,0x6e,0x64,0x65,0x64,6,0x64,0xc,0x64,0xa3,0x95,0x65,0xa3,0xe7,
+0x66,0xa5,0x39,0x67,0xa5,0x3a,0x61,0x2a,0x62,0x29,0x63,0xa3,0x94,0x26,0x18,0x64,
+0x64,0x69,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x6d,0x24,0x12,0x73,0x75,0x70,0x24,0x16,
+0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x25,1,0x70,0x42,0x74,0x1d,0x74,0x65,0x72,
+0x6c,0x69,0x6b,0x65,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x79,0x12,0x63,0x68,0x61,
+0xa3,0x9c,2,0x6d,0x4e,0x6e,0x54,0x73,0x10,0x75,0xa2,0xb0,0x12,0x73,0x75,0x70,
+0xa4,0x31,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0x31,0x11,0x62,0x75,0xa3,
+0x6f,0x12,0x65,0x61,0x72,1,0x61,0xa3,0xe8,0x62,1,0x69,0x38,0x73,0x17,0x79,
+0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,0x75,0x17,0x64,0x65,0x6f,0x67,0x72,0x61,
+0x6d,0x73,0xa3,0x76,0x1a,0x77,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,
+0xa3,0x4d,0x10,0x61,1,0x6d,0x32,0x76,0x14,0x61,0x6e,0x65,0x73,0x65,0xa3,0xb5,
+0x10,0x6f,0x5c,0x12,0x65,0x78,0x74,1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,1,0x61,
+0xa2,0x43,0x68,4,0x61,0x40,0x69,0x50,0x6d,0x6e,0x6f,0x86,0x75,0x15,0x64,0x61,
+0x77,0x61,0x64,0x69,0xa3,0xe6,0x16,0x72,0x6f,0x73,0x68,0x74,0x68,0x69,0xa3,0x89,
+0x1d,0x74,0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74,0xa5,
+0x30,0x11,0x65,0x72,0x68,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x71,0x12,
+0x6a,0x6b,0x69,0xa3,0xe5,5,0x74,0x35,0x74,0x34,0x77,0x7a,0x79,0x13,0x61,0x68,
+0x6c,0x69,0xa3,0xa2,0x14,0x61,0x6b,0x61,0x6e,0x61,0x9e,1,0x65,0x4c,0x70,0x10,
+0x68,0x1f,0x6f,0x6e,0x65,0x74,0x69,0x63,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,
+0x6e,0x73,0xa3,0x6b,0x11,0x78,0x74,0xa3,0x6b,0x10,0x69,0xa5,0x46,0x69,0xa2,0x4e,
+0x6b,0xa2,0x51,0x6e,3,0x61,0x34,0x62,0x84,0x67,0x8a,0x6e,0x12,0x61,0x64,0x61,
+0x4d,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,0xcb,0x16,0x70,0x6c,0x65,0x6d,0x65,
+0x6e,0x74,0xa3,0xcb,0x11,0x78,0x74,2,0x61,0xa5,0x13,0x62,0xa5,0x38,0x65,0x13,
+0x6e,0x64,0x65,0x64,1,0x61,0xa5,0x13,0x62,0xa5,0x38,0x11,0x75,0x6e,0xa3,0x42,
+0x11,0x78,0x69,0x96,0x17,0x72,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x97,0x12,0x74,
+0x68,0x69,0xa3,0xc1,0x1c,0x74,0x6f,0x76,0x69,0x6b,0x6e,0x75,0x6d,0x65,0x72,0x61,
+0x6c,0x73,0xa5,0x45,0x67,0xa2,0xb5,0x68,0xa4,0x84,0x69,3,0x64,0x4c,0x6d,0xa2,
+0x55,0x6e,0xa2,0x62,0x70,0x13,0x61,0x65,0x78,0x74,0x2a,0x16,0x65,0x6e,0x73,0x69,
+0x6f,0x6e,0x73,0x2b,1,0x63,0x99,0x65,0x17,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,
+0x63,1,0x64,0x56,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa4,0xb,0x1d,0x61,
+0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xa5,0xb,0x13,
+0x65,0x73,0x63,0x72,0x1f,0x69,0x70,0x74,0x69,0x6f,0x6e,0x63,0x68,0x61,0x72,0x61,
+0x63,0x74,0x65,0x72,0x73,0x99,0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,
+0x6d,0x61,0x69,0x63,0xa3,0xba,1,0x64,0x62,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,
+0x69,0x6f,0x6e,0x61,0x6c,0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,
+0x6e,0xa3,0xbd,0x13,0x6c,0x61,0x76,0x69,0xa3,0xbe,0x11,0x69,0x63,1,0x6e,0x3e,
+0x73,0x1a,0x69,0x79,0x61,0x71,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa5,0x1e,0x19,
+0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2,4,0x65,0x74,0x6c,
+0xa2,0x82,0x6f,0xa2,0x9a,0x72,0xa2,0x9e,0x75,2,0x6a,0x34,0x6e,0x3e,0x72,0x14,
+0x6d,0x75,0x6b,0x68,0x69,0x43,0x14,0x61,0x72,0x61,0x74,0x69,0x45,0x18,0x6a,0x61,
+0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa5,0x1c,1,0x6e,0xa2,0x46,0x6f,1,0x6d,
+0x6e,0x72,0x13,0x67,0x69,0x61,0x6e,0x5a,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,
+0x87,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x87,0x11,0x78,0x74,0xa4,0x1b,
+0x14,0x65,0x6e,0x64,0x65,0x64,0xa5,0x1b,0x1a,0x65,0x74,0x72,0x69,0x63,0x73,0x68,
+0x61,0x70,0x65,0x73,0x8c,0x12,0x65,0x78,0x74,0xa2,0xe3,0x14,0x65,0x6e,0x64,0x65,
+0x64,0xa3,0xe3,0x1e,0x65,0x72,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,
+0x69,0x6f,0x6e,0x71,0x17,0x61,0x67,0x6f,0x6c,0x69,0x74,0x69,0x63,0xa2,0x88,0x12,
+0x73,0x75,0x70,0xa4,0xa,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa5,0xa,0x13,
+0x74,0x68,0x69,0x63,0xa3,0x59,1,0x61,0x5c,0x65,0x11,0x65,0x6b,0x30,1,0x61,
+0x38,0x65,0x11,0x78,0x74,0x6e,0x14,0x65,0x6e,0x64,0x65,0x64,0x6f,0x17,0x6e,0x64,
+0x63,0x6f,0x70,0x74,0x69,0x63,0x31,0x13,0x6e,0x74,0x68,0x61,0xa3,0xe4,2,0x61,
+0xa2,0x48,0x65,0xa2,0xdf,0x69,1,0x67,0x30,0x72,0x14,0x61,0x67,0x61,0x6e,0x61,
+0x9d,0x10,0x68,1,0x70,0x3a,0x73,0x18,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,
+0x73,0xa3,0x4b,1,0x72,0x3c,0x75,0x19,0x73,0x75,0x72,0x72,0x6f,0x67,0x61,0x74,
+0x65,0x73,0xa3,0x4c,0x11,0x69,0x76,0x1f,0x61,0x74,0x65,0x75,0x73,0x65,0x73,0x75,
+0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x73,0xa3,0x4c,2,0x6c,0x32,0x6e,0x9a,0x74,
+0x12,0x72,0x61,0x6e,0xa5,2,0x10,0x66,2,0x61,0x58,0x6d,0x70,0x77,0x14,0x69,
+0x64,0x74,0x68,0x61,0x1f,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,
+0x66,0x6f,0x72,0x6d,0x73,0xa3,0x57,0x1a,0x6e,0x64,0x66,0x75,0x6c,0x6c,0x66,0x6f,
+0x72,0x6d,0x73,0xa3,0x57,0x13,0x61,0x72,0x6b,0x73,0xa3,0x52,2,0x67,0x34,0x69,
+0xa2,0x45,0x75,0x12,0x6e,0x6f,0x6f,0xa3,0x63,0x11,0x75,0x6c,0xa2,0x4a,2,0x63,
+0x3c,0x6a,0x5e,0x73,0x17,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x73,0xa3,0x4a,0x1f,
+0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x6a,0x61,0x6d,0x6f,
+0xa3,0x41,0x12,0x61,0x6d,0x6f,0x5c,0x17,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,
+1,0x61,0xa3,0xb4,0x62,0xa3,0xb9,0x19,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,
+0x79,0x61,0xa5,0x1d,0x13,0x62,0x72,0x65,0x77,0x37,0x61,0xa4,0xc,0x62,0xa6,0x59,
+0x63,0xa8,0x2e,0x64,0xac,0xe3,0x65,5,0x6d,0xa9,0x6d,0x94,0x6e,0xa2,0x41,0x74,
+0x15,0x68,0x69,0x6f,0x70,0x69,0x63,0x5e,1,0x65,0x40,0x73,0x11,0x75,0x70,0xa2,
+0x86,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x86,0x11,0x78,0x74,0xa2,0x85,
+2,0x61,0xa3,0xc8,0x62,0xa5,0x37,0x65,0x13,0x6e,0x64,0x65,0x64,0xa2,0x85,1,
+0x61,0xa3,0xc8,0x62,0xa5,0x37,0x16,0x6f,0x74,0x69,0x63,0x6f,0x6e,0x73,0xa3,0xce,
+0x15,0x63,0x6c,0x6f,0x73,0x65,0x64,2,0x61,0x5a,0x63,0x9e,0x69,0x1c,0x64,0x65,
+0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x73,0x75,0x70,0xa2,0xc4,0x16,0x70,0x6c,
+0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc4,0x16,0x6c,0x70,0x68,0x61,0x6e,0x75,0x6d,0x86,
+1,0x65,0x2c,0x73,0x11,0x75,0x70,0xa3,0xc3,0x13,0x72,0x69,0x63,0x73,0x86,0x18,
+0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xc3,0x11,0x6a,0x6b,0xa2,0x44,
+0x1f,0x6c,0x65,0x74,0x74,0x65,0x72,0x73,0x61,0x6e,0x64,0x6d,0x6f,0x6e,0x74,0x68,
+0x73,0xa3,0x44,0x61,0x4a,0x67,0x76,0x6c,1,0x62,0x30,0x79,0x13,0x6d,0x61,0x69,
+0x63,0xa5,0x25,0x13,0x61,0x73,0x61,0x6e,0xa3,0xe2,0x13,0x72,0x6c,0x79,0x64,0x1f,
+0x79,0x6e,0x61,0x73,0x74,0x69,0x63,0x63,0x75,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,
+0xa5,1,0x1f,0x79,0x70,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,
+0x79,0x70,0x68,1,0x66,0x26,0x73,0xa3,0xc2,0x1c,0x6f,0x72,0x6d,0x61,0x74,0x63,
+0x6f,0x6e,0x74,0x72,0x6f,0x6c,0x73,0xa5,0x24,7,0x6e,0xc0,0xf2,0x6e,0x3e,0x72,
+0xa2,0x5d,0x73,0xa2,0xe5,0x76,0x14,0x65,0x73,0x74,0x61,0x6e,0xa3,0xbc,1,0x61,
+0x92,0x63,0x13,0x69,0x65,0x6e,0x74,1,0x67,0x34,0x73,0x15,0x79,0x6d,0x62,0x6f,
+0x6c,0x73,0xa3,0xa5,0x13,0x72,0x65,0x65,0x6b,1,0x6d,0x34,0x6e,0x15,0x75,0x6d,
+0x62,0x65,0x72,0x73,0xa3,0x7f,0x13,0x75,0x73,0x69,0x63,0xa2,0x7e,0x19,0x61,0x6c,
+0x6e,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0xa3,0x7e,0x10,0x74,0x1f,0x6f,0x6c,0x69,
+0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0xfe,2,
+0x61,0x32,0x6d,0xa2,0x7e,0x72,0x12,0x6f,0x77,0x73,0x7d,0x12,0x62,0x69,0x63,0x38,
+3,0x65,0x4a,0x6d,0x80,0x70,0xa2,0x50,0x73,0x11,0x75,0x70,0xa2,0x80,0x16,0x70,
+0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x80,0x11,0x78,0x74,3,0x61,0xa3,0xd2,0x62,
+0xa5,0x35,0x63,0xa5,0x41,0x65,0x13,0x6e,0x64,0x65,0x64,2,0x61,0xa3,0xd2,0x62,
+0xa5,0x35,0x63,0xa5,0x41,0x12,0x61,0x74,0x68,0xa2,0xd3,0x18,0x65,0x6d,0x61,0x74,
+0x69,0x63,0x61,0x6c,0x61,0x1f,0x6c,0x70,0x68,0x61,0x62,0x65,0x74,0x69,0x63,0x73,
+0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd3,1,0x66,0x42,0x72,0x1e,0x65,0x73,0x65,
+0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,1,0x61,0xa3,0x51,
+0x62,0xa3,0x55,0x14,0x65,0x6e,0x69,0x61,0x6e,0x35,0x12,0x63,0x69,0x69,0x23,0x64,
+0x9e,0x65,0xa2,0x42,0x68,0xa2,0x4d,0x6c,1,0x63,0x62,0x70,0x17,0x68,0x61,0x62,
+0x65,0x74,0x69,0x63,0x70,1,0x66,0xa3,0x50,0x72,0x1e,0x65,0x73,0x65,0x6e,0x74,
+0x61,0x74,0x69,0x6f,0x6e,0x66,0x6f,0x72,0x6d,0x73,0xa3,0x50,0x16,0x68,0x65,0x6d,
+0x69,0x63,0x61,0x6c,0xa2,0xd0,0x16,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0xd0,
+0x12,0x6c,0x61,0x6d,0xa5,7,0x1a,0x67,0x65,0x61,0x6e,0x6e,0x75,0x6d,0x62,0x65,
+0x72,0x73,0xa3,0x77,0x11,0x6f,0x6d,0xa3,0xfd,7,0x6f,0x71,0x6f,0x64,0x72,0xa2,
+0x41,0x75,0xa2,0x58,0x79,0x1b,0x7a,0x61,0x6e,0x74,0x69,0x6e,0x65,0x6d,0x75,0x73,
+0x69,0x63,0xa2,0x5b,0x18,0x61,0x6c,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0xa3,0x5b,
+1,0x70,0x34,0x78,0x16,0x64,0x72,0x61,0x77,0x69,0x6e,0x67,0x89,0x14,0x6f,0x6d,
+0x6f,0x66,0x6f,0xa0,0x12,0x65,0x78,0x74,0xa2,0x43,0x14,0x65,0x6e,0x64,0x65,0x64,
+0xa3,0x43,0x10,0x61,1,0x68,0x40,0x69,0x12,0x6c,0x6c,0x65,0x92,0x17,0x70,0x61,
+0x74,0x74,0x65,0x72,0x6e,0x73,0x93,0x11,0x6d,0x69,0xa3,0xc9,1,0x67,0x2c,0x68,
+0x11,0x69,0x64,0xa3,0x64,0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x81,0x61,0x48,0x65,
+0xa2,0x4e,0x68,0xa2,0x52,0x6c,0x1a,0x6f,0x63,0x6b,0x65,0x6c,0x65,0x6d,0x65,0x6e,
+0x74,0x73,0x8b,3,0x6c,0x34,0x6d,0x40,0x73,0x66,0x74,0x11,0x61,0x6b,0xa3,0xc7,
+0x14,0x69,0x6e,0x65,0x73,0x65,0xa3,0x93,0x11,0x75,0x6d,0xa2,0xb1,0x12,0x73,0x75,
+0x70,0xa2,0xca,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xca,1,0x69,0x30,
+0x73,0x13,0x61,0x76,0x61,0x68,0xa3,0xdd,0x15,0x63,0x6c,0x61,0x74,0x69,0x6e,0x23,
+0x14,0x6e,0x67,0x61,0x6c,0x69,0x41,0x16,0x61,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa5,
+8,5,0x6f,0xc1,0x60,0x6f,0xa2,0x69,0x75,0xa4,0x24,0x79,1,0x70,0xa2,0x44,
+0x72,0x14,0x69,0x6c,0x6c,0x69,0x63,0x32,1,0x65,0x4c,0x73,0x11,0x75,0x70,0xa2,
+0x61,0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa2,0x61,0x12,0x61,0x72,0x79,0xa3,
+0x61,0x11,0x78,0x74,4,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5,9,0x64,0xa5,
+0x43,0x65,0x13,0x6e,0x64,0x65,0x64,3,0x61,0xa3,0x9e,0x62,0xa3,0xa0,0x63,0xa5,
+9,0x64,0xa5,0x43,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e,0x6f,0x61,
+0x6e,0xa5,0x36,0x1a,0x6f,0x74,0x73,0x79,0x6c,0x6c,0x61,0x62,0x61,0x72,0x79,0xa3,
+0x7b,3,0x6d,0x5a,0x6e,0xa2,0x95,0x70,0xa2,0xa0,0x75,0x17,0x6e,0x74,0x69,0x6e,
+0x67,0x72,0x6f,0x64,0xa2,0x9a,0x17,0x6e,0x75,0x6d,0x65,0x72,0x61,0x6c,0x73,0xa3,
+0x9a,2,0x62,0x3a,0x6d,0xa2,0x5f,0x70,0x15,0x61,0x74,0x6a,0x61,0x6d,0x6f,0xa3,
+0x41,0x14,0x69,0x6e,0x69,0x6e,0x67,2,0x64,0x46,0x68,0x9e,0x6d,0x1d,0x61,0x72,
+0x6b,0x73,0x66,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x1e,0x69,0x61,
+0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x6d,0x61,0x72,0x6b,0x73,0x2e,2,0x65,
+0x40,0x66,0xa6,0x4c,0x73,0x18,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,
+0x83,0x16,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0xa3,0xe0,0x17,0x61,0x6c,0x66,0x6d,
+0x61,0x72,0x6b,0x73,0xa3,0x52,0x11,0x6f,0x6e,0x1f,0x69,0x6e,0x64,0x69,0x63,0x6e,
+0x75,0x6d,0x62,0x65,0x72,0x66,0x6f,0x72,0x6d,0x73,0xa3,0xb2,0x1b,0x74,0x72,0x6f,
+0x6c,0x70,0x69,0x63,0x74,0x75,0x72,0x65,0x73,0x83,0x12,0x74,0x69,0x63,0xa2,0x84,
+0x1b,0x65,0x70,0x61,0x63,0x74,0x6e,0x75,0x6d,0x62,0x65,0x72,0x73,0xa3,0xdf,1,
+0x6e,0x3e,0x72,0x1b,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,
+0x75,0x15,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa2,0x98,0x16,0x6e,0x75,0x6d,0x62,0x65,
+0x72,0x73,0xa2,0x99,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,
+0x69,0x6f,0x6e,0xa3,0x99,0x61,0xa2,0xe4,0x68,0xa4,0xe,0x6a,0x10,0x6b,0xa2,0x47,
+4,0x63,0x8c,0x65,0xa2,0x80,0x72,0xa2,0x9b,0x73,0xa2,0xad,0x75,0x1f,0x6e,0x69,
+0x66,0x69,0x65,0x64,0x69,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,0xa2,0x47,
+0x18,0x65,0x78,0x74,0x65,0x6e,0x73,0x69,0x6f,0x6e,7,0x65,0x6b,0x65,0xa5,0,
+0x66,0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5,0x42,0x14,0x6f,0x6d,0x70,0x61,0x74,0xa2,
+0x45,1,0x66,0x96,0x69,1,0x62,0x44,0x64,0x17,0x65,0x6f,0x67,0x72,0x61,0x70,
+0x68,0x73,0xa2,0x4f,0x12,0x73,0x75,0x70,0xa3,0x5f,0x14,0x69,0x6c,0x69,0x74,0x79,
+0xa2,0x45,1,0x66,0x54,0x69,0x18,0x64,0x65,0x6f,0x67,0x72,0x61,0x70,0x68,0x73,
+0xa2,0x4f,0x19,0x73,0x75,0x70,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0x5f,0x13,
+0x6f,0x72,0x6d,0x73,0xa3,0x53,0x11,0x78,0x74,7,0x65,0xc,0x65,0xa5,0,0x66,
+0xa5,0x12,0x67,0xa5,0x2e,0x68,0xa5,0x42,0x61,0xa3,0x46,0x62,0xa3,0x5e,0x63,0xa3,
+0xc5,0x64,0xa3,0xd1,0x19,0x61,0x64,0x69,0x63,0x61,0x6c,0x73,0x73,0x75,0x70,0x94,
+0x16,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x95,1,0x74,0x50,0x79,0x14,0x6d,0x62,
+0x6f,0x6c,0x73,0x9a,0x1d,0x61,0x6e,0x64,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,
+0x69,0x6f,0x6e,0x9b,0x14,0x72,0x6f,0x6b,0x65,0x73,0xa3,0x82,2,0x6e,0x48,0x72,
+0x64,0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,
+0x6e,0xa3,0xde,0x1d,0x61,0x64,0x69,0x61,0x6e,0x73,0x79,0x6c,0x6c,0x61,0x62,0x69,
+0x63,0x73,0x63,0x12,0x69,0x61,0x6e,0xa3,0xa8,2,0x61,0x3a,0x65,0x4c,0x6f,0x16,
+0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa5,0x2d,1,0x6b,0x26,0x6d,0xa3,0xa4,0x11,
+0x6d,0x61,0xa3,0xd4,1,0x72,0x38,0x73,0x17,0x73,0x73,0x79,0x6d,0x62,0x6f,0x6c,
+0x73,0xa5,0x19,0x13,0x6f,0x6b,0x65,0x65,0x60,0x12,0x73,0x75,0x70,0xa2,0xff,0x16,
+0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0xa3,0xff,3,0x65,0x3e,0x69,0x8e,0x6f,0xa2,
+0x71,0x75,0x15,0x70,0x6c,0x6f,0x79,0x61,0x6e,0xa3,0xe1,1,0x73,0x60,0x76,0x16,
+0x61,0x6e,0x61,0x67,0x61,0x72,0x69,0x3e,0x12,0x65,0x78,0x74,0xa2,0xb3,1,0x61,
+0xa5,0x44,0x65,0x13,0x6e,0x64,0x65,0x64,0xa2,0xb3,0x10,0x61,0xa5,0x44,0x13,0x65,
+0x72,0x65,0x74,0xa3,0x5a,2,0x61,0x3a,0x6e,0x82,0x76,0x16,0x65,0x73,0x61,0x6b,
+0x75,0x72,0x75,0xa5,0x2f,0x18,0x63,0x72,0x69,0x74,0x69,0x63,0x61,0x6c,0x73,0x2e,
+2,0x65,0x30,0x66,0x36,0x73,0x11,0x75,0x70,0xa3,0x83,0x11,0x78,0x74,0xa3,0xe0,
+0x18,0x6f,0x72,0x73,0x79,0x6d,0x62,0x6f,0x6c,0x73,0x77,0x14,0x67,0x62,0x61,0x74,
+0x73,0x91,1,0x67,0x3e,0x6d,0x12,0x69,0x6e,0x6f,0xa2,0xab,0x14,0x74,0x69,0x6c,
+0x65,0x73,0xa3,0xab,0x11,0x72,0x61,0xa5,0x1a,8,0x6d,0x5f,0x6d,0x3a,0x6e,0x48,
+0x73,0x7a,0x76,0xa2,0x4b,0x77,0x12,0x69,0x64,0x65,0x43,0x11,0x65,0x64,0x32,0x12,
+0x69,0x61,0x6c,0x33,2,0x61,0x40,0x62,0x37,0x6f,1,0x62,0x28,0x6e,0x10,0x65,
+0x21,0x13,0x72,0x65,0x61,0x6b,0x37,0x10,0x72,0x34,0x12,0x72,0x6f,0x77,0x35,2,
+0x6d,0x38,0x71,0x46,0x75,1,0x62,0x3d,0x70,0x3e,0x11,0x65,0x72,0x3f,1,0x61,
+0x24,0x6c,0x39,0x11,0x6c,0x6c,0x39,1,0x72,0x3b,0x75,0x12,0x61,0x72,0x65,0x3b,
+0x12,0x65,0x72,0x74,0x40,0x13,0x69,0x63,0x61,0x6c,0x41,0x63,0x58,0x65,0x92,0x66,
+0x96,0x69,1,0x6e,0x36,0x73,0x10,0x6f,0x30,0x14,0x6c,0x61,0x74,0x65,0x64,0x31,
+0x11,0x69,0x74,0x2e,0x12,0x69,0x61,0x6c,0x2f,2,0x61,0x36,0x69,0x48,0x6f,0x10,
+0x6d,0x24,0x12,0x70,0x61,0x74,0x25,0x10,0x6e,0x22,0x15,0x6f,0x6e,0x69,0x63,0x61,
+0x6c,0x23,0x13,0x72,0x63,0x6c,0x65,0x27,0x11,0x6e,0x63,0x27,2,0x69,0x3a,0x6f,
+0x44,0x72,0x10,0x61,0x2c,0x14,0x63,0x74,0x69,0x6f,0x6e,0x2d,0x10,0x6e,0x28,0x11,
+0x61,0x6c,0x29,0x11,0x6e,0x74,0x2b,4,0x61,0x3a,0x66,0x4c,0x68,0x5e,0x6e,0x70,
+0x77,0x2a,0x12,0x69,0x64,0x65,0x2b,0x22,0x17,0x6d,0x62,0x69,0x67,0x75,0x6f,0x75,
+0x73,0x23,0x26,0x17,0x75,0x6c,0x6c,0x77,0x69,0x64,0x74,0x68,0x27,0x24,0x17,0x61,
+0x6c,0x66,0x77,0x69,0x64,0x74,0x68,0x25,0x20,1,0x61,0x30,0x65,0x14,0x75,0x74,
+0x72,0x61,0x6c,0x21,0x28,0x13,0x72,0x72,0x6f,0x77,0x29,0xd,0x6e,0xc0,0xfb,0x73,
+0x6d,0x73,0x3a,0x74,0x98,0x75,0xa2,0x49,0x7a,2,0x6c,0x3b,0x70,0x3d,0x73,0x39,
+5,0x6f,0x28,0x6f,0x57,0x70,0x34,0x75,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,
+0x45,0x11,0x61,0x63,1,0x65,0x32,0x69,0x15,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x31,
+0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x39,0x63,0x53,0x6b,0x55,0x6d,
+0x51,0x1d,0x69,0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,
+0x27,1,0x6e,0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,
+0x74,0x65,0x72,0x23,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x21,0x6e,0x8a,
+0x6f,0xa2,0x47,0x70,8,0x66,0x14,0x66,0x5b,0x69,0x59,0x6f,0x4f,0x72,0x24,0x73,
+0x49,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0x43,0x61,0x2c,0x63,0x4d,0x64,
+0x47,0x65,0x4b,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,
+0x61,0x74,0x6f,0x72,0x3d,2,0x64,0x33,0x6c,0x35,0x6f,0x36,0x1b,0x6e,0x73,0x70,
+0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2d,1,0x70,0x7c,0x74,0x12,0x68,
+0x65,0x72,3,0x6c,0x38,0x6e,0x42,0x70,0x4c,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,
+0x57,0x14,0x65,0x74,0x74,0x65,0x72,0x2b,0x14,0x75,0x6d,0x62,0x65,0x72,0x37,0x19,
+0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x1c,0x65,0x6e,0x70,0x75,
+0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,0x66,0x9e,0x66,0x88,0x69,0xa2,
+0x4b,0x6c,0xa2,0x5c,0x6d,4,0x61,0x60,0x63,0x31,0x65,0x2f,0x6e,0x2d,0x6f,0x15,
+0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x30,0x73,0x14,0x79,0x6d,0x62,0x6f,0x6c,
+0x55,0x14,0x65,0x74,0x74,0x65,0x72,0x29,0x17,0x74,0x68,0x73,0x79,0x6d,0x62,0x6f,
+0x6c,0x51,1,0x69,0x2e,0x6f,0x13,0x72,0x6d,0x61,0x74,0x41,0x1d,0x6e,0x61,0x6c,
+0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x5b,0x10,0x6e,0x1f,0x69,
+0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x59,
+6,0x6d,0x18,0x6d,0x29,0x6f,0x28,0x74,0x27,0x75,0x23,0x2a,0x1c,0x77,0x65,0x72,
+0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x25,0x65,0x28,0x69,0x3c,0x6c,
+0x25,0x19,0x74,0x74,0x65,0x72,0x6e,0x75,0x6d,0x62,0x65,0x72,0x35,0x1a,0x6e,0x65,
+0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0x3b,0x63,0x44,0x64,0xa2,0x60,0x65,
+0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x2f,6,0x6e,
+0x39,0x6e,0x46,0x6f,0x4e,0x73,0x45,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,
+0x79,0x6d,0x62,0x6f,0x6c,0x53,0x20,0x12,0x74,0x72,0x6c,0x3f,0x42,0x10,0x6e,1,
+0x6e,0x2c,0x74,0x12,0x72,0x6f,0x6c,0x3f,0x1f,0x65,0x63,0x74,0x6f,0x72,0x70,0x75,
+0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4d,0x63,0x3f,0x66,0x41,0x6c,0x1d,
+0x6f,0x73,0x65,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x4b,2,
+0x61,0x30,0x65,0x4a,0x69,0x12,0x67,0x69,0x74,0x33,0x1c,0x73,0x68,0x70,0x75,0x6e,
+0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x47,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,
+0x75,0x6d,0x62,0x65,0x72,0x33,0,0x13,0x6e,0xc1,0xf,0x74,0x76,0x74,0x4c,0x76,
+0x9a,0x77,0xa2,0x48,0x79,0xa2,0x49,0x7a,1,0x61,0x2c,0x68,0x12,0x61,0x69,0x6e,
+0x8b,0x11,0x69,0x6e,0x85,2,0x61,0x36,0x65,0x3c,0x68,0x14,0x69,0x6e,0x79,0x65,
+0x68,0xa3,0x66,1,0x68,0x71,0x77,0x73,1,0x68,0x28,0x74,0x10,0x68,0x77,0x16,
+0x6d,0x61,0x72,0x62,0x75,0x74,0x61,0x74,0x13,0x67,0x6f,0x61,0x6c,0x3d,0x1a,0x65,
+0x72,0x74,0x69,0x63,0x61,0x6c,0x74,0x61,0x69,0x6c,0xa3,0x67,0x11,0x61,0x77,0x79,
+1,0x65,0x32,0x75,0x11,0x64,0x68,0x80,0x11,0x68,0x65,0x83,0x10,0x68,0x7a,1,
+0x62,0x34,0x77,0x16,0x69,0x74,0x68,0x74,0x61,0x69,0x6c,0x7f,0x14,0x61,0x72,0x72,
+0x65,0x65,0x7d,0x6e,0xa2,0x4c,0x70,0xa2,0x69,0x71,0xa2,0x69,0x72,0xa2,0x6f,0x73,
+5,0x74,0x22,0x74,0x38,0x77,0x4c,0x79,0x16,0x72,0x69,0x61,0x63,0x77,0x61,0x77,
+0x6f,0x18,0x72,0x61,0x69,0x67,0x68,0x74,0x77,0x61,0x77,0xa3,0x55,0x15,0x61,0x73,
+0x68,0x6b,0x61,0x66,0x6d,0x61,0x2e,0x65,0x38,0x68,0x11,0x69,0x6e,0x6b,0x10,0x64,
+0x62,0x11,0x68,0x65,0x65,1,0x65,0x2e,0x6d,0x13,0x6b,0x61,0x74,0x68,0x69,0x10,
+0x6e,0x67,2,0x6f,0x2c,0x75,0x50,0x79,0x10,0x61,0x91,1,0x6a,0x28,0x6f,0x10,
+0x6e,0x55,0x1a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x67,0x72,0x6f,0x75,0x70,0x21,0x10,
+0x6e,0x57,0x10,0x65,0x59,0x10,0x61,1,0x66,0x5b,0x70,0x10,0x68,0x5d,1,0x65,
+0x38,0x6f,0x18,0x68,0x69,0x6e,0x67,0x79,0x61,0x79,0x65,0x68,0x93,1,0x68,0x5f,
+0x76,0x16,0x65,0x72,0x73,0x65,0x64,0x70,0x65,0x61,0x67,0xc1,0xc7,0x67,0xa4,0x52,
+0x68,0xa4,0x59,0x6b,0xa4,0x99,0x6c,0xa4,0xb2,0x6d,2,0x61,0x2e,0x65,0xa4,0x3e,
+0x69,0x10,0x6d,0x53,1,0x6c,0xa2,0xe7,0x6e,0x16,0x69,0x63,0x68,0x61,0x65,0x61,
+0x6e,0,0x12,0x6e,0x76,0x73,0x51,0x73,0x3e,0x74,0x5c,0x77,0xa0,0x79,0xa2,0x42,
+0x7a,0x13,0x61,0x79,0x69,0x6e,0xa3,0x54,0x10,0x61,1,0x64,0x2e,0x6d,0x12,0x65,
+0x6b,0x68,0xa3,0x4c,0x11,0x68,0x65,0xa3,0x4b,3,0x61,0x38,0x65,0x3c,0x68,0x4a,
+0x77,0x13,0x65,0x6e,0x74,0x79,0xa3,0x51,0x10,0x77,0xa3,0x4d,1,0x6e,0xa3,0x4e,
+0x74,0x10,0x68,0xa3,0x4f,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x50,0x11,0x61,0x77,
+0xa3,0x52,0x12,0x6f,0x64,0x68,0xa3,0x53,0x6e,0x3a,0x6f,0x40,0x70,0x46,0x71,0x4a,
+0x72,0x12,0x65,0x73,0x68,0xa3,0x4a,0x11,0x75,0x6e,0xa3,0x46,0x11,0x6e,0x65,0xa3,
+0x47,0x10,0x65,0xa3,0x48,0x12,0x6f,0x70,0x68,0xa3,0x49,0x67,0x33,0x67,0x38,0x68,
+0x40,0x6b,0x5e,0x6c,0x66,0x6d,0x11,0x65,0x6d,0xa3,0x45,0x13,0x69,0x6d,0x65,0x6c,
+0xa1,1,0x65,0x32,0x75,0x14,0x6e,0x64,0x72,0x65,0x64,0xa3,0x42,0x11,0x74,0x68,
+0xa3,0x41,0x12,0x61,0x70,0x68,0xa3,0x43,0x14,0x61,0x6d,0x65,0x64,0x68,0xa3,0x44,
+0x61,0x34,0x62,0x4a,0x64,0x50,0x66,0x12,0x69,0x76,0x65,0x9f,1,0x6c,0x2a,0x79,
+0x11,0x69,0x6e,0x97,0x12,0x65,0x70,0x68,0x95,0x12,0x65,0x74,0x68,0x99,1,0x61,
+0x30,0x68,0x14,0x61,0x6d,0x65,0x64,0x68,0x9d,0x13,0x6c,0x65,0x74,0x68,0x9b,0x15,
+0x61,0x79,0x61,0x6c,0x61,0x6d,6,0x6e,0x2c,0x6e,0x34,0x72,0x5e,0x73,0x62,0x74,
+0x11,0x74,0x61,0xa3,0x63,2,0x67,0x2e,0x6e,0x32,0x79,0x10,0x61,0xa3,0x60,0x10,
+0x61,0xa3,0x5d,1,0x61,0xa3,0x5e,0x6e,0x10,0x61,0xa3,0x5f,0x10,0x61,0xa3,0x61,
+0x11,0x73,0x61,0xa3,0x62,0x62,0x3c,0x6a,0x42,0x6c,0x10,0x6c,1,0x61,0xa3,0x5b,
+0x6c,0x10,0x61,0xa3,0x5c,0x11,0x68,0x61,0xa3,0x59,0x10,0x61,0xa3,0x5a,0x11,0x65,
+0x6d,0x51,0x10,0x61,1,0x66,0x37,0x6d,0x11,0x61,0x6c,0x39,1,0x61,0x40,0x65,
+0x3e,1,0x68,0x28,0x74,0x10,0x68,0x45,0x40,0x13,0x67,0x6f,0x61,0x6c,0x43,2,
+0x68,0x3b,0x6d,0x5c,0x6e,0x1a,0x69,0x66,0x69,0x72,0x6f,0x68,0x69,0x6e,0x67,0x79,
+0x61,1,0x6b,0x2a,0x70,0x10,0x61,0xa3,0x65,0x15,0x69,0x6e,0x6e,0x61,0x79,0x61,
+0xa3,0x64,0x1a,0x7a,0x61,0x6f,0x6e,0x68,0x65,0x68,0x67,0x6f,0x61,0x6c,0x3d,2,
+0x61,0x3a,0x68,0x44,0x6e,0x17,0x6f,0x74,0x74,0x65,0x64,0x68,0x65,0x68,0x4b,1,
+0x66,0x47,0x70,0x10,0x68,0x49,0x12,0x61,0x70,0x68,0x89,0x11,0x61,0x6d,0x4c,0x12,
+0x61,0x64,0x68,0x4f,0x61,0x6e,0x62,0xa2,0x54,0x64,0xa2,0x70,0x65,0x31,0x66,2,
+0x61,0x3e,0x65,0x4a,0x69,0x19,0x6e,0x61,0x6c,0x73,0x65,0x6d,0x6b,0x61,0x74,0x68,
+0x35,0x15,0x72,0x73,0x69,0x79,0x65,0x68,0x8f,0x86,0x10,0x68,0x33,2,0x66,0x3c,
+0x69,0x70,0x6c,1,0x61,0x28,0x65,0x10,0x66,0x27,0x11,0x70,0x68,0x25,0x14,0x72,
+0x69,0x63,0x61,0x6e,2,0x66,0x30,0x6e,0x36,0x71,0x11,0x61,0x66,0xa3,0x58,0x11,
+0x65,0x68,0xa3,0x56,0x12,0x6f,0x6f,0x6e,0xa3,0x57,0x10,0x6e,0x23,1,0x65,0x4a,
+0x75,0x10,0x72,0x1f,0x75,0x73,0x68,0x61,0x73,0x6b,0x69,0x79,0x65,0x68,0x62,0x61,
+0x72,0x72,0x65,0x65,0x8d,1,0x68,0x29,0x74,0x10,0x68,0x2b,0x11,0x61,0x6c,0x2c,
+0x16,0x61,0x74,0x68,0x72,0x69,0x73,0x68,0x2f,7,0x6e,0x2e,0x6e,0x2c,0x72,0x3e,
+0x74,0x56,0x75,0x21,0x18,0x6f,0x6e,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x21,0x28,
+0x1a,0x69,0x67,0x68,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x29,0x2a,0x19,0x72,
+0x61,0x6e,0x73,0x70,0x61,0x72,0x65,0x6e,0x74,0x2b,0x63,0x23,0x64,0x40,0x6a,0x56,
+0x6c,0x26,0x19,0x65,0x66,0x74,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x27,0x24,0x19,
+0x75,0x61,0x6c,0x6a,0x6f,0x69,0x6e,0x69,0x6e,0x67,0x25,0x19,0x6f,0x69,0x6e,0x63,
+0x61,0x75,0x73,0x69,0x6e,0x67,0x23,0,0x13,0x6e,0xc0,0xd0,0x73,0x49,0x73,0x48,
+0x75,0x78,0x77,0x84,0x78,0x9c,0x7a,0x10,0x77,0x58,1,0x6a,0x75,0x73,0x13,0x70,
+0x61,0x63,0x65,0x59,4,0x61,0x51,0x67,0x53,0x70,0x28,0x75,0x30,0x79,0x57,0x54,
+0x12,0x61,0x63,0x65,0x55,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0x53,0x15,0x6e,
+0x6b,0x6e,0x6f,0x77,0x6e,0x21,1,0x6a,0x5d,0x6f,0x17,0x72,0x64,0x6a,0x6f,0x69,
+0x6e,0x65,0x72,0x5d,0x10,0x78,0x21,0x6e,0x60,0x6f,0xa2,0x41,0x70,0xa2,0x50,0x71,
+0xa2,0x6e,0x72,1,0x65,0x24,0x69,0x6f,0x1e,0x67,0x69,0x6f,0x6e,0x61,0x6c,0x69,
+0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x6f,4,0x65,0x3e,0x6c,0x5b,0x6f,0x46,
+0x73,0x45,0x75,0x46,0x14,0x6d,0x65,0x72,0x69,0x63,0x47,0x15,0x78,0x74,0x6c,0x69,
+0x6e,0x65,0x5b,0x17,0x6e,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x45,0x10,0x70,0x48,
+0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0x49,1,
+0x6f,0x3e,0x72,0x4c,0x1a,0x65,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,
+0x4d,0x4a,0x1b,0x73,0x74,0x66,0x69,0x78,0x6e,0x75,0x6d,0x65,0x72,0x69,0x63,0x4b,
+0x10,0x75,0x4e,0x16,0x6f,0x74,0x61,0x74,0x69,0x6f,0x6e,0x4f,0x68,0x7b,0x68,0x50,
+0x69,0x86,0x6a,0xa2,0x61,0x6c,0xa2,0x65,0x6d,0x1c,0x61,0x6e,0x64,0x61,0x74,0x6f,
+0x72,0x79,0x62,0x72,0x65,0x61,0x6b,0x2d,4,0x32,0x5f,0x33,0x61,0x65,0x34,0x6c,
+0x6d,0x79,0x3a,0x13,0x70,0x68,0x65,0x6e,0x3b,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,
+0x74,0x74,0x65,0x72,0x6d,2,0x64,0x28,0x6e,0x3c,0x73,0x41,0x3c,0x18,0x65,0x6f,
+0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x3d,0x3e,1,0x66,0x3e,0x73,0x11,0x65,0x70,
+1,0x61,0x22,0x65,0x14,0x72,0x61,0x62,0x6c,0x65,0x3f,0x18,0x69,0x78,0x6e,0x75,
+0x6d,0x65,0x72,0x69,0x63,0x41,2,0x6c,0x63,0x74,0x65,0x76,0x67,1,0x66,0x43,
+0x69,0x15,0x6e,0x65,0x66,0x65,0x65,0x64,0x43,0x61,0x40,0x62,0x70,0x63,0xa2,0x55,
+0x65,0xa2,0xdb,0x67,0x10,0x6c,0x38,0x11,0x75,0x65,0x39,2,0x69,0x23,0x6c,0x34,
+0x6d,0x16,0x62,0x69,0x67,0x75,0x6f,0x75,0x73,0x23,0x24,0x17,0x70,0x68,0x61,0x62,
+0x65,0x74,0x69,0x63,0x25,4,0x32,0x27,0x61,0x29,0x62,0x2b,0x6b,0x2d,0x72,0x12,
+0x65,0x61,0x6b,2,0x61,0x36,0x62,0x3e,0x73,0x15,0x79,0x6d,0x62,0x6f,0x6c,0x73,
+0x57,0x13,0x66,0x74,0x65,0x72,0x29,1,0x65,0x2a,0x6f,0x11,0x74,0x68,0x27,0x13,
+0x66,0x6f,0x72,0x65,0x2b,7,0x6d,0x51,0x6d,0x33,0x6f,0x28,0x70,0x69,0x72,0x35,
+1,0x6d,0x76,0x6e,1,0x64,0x3c,0x74,0x1a,0x69,0x6e,0x67,0x65,0x6e,0x74,0x62,
+0x72,0x65,0x61,0x6b,0x2f,0x15,0x69,0x74,0x69,0x6f,0x6e,0x61,0x1f,0x6c,0x6a,0x61,
+0x70,0x61,0x6e,0x65,0x73,0x65,0x73,0x74,0x61,0x72,0x74,0x65,0x72,0x6b,1,0x62,
+0x3a,0x70,0x19,0x6c,0x65,0x78,0x63,0x6f,0x6e,0x74,0x65,0x78,0x74,0x51,0x18,0x69,
+0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x33,0x61,0x6a,0x62,0x2f,0x6a,0x6b,0x6c,
+0x30,0x13,0x6f,0x73,0x65,0x70,1,0x61,0x38,0x75,0x18,0x6e,0x63,0x74,0x75,0x61,
+0x74,0x69,0x6f,0x6e,0x31,0x18,0x72,0x65,0x6e,0x74,0x68,0x65,0x73,0x69,0x73,0x69,
+0x1b,0x72,0x72,0x69,0x61,0x67,0x65,0x72,0x65,0x74,0x75,0x72,0x6e,0x35,2,0x62,
+0x3e,0x6d,0x46,0x78,0x36,0x18,0x63,0x6c,0x61,0x6d,0x61,0x74,0x69,0x6f,0x6e,0x37,
+0x70,0x12,0x61,0x73,0x65,0x71,0x72,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x73,
+1,0x64,0x42,0x6e,1,0x6f,0x32,0x75,0x26,0x14,0x6d,0x65,0x72,0x69,0x63,0x27,
+0x11,0x6e,0x65,0x21,1,0x65,0x2e,0x69,0x24,0x12,0x67,0x69,0x74,0x25,0x22,0x14,
+0x63,0x69,0x6d,0x61,0x6c,0x23,0,0x18,0x6e,0xc4,0x6f,0x74,0xc1,0x91,0x77,0x96,
+0x77,0xa2,0x4c,0x78,0xa2,0x70,0x79,0xa2,0x7a,0x7a,6,0x73,0x1e,0x73,0x34,0x78,
+0x42,0x79,0x48,0x7a,0x11,0x7a,0x7a,0xa3,0x67,0x10,0x79,1,0x65,0xa3,0xae,0x6d,
+0xa3,0x81,0x11,0x78,0x78,0xa3,0x66,0x11,0x79,0x79,0x21,0x61,0x30,0x69,0x58,0x6d,
+0x11,0x74,0x68,0xa3,0x80,0x10,0x6e,1,0x61,0x26,0x62,0xa3,0xb1,0x1a,0x62,0x61,
+0x7a,0x61,0x72,0x73,0x71,0x75,0x61,0x72,0x65,0xa3,0xb1,0x11,0x6e,0x68,0x23,2,
+0x61,0x30,0x63,0x5a,0x6f,0x11,0x6c,0x65,0xa3,0x9b,1,0x6e,0x3c,0x72,0x10,0x61,
+0xa2,0x92,0x15,0x6e,0x67,0x63,0x69,0x74,0x69,0xa3,0x92,0x12,0x63,0x68,0x6f,0xa3,
+0xbc,0x11,0x68,0x6f,0xa3,0xbc,1,0x70,0x2c,0x73,0x11,0x75,0x78,0xa3,0x65,0x11,
+0x65,0x6f,0x9b,1,0x65,0x2c,0x69,0x72,0x11,0x69,0x69,0x73,0x11,0x7a,0x69,0xa2,
+0xc0,0x11,0x64,0x69,0xa3,0xc0,0x74,0x66,0x75,0xa2,0xde,0x76,1,0x61,0x48,0x69,
+1,0x73,0x38,0x74,0x10,0x68,0xa2,0xc5,0x13,0x6b,0x75,0x71,0x69,0xa3,0xc5,0x10,
+0x70,0xa3,0x64,0x10,0x69,0xa2,0x63,0x10,0x69,0xa3,0x63,7,0x68,0x3e,0x68,0x34,
+0x69,0x48,0x6e,0x86,0x6f,0x11,0x74,0x6f,0xa3,0xc4,0x10,0x61,1,0x61,0x24,0x69,
+0x6d,0x6a,0x11,0x6e,0x61,0x6b,2,0x62,0x3a,0x66,0x4a,0x72,0x10,0x68,0xa2,0x9e,
+0x12,0x75,0x74,0x61,0xa3,0x9e,1,0x65,0x24,0x74,0x6f,0x12,0x74,0x61,0x6e,0x6f,
+0x14,0x69,0x6e,0x61,0x67,0x68,0x99,0x11,0x73,0x61,0xa3,0xc3,0x61,0x36,0x65,0xa2,
+0x65,0x66,0xa2,0x71,0x67,0x11,0x6c,0x67,0x75,6,0x6c,0x28,0x6c,0x32,0x6d,0x38,
+0x6e,0x44,0x76,0x10,0x74,0xa3,0x7f,1,0x65,0x89,0x75,0x97,1,0x69,0x24,0x6c,
+0x67,0x10,0x6c,0x67,0x10,0x67,0xa2,0x9a,1,0x73,0x2a,0x75,0x10,0x74,0xa3,0x9a,
+0x10,0x61,0xa3,0xc3,0x67,0x36,0x69,0x52,0x6b,0x10,0x72,0xa2,0x99,0x10,0x69,0xa3,
+0x99,1,0x61,0x30,0x62,0x7a,0x13,0x61,0x6e,0x77,0x61,0x7b,0x12,0x6c,0x6f,0x67,
+0x75,2,0x6c,0x32,0x74,0x34,0x76,0x12,0x69,0x65,0x74,0xa3,0x7f,0x10,0x65,0x89,
+0x12,0x68,0x61,0x6d,0xa3,0x6a,1,0x6c,0x2a,0x6e,0x10,0x67,0xa3,0x62,0x10,0x75,
+0x68,0x11,0x67,0x75,0x69,0x11,0x6e,0x67,0x99,1,0x67,0x32,0x6e,0x14,0x6b,0x6e,
+0x6f,0x77,0x6e,0xa3,0x67,0x11,0x61,0x72,0x8a,0x13,0x69,0x74,0x69,0x63,0x8b,0x71,
+0xc1,0x13,0x71,0xa2,0xde,0x72,0xa2,0xe3,0x73,6,0x69,0x8a,0x69,0x72,0x6f,0xa2,
+0x4c,0x75,0xa2,0x75,0x79,1,0x6c,0x46,0x72,4,0x63,0x65,0x65,0xa3,0x5f,0x69,
+0x2c,0x6a,0xa3,0x60,0x6e,0xa3,0x61,0x11,0x61,0x63,0x65,0x10,0x6f,0x94,0x16,0x74,
+0x69,0x6e,0x61,0x67,0x72,0x69,0x95,2,0x64,0x3c,0x67,0x4c,0x6e,1,0x64,0xa3,
+0x91,0x68,0x62,0x12,0x61,0x6c,0x61,0x63,0x10,0x64,0xa2,0xa6,0x12,0x68,0x61,0x6d,
+0xa3,0xa6,0x17,0x6e,0x77,0x72,0x69,0x74,0x69,0x6e,0x67,0xa3,0x70,2,0x67,0x3a,
+0x72,0x52,0x79,0x10,0x6f,0xa2,0xb0,0x12,0x6d,0x62,0x6f,0xa3,0xb0,1,0x64,0x26,
+0x6f,0xa3,0xb8,0xa2,0xb7,0x12,0x69,0x61,0x6e,0xa3,0xb7,0x10,0x61,0xa2,0x98,0x16,
+0x73,0x6f,0x6d,0x70,0x65,0x6e,0x67,0xa3,0x98,0x11,0x6e,0x64,0xa2,0x71,0x14,0x61,
+0x6e,0x65,0x73,0x65,0xa3,0x71,0x61,0x5c,0x67,0xa2,0x43,0x68,1,0x61,0x2a,0x72,
+0x10,0x64,0xa3,0x97,2,0x72,0x28,0x76,0x30,0x77,0x87,0x12,0x61,0x64,0x61,0xa3,
+0x97,0x12,0x69,0x61,0x6e,0x87,2,0x6d,0x40,0x72,0x58,0x75,0x10,0x72,0xa2,0x6f,
+0x15,0x61,0x73,0x68,0x74,0x72,0x61,0xa3,0x6f,1,0x61,0x26,0x72,0xa3,0x7e,0x14,
+0x72,0x69,0x74,0x61,0x6e,0xa3,0x7e,1,0x61,0xa3,0x5e,0x62,0xa3,0x85,0x11,0x6e,
+0x77,0xa3,0x70,0x11,0x61,0x61,1,0x63,0x2f,0x69,0x23,3,0x65,0x3e,0x6a,0x48,
+0x6f,0x4e,0x75,0x10,0x6e,1,0x69,0x24,0x72,0x61,0x10,0x63,0x61,0x13,0x6a,0x61,
+0x6e,0x67,0xa3,0x6e,0x11,0x6e,0x67,0xa3,0x6e,1,0x68,0x2a,0x72,0x10,0x6f,0xa3,
+0x5d,0x10,0x67,0xa3,0xb6,0x6e,0xa2,0x83,0x6f,0xa4,1,0x70,5,0x6c,0x1e,0x6c,
+0x44,0x72,0x4a,0x73,0x1b,0x61,0x6c,0x74,0x65,0x72,0x70,0x61,0x68,0x6c,0x61,0x76,
+0x69,0xa3,0x7b,0x11,0x72,0x64,0xa3,0x5c,0x11,0x74,0x69,0xa3,0x7d,0x61,0x7c,0x65,
+0xa2,0x54,0x68,3,0x61,0x3e,0x6c,0x4e,0x6e,0x5e,0x6f,0x16,0x65,0x6e,0x69,0x63,
+0x69,0x61,0x6e,0xa3,0x5b,0x10,0x67,0xa2,0x5a,0x12,0x73,0x70,0x61,0xa3,0x5a,2,
+0x69,0xa3,0x7a,0x70,0xa3,0x7b,0x76,0xa3,0x7c,0x10,0x78,0xa3,0x5b,2,0x68,0x3e,
+0x6c,0x50,0x75,0x10,0x63,0xa2,0xa5,0x14,0x69,0x6e,0x68,0x61,0x75,0xa3,0xa5,0x17,
+0x61,0x77,0x68,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0x4b,0x10,0x6d,0xa2,0x90,0x14,0x79,
+0x72,0x65,0x6e,0x65,0xa3,0x90,0x11,0x72,0x6d,0xa3,0x59,6,0x6b,0x36,0x6b,0x56,
+0x73,0x6e,0x75,0x74,0x79,0x11,0x69,0x61,0x1f,0x6b,0x65,0x6e,0x67,0x70,0x75,0x61,
+0x63,0x68,0x75,0x65,0x68,0x6d,0x6f,0x6e,0x67,0xa3,0xba,1,0x67,0x2e,0x6f,0xa2,
+0x57,0x10,0x6f,0xa3,0x57,0x10,0x62,0xa3,0x84,0x11,0x68,0x75,0xa3,0x96,0x12,0x73,
+0x68,0x75,0xa3,0x96,0x61,0x42,0x62,0x9e,0x65,0x10,0x77,1,0x61,0xa3,0xaa,0x74,
+0x14,0x61,0x69,0x6c,0x75,0x65,0x97,3,0x62,0x32,0x67,0x40,0x6e,0x56,0x72,0x10,
+0x62,0xa3,0x8e,0x15,0x61,0x74,0x61,0x65,0x61,0x6e,0xa3,0x8f,0x10,0x6d,0xa2,0xc7,
+0x15,0x75,0x6e,0x64,0x61,0x72,0x69,0xa3,0xc7,0x10,0x64,0xa2,0xbb,0x16,0x69,0x6e,
+0x61,0x67,0x61,0x72,0x69,0xa3,0xbb,0x11,0x61,0x74,0xa3,0x8f,4,0x67,0x3c,0x6c,
+0x4e,0x72,0xa2,0x8e,0x73,0xa2,0x9c,0x75,0x11,0x67,0x72,0xa3,0xc2,1,0x61,0x2a,
+0x68,0x11,0x61,0x6d,0x5b,0x10,0x6d,0x5b,1,0x63,0xa2,0x6a,0x64,6,0x70,0x41,
+0x70,0x3a,0x73,0x58,0x74,0x86,0x75,0x14,0x79,0x67,0x68,0x75,0x72,0xa3,0xc2,0x11,
+0x65,0x72,1,0x6d,0x2c,0x73,0x12,0x69,0x61,0x6e,0x9b,0x11,0x69,0x63,0xa3,0x59,
+0x10,0x6f,1,0x67,0x3a,0x75,0x18,0x74,0x68,0x61,0x72,0x61,0x62,0x69,0x61,0x6e,
+0xa3,0x85,0x13,0x64,0x69,0x61,0x6e,0xa3,0xb8,0x14,0x75,0x72,0x6b,0x69,0x63,0xa3,
+0x58,0x68,0x42,0x69,0x54,0x6e,0x1a,0x6f,0x72,0x74,0x68,0x61,0x72,0x61,0x62,0x69,
+0x61,0x6e,0xa3,0x8e,0x17,0x75,0x6e,0x67,0x61,0x72,0x69,0x61,0x6e,0xa3,0x4c,0x14,
+0x74,0x61,0x6c,0x69,0x63,0x5d,1,0x68,0x26,0x6b,0xa3,0x6d,0x12,0x69,0x6b,0x69,
+0xa3,0x6d,2,0x69,0x2c,0x6b,0x30,0x79,0x10,0x61,0x5f,0x11,0x79,0x61,0x5f,0x10,
+0x68,0xa3,0x58,2,0x61,0x36,0x67,0x3c,0x6d,0x10,0x61,0x84,0x12,0x6e,0x79,0x61,
+0x85,0x11,0x67,0x65,0xa3,0xab,0x10,0x65,0xa3,0xab,0x68,0xc3,0x15,0x6b,0xc2,0x2c,
+0x6b,0xa4,0x17,0x6c,0xa4,0xba,0x6d,8,0x6f,0x46,0x6f,0x48,0x72,0x74,0x74,0x80,
+0x75,0x86,0x79,1,0x61,0x28,0x6d,0x10,0x72,0x59,0x13,0x6e,0x6d,0x61,0x72,0x59,
+2,0x64,0x2e,0x6e,0x32,0x6f,0x10,0x6e,0xa3,0x72,0x10,0x69,0xa3,0xa3,0x10,0x67,
+0x56,0x14,0x6f,0x6c,0x69,0x61,0x6e,0x57,0x10,0x6f,0xa2,0x95,0x10,0x6f,0xa3,0x95,
+0x11,0x65,0x69,0xa3,0x73,0x11,0x6c,0x74,0xa2,0xa4,0x12,0x61,0x6e,0x69,0xa3,0xa4,
+0x61,0x36,0x65,0xa2,0x67,0x69,0xa2,0xbd,0x6c,0x11,0x79,0x6d,0x55,6,0x6e,0x38,
+0x6e,0x32,0x72,0x5c,0x73,0x6c,0x79,0x10,0x61,0xa3,0x55,1,0x64,0x38,0x69,0xa2,
+0x79,0x15,0x63,0x68,0x61,0x65,0x61,0x6e,0xa3,0x79,0xa2,0x54,0x12,0x61,0x69,0x63,
+0xa3,0x54,0x10,0x63,0xa2,0xa9,0x12,0x68,0x65,0x6e,0xa3,0xa9,0x18,0x61,0x72,0x61,
+0x6d,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xaf,0x68,0x36,0x6b,0x4c,0x6c,0x15,0x61,0x79,
+0x61,0x6c,0x61,0x6d,0x55,1,0x61,0x26,0x6a,0xa3,0xa0,0x13,0x6a,0x61,0x6e,0x69,
+0xa3,0xa0,0x10,0x61,0xa2,0xb4,0x12,0x73,0x61,0x72,0xa3,0xb4,3,0x64,0x78,0x65,
+0x94,0x6e,0xa2,0x42,0x72,1,0x63,0xa3,0x8d,0x6f,0xa2,0x56,0x13,0x69,0x74,0x69,
+0x63,1,0x63,0x3c,0x68,0x19,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,
+0xa3,0x56,0x15,0x75,0x72,0x73,0x69,0x76,0x65,0xa3,0x8d,1,0x65,0x26,0x66,0xa3,
+0xb5,0x16,0x66,0x61,0x69,0x64,0x72,0x69,0x6e,0xa3,0xb5,0x17,0x74,0x65,0x69,0x6d,
+0x61,0x79,0x65,0x6b,0xa3,0x73,0x10,0x64,0xa2,0x8c,0x17,0x65,0x6b,0x69,0x6b,0x61,
+0x6b,0x75,0x69,0xa3,0x8c,0x11,0x61,0x6f,0xa3,0x5c,6,0x6e,0x1a,0x6e,0x34,0x6f,
+0x38,0x70,0x3e,0x74,0x11,0x68,0x69,0xa3,0x78,0x11,0x64,0x61,0x4b,0x11,0x72,0x65,
+0xa3,0x77,0x11,0x65,0x6c,0xa3,0x8a,0x61,0x32,0x68,0xa2,0x44,0x69,0x11,0x74,0x73,
+0xa3,0xbf,5,0x74,0x23,0x74,0x34,0x77,0x56,0x79,0x13,0x61,0x68,0x6c,0x69,0xa3,
+0x4f,0x14,0x61,0x6b,0x61,0x6e,0x61,0x4c,0x19,0x6f,0x72,0x68,0x69,0x72,0x61,0x67,
+0x61,0x6e,0x61,0x8d,0x10,0x69,0xa3,0xc6,0x69,0x38,0x6c,0x40,0x6e,1,0x61,0x4d,
+0x6e,0x12,0x61,0x64,0x61,0x4b,0x12,0x74,0x68,0x69,0xa3,0x78,0x10,0x69,0xa3,0x4f,
+4,0x61,0x40,0x69,0x52,0x6d,0x70,0x6f,0x7c,0x75,0x15,0x64,0x61,0x77,0x61,0x64,
+0x69,0xa3,0x91,0x10,0x72,0x92,0x15,0x6f,0x73,0x68,0x74,0x68,0x69,0x93,0x1d,0x74,
+0x61,0x6e,0x73,0x6d,0x61,0x6c,0x6c,0x73,0x63,0x72,0x69,0x70,0x74,0xa3,0xbf,1,
+0x65,0x24,0x72,0x4f,0x10,0x72,0x4f,0x10,0x6a,0xa2,0x9d,0x11,0x6b,0x69,0xa3,0x9d,
+4,0x61,0x5c,0x65,0x90,0x69,0xa0,0x6f,0xa2,0x5d,0x79,1,0x63,0x34,0x64,0x10,
+0x69,0xa2,0x6c,0x11,0x61,0x6e,0xa3,0x6c,0x10,0x69,0xa2,0x6b,0x11,0x61,0x6e,0xa3,
+0x6b,2,0x6e,0x42,0x6f,0x46,0x74,3,0x66,0xa3,0x50,0x67,0xa3,0x51,0x69,0x24,
+0x6e,0x53,0x10,0x6e,0x53,0x10,0x61,0xa3,0x6a,0x50,0x10,0x6f,0x51,0x11,0x70,0x63,
+0xa2,0x52,0x11,0x68,0x61,0xa3,0x52,2,0x6d,0x2e,0x6e,0x36,0x73,0x10,0x75,0xa3,
+0x83,0x10,0x62,0x80,0x10,0x75,0x81,2,0x61,0xa3,0x53,0x62,0x83,0x65,0x11,0x61,
+0x72,1,0x61,0xa3,0x53,0x62,0x83,0x11,0x6d,0x61,0xa3,0x8b,0x68,0x6e,0x69,0xa2,
+0x95,0x6a,2,0x61,0x30,0x70,0x52,0x75,0x11,0x72,0x63,0xa3,0x94,1,0x6d,0x38,
+0x76,0x10,0x61,0xa2,0x4e,0x13,0x6e,0x65,0x73,0x65,0xa3,0x4e,0x10,0x6f,0xa3,0xad,
+0x11,0x61,0x6e,0xa3,0x69,6,0x6c,0x1e,0x6c,0x34,0x6d,0x3a,0x72,0x48,0x75,0x11,
+0x6e,0x67,0xa3,0x4c,0x11,0x75,0x77,0xa3,0x9c,0x10,0x6e,1,0x67,0xa3,0x4b,0x70,
+0xa3,0xba,0x11,0x6b,0x74,0x8d,0x61,0x3c,0x65,0xa2,0x43,0x69,0x11,0x72,0x61,0x48,
+0x13,0x67,0x61,0x6e,0x61,0x49,1,0x6e,0x34,0x74,0x10,0x72,0xa2,0xa2,0x11,0x61,
+0x6e,0xa3,0xa2,0x42,6,0x6f,0xe,0x6f,0x77,0x73,0xa3,0x49,0x74,0xa3,0x4a,0x75,
+0x12,0x6e,0x6f,0x6f,0x77,0x62,0xa3,0xac,0x67,0x3e,0x69,0x42,0x19,0x66,0x69,0x72,
+0x6f,0x68,0x69,0x6e,0x67,0x79,0x61,0xa3,0xb6,0x44,0x11,0x75,0x6c,0x45,0x11,0x62,
+0x72,0x46,0x11,0x65,0x77,0x47,2,0x6d,0x2e,0x6e,0x4a,0x74,0x11,0x61,0x6c,0x5d,
+0x1c,0x70,0x65,0x72,0x69,0x61,0x6c,0x61,0x72,0x61,0x6d,0x61,0x69,0x63,0xa3,0x74,
+2,0x64,0x66,0x68,0x6a,0x73,0x1b,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x61,
+0x6c,0x70,0x61,1,0x68,0x32,0x72,0x14,0x74,0x68,0x69,0x61,0x6e,0xa3,0x7d,0x13,
+0x6c,0x61,0x76,0x69,0xa3,0x7a,0x10,0x73,0xa3,0x4d,0x15,0x65,0x72,0x69,0x74,0x65,
+0x64,0x23,0x64,0xc1,0xd,0x64,0xa2,0x7a,0x65,0xa2,0xc1,0x67,4,0x65,0x82,0x6c,
+0x9a,0x6f,0xa2,0x46,0x72,0xa2,0x55,0x75,2,0x6a,0x3c,0x6e,0x4e,0x72,1,0x6d,
+0x24,0x75,0x41,0x13,0x75,0x6b,0x68,0x69,0x41,1,0x61,0x24,0x72,0x3f,0x13,0x72,
+0x61,0x74,0x69,0x3f,0x18,0x6a,0x61,0x6c,0x61,0x67,0x6f,0x6e,0x64,0x69,0xa3,0xb3,
+0x10,0x6f,1,0x6b,0xa3,0x48,0x72,0x38,0x13,0x67,0x69,0x61,0x6e,0x39,0x11,0x61,
+0x67,0x90,0x15,0x6f,0x6c,0x69,0x74,0x69,0x63,0x91,1,0x6e,0x30,0x74,0x10,0x68,
+0x3a,0x11,0x69,0x63,0x3b,1,0x67,0xa3,0xb3,0x6d,0xa3,0xaf,1,0x61,0x32,0x65,
+1,0x65,0x24,0x6b,0x3d,0x10,0x6b,0x3d,0x10,0x6e,0xa2,0x89,0x12,0x74,0x68,0x61,
+0xa3,0x89,4,0x65,0x46,0x69,0x6c,0x6f,0x8c,0x73,0x9a,0x75,0x11,0x70,0x6c,0xa2,
+0x87,0x13,0x6f,0x79,0x61,0x6e,0xa3,0x87,1,0x73,0x38,0x76,0x10,0x61,0x34,0x15,
+0x6e,0x61,0x67,0x61,0x72,0x69,0x35,0x13,0x65,0x72,0x65,0x74,0x33,1,0x61,0x36,
+0x76,0x16,0x65,0x73,0x61,0x6b,0x75,0x72,0x75,0xa3,0xbe,0x10,0x6b,0xa3,0xbe,0x11,
+0x67,0x72,0xa2,0xb2,0x10,0x61,0xa3,0xb2,0x11,0x72,0x74,0x33,2,0x67,0x3a,0x6c,
+0x72,0x74,0x11,0x68,0x69,0x36,0x13,0x6f,0x70,0x69,0x63,0x37,0x10,0x79,2,0x64,
+0xa3,0x45,0x68,0xa3,0x46,0x70,0xa2,0x47,0x1e,0x74,0x69,0x61,0x6e,0x68,0x69,0x65,
+0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,0xa3,0x47,1,0x62,0x36,0x79,0x10,0x6d,
+0xa2,0xb9,0x12,0x61,0x69,0x63,0xa3,0xb9,0x10,0x61,0xa2,0x88,0x12,0x73,0x61,0x6e,
+0xa3,0x88,0x61,0xa2,0xc9,0x62,0xa4,0x2e,0x63,6,0x6f,0x52,0x6f,0x76,0x70,0x92,
+0x75,0xa2,0x41,0x79,1,0x70,0x3e,0x72,2,0x69,0x2a,0x6c,0x31,0x73,0xa3,0x44,
+0x13,0x6c,0x6c,0x69,0x63,0x31,0x10,0x72,1,0x69,0x34,0x6f,0x15,0x6d,0x69,0x6e,
+0x6f,0x61,0x6e,0xa3,0xc1,0x11,0x6f,0x74,0x7f,1,0x6d,0x30,0x70,0x10,0x74,0x2e,
+0x11,0x69,0x63,0x2f,0x12,0x6d,0x6f,0x6e,0x21,1,0x6d,0x28,0x72,0x10,0x74,0x7f,
+0x10,0x6e,0xa3,0xc1,0x16,0x6e,0x65,0x69,0x66,0x6f,0x72,0x6d,0xa3,0x65,0x61,0x32,
+0x68,0xa2,0x41,0x69,0x11,0x72,0x74,0xa3,0x43,3,0x6b,0x4c,0x6e,0x50,0x72,0x76,
+0x75,0x1d,0x63,0x61,0x73,0x69,0x61,0x6e,0x61,0x6c,0x62,0x61,0x6e,0x69,0x61,0x6e,
+0xa3,0x9f,0x10,0x6d,0xa3,0x76,1,0x61,0x24,0x73,0x71,0x1d,0x64,0x69,0x61,0x6e,
+0x61,0x62,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x71,0x10,0x69,0xa2,0x68,0x11,
+0x61,0x6e,0xa3,0x68,3,0x61,0x32,0x65,0x44,0x6f,0x52,0x72,0x10,0x73,0xa3,0xbd,
+1,0x6b,0x26,0x6d,0xa3,0x42,0x11,0x6d,0x61,0xa3,0x76,0x10,0x72,0x2c,0x13,0x6f,
+0x6b,0x65,0x65,0x2d,0x16,0x72,0x61,0x73,0x6d,0x69,0x61,0x6e,0xa3,0xbd,6,0x68,
+0x4a,0x68,0x48,0x6e,0x4e,0x72,0x76,0x76,1,0x65,0x2a,0x73,0x10,0x74,0xa3,0x75,
+0x13,0x73,0x74,0x61,0x6e,0xa3,0x75,0x11,0x6f,0x6d,0xa3,0xa1,0x11,0x61,0x74,0x1f,
+0x6f,0x6c,0x69,0x61,0x6e,0x68,0x69,0x65,0x72,0x6f,0x67,0x6c,0x79,0x70,0x68,0x73,
+0xa3,0x9c,1,0x61,0x3e,0x6d,2,0x65,0x2a,0x69,0xa3,0x74,0x6e,0x27,0x13,0x6e,
+0x69,0x61,0x6e,0x27,0x10,0x62,0x24,0x11,0x69,0x63,0x25,0x64,0x30,0x66,0x44,0x67,
+0x11,0x68,0x62,0xa3,0x9f,0x10,0x6c,1,0x61,0x26,0x6d,0xa3,0xa7,0x10,0x6d,0xa3,
+0xa7,0x11,0x61,0x6b,0xa3,0x93,6,0x6c,0x3c,0x6c,0x52,0x6f,0x56,0x72,0x66,0x75,
+1,0x67,0x30,0x68,1,0x64,0x79,0x69,0x10,0x64,0x79,0x10,0x69,0x8e,0x13,0x6e,
+0x65,0x73,0x65,0x8f,0x11,0x69,0x73,0xa1,0x11,0x70,0x6f,0x2a,0x13,0x6d,0x6f,0x66,
+0x6f,0x2b,0x10,0x61,1,0x68,0x2e,0x69,0x7c,0x12,0x6c,0x6c,0x65,0x7d,0xa2,0x41,
+0x11,0x6d,0x69,0xa3,0x41,0x61,0x48,0x65,0x9c,0x68,1,0x61,0x2a,0x6b,0x10,0x73,
+0xa3,0xa8,0x15,0x69,0x6b,0x73,0x75,0x6b,0x69,0xa3,0xa8,3,0x6c,0x3a,0x6d,0x48,
+0x73,0x54,0x74,1,0x61,0x24,0x6b,0x9f,0x10,0x6b,0x9f,0x10,0x69,0x9c,0x13,0x6e,
+0x65,0x73,0x65,0x9d,0x10,0x75,0xa2,0x82,0x10,0x6d,0xa3,0x82,0x10,0x73,0xa2,0x86,
+0x13,0x61,0x76,0x61,0x68,0xa3,0x86,0x11,0x6e,0x67,0x28,0x12,0x61,0x6c,0x69,0x29,
+3,0x6c,0x42,0x6e,0x90,0x74,0xa2,0x46,0x76,0x24,0x17,0x6f,0x77,0x65,0x6c,0x6a,
+0x61,0x6d,0x6f,0x25,0x22,1,0x65,0x54,0x76,0x28,1,0x73,0x38,0x74,0x2a,0x17,
+0x73,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x2b,0x16,0x79,0x6c,0x6c,0x61,0x62,0x6c,
+0x65,0x29,0x18,0x61,0x64,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x23,1,0x61,0x21,
+0x6f,0x1a,0x74,0x61,0x70,0x70,0x6c,0x69,0x63,0x61,0x62,0x6c,0x65,0x21,0x26,0x1a,
+0x72,0x61,0x69,0x6c,0x69,0x6e,0x67,0x6a,0x61,0x6d,0x6f,0x27,1,0x6e,0x2c,0x79,
+0x22,0x11,0x65,0x73,0x23,0x20,0x10,0x6f,0x21,1,0x6e,0x2c,0x79,0x22,0x11,0x65,
+0x73,0x23,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e,0x3a,0x79,0x22,0x11,0x65,0x73,
+0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10,0x6f,0x21,2,0x6d,0x30,0x6e,
+0x3a,0x79,0x22,0x11,0x65,0x73,0x23,0x24,0x13,0x61,0x79,0x62,0x65,0x25,0x20,0x10,
+0x6f,0x21,0xb,0x72,0x39,0x76,0xc,0x76,0x33,0x78,0x2a,0x7a,0x11,0x77,0x6a,0x43,
+0x10,0x78,0x21,0x72,0x28,0x73,0x50,0x74,0x31,1,0x65,0x24,0x69,0x39,0x1e,0x67,
+0x69,0x6f,0x6e,0x61,0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x39,1,
+0x6d,0x35,0x70,0x18,0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0x35,0x6c,0x1f,
+0x6c,0x3c,0x6f,0x4a,0x70,1,0x70,0x37,0x72,0x14,0x65,0x70,0x65,0x6e,0x64,0x37,
+0x28,1,0x66,0x2b,0x76,0x2c,0x10,0x74,0x2f,0x13,0x74,0x68,0x65,0x72,0x21,0x63,
+0x4c,0x65,0x64,0x67,1,0x61,0x3a,0x6c,0x19,0x75,0x65,0x61,0x66,0x74,0x65,0x72,
+0x7a,0x77,0x6a,0x41,0x10,0x7a,0x41,2,0x6e,0x23,0x6f,0x24,0x72,0x25,0x14,0x6e,
+0x74,0x72,0x6f,0x6c,0x23,2,0x62,0x34,0x6d,0x4e,0x78,0x26,0x13,0x74,0x65,0x6e,
+0x64,0x27,0x3a,1,0x61,0x24,0x67,0x3d,0x11,0x73,0x65,0x3a,0x12,0x67,0x61,0x7a,
+0x3d,0x3e,0x16,0x6f,0x64,0x69,0x66,0x69,0x65,0x72,0x3f,9,0x6e,0x4a,0x6e,0x34,
+0x6f,0x44,0x73,0x60,0x75,0x94,0x78,0x10,0x78,0x21,0x10,0x75,0x2a,0x14,0x6d,0x65,
+0x72,0x69,0x63,0x2b,1,0x6c,0x2c,0x74,0x12,0x68,0x65,0x72,0x21,0x14,0x65,0x74,
+0x74,0x65,0x72,0x2d,3,0x63,0x36,0x65,0x46,0x70,0x31,0x74,0x32,0x12,0x65,0x72,
+0x6d,0x33,0x3c,0x16,0x6f,0x6e,0x74,0x69,0x6e,0x75,0x65,0x3d,0x2e,0x10,0x70,0x2f,
+0x10,0x70,0x34,0x12,0x70,0x65,0x72,0x35,0x61,0x46,0x63,0x52,0x65,0x64,0x66,0x72,
+0x6c,2,0x65,0x2d,0x66,0x3b,0x6f,0x28,0x12,0x77,0x65,0x72,0x29,0x10,0x74,0x22,
+0x12,0x65,0x72,0x6d,0x23,1,0x6c,0x24,0x72,0x37,0x24,0x12,0x6f,0x73,0x65,0x25,
+0x10,0x78,0x38,0x13,0x74,0x65,0x6e,0x64,0x39,0x10,0x6f,0x26,0x13,0x72,0x6d,0x61,
+0x74,0x27,0,0x10,0x6c,0x88,0x72,0x40,0x72,0x36,0x73,0x5e,0x77,0x7a,0x78,0x8a,
+0x7a,0x11,0x77,0x6a,0x4b,1,0x65,0x24,0x69,0x3b,0x1e,0x67,0x69,0x6f,0x6e,0x61,
+0x6c,0x69,0x6e,0x64,0x69,0x63,0x61,0x74,0x6f,0x72,0x3b,1,0x69,0x24,0x71,0x3f,
+0x18,0x6e,0x67,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x3f,0x17,0x73,0x65,0x67,0x73,
+0x70,0x61,0x63,0x65,0x4d,0x10,0x78,0x21,0x6c,0x36,0x6d,0x3c,0x6e,0x76,0x6f,0x13,
+0x74,0x68,0x65,0x72,0x21,1,0x65,0x23,0x66,0x35,3,0x62,0x37,0x69,0x28,0x6c,
+0x29,0x6e,0x2b,0x10,0x64,1,0x6c,0x34,0x6e,0x11,0x75,0x6d,0x2a,0x12,0x6c,0x65,
+0x74,0x37,0x14,0x65,0x74,0x74,0x65,0x72,0x29,2,0x65,0x36,0x6c,0x39,0x75,0x2c,
+0x14,0x6d,0x65,0x72,0x69,0x63,0x2d,0x14,0x77,0x6c,0x69,0x6e,0x65,0x39,0x66,0x3f,
+0x66,0x40,0x67,0x4e,0x68,0x70,0x6b,0x10,0x61,0x26,0x15,0x74,0x61,0x6b,0x61,0x6e,
+0x61,0x27,0x10,0x6f,0x24,0x13,0x72,0x6d,0x61,0x74,0x25,1,0x61,0x3a,0x6c,0x19,
+0x75,0x65,0x61,0x66,0x74,0x65,0x72,0x7a,0x77,0x6a,0x49,0x10,0x7a,0x49,1,0x65,
+0x24,0x6c,0x3d,0x19,0x62,0x72,0x65,0x77,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,0x61,
+0x86,0x63,0x92,0x64,0x94,0x65,2,0x62,0x44,0x6d,0x5e,0x78,0x2e,0x13,0x74,0x65,
+0x6e,0x64,0x32,0x15,0x6e,0x75,0x6d,0x6c,0x65,0x74,0x2f,0x42,1,0x61,0x24,0x67,
+0x45,0x11,0x73,0x65,0x42,0x12,0x67,0x61,0x7a,0x45,0x46,0x16,0x6f,0x64,0x69,0x66,
+0x69,0x65,0x72,0x47,0x15,0x6c,0x65,0x74,0x74,0x65,0x72,0x23,0x10,0x72,0x31,1,
+0x6f,0x24,0x71,0x41,0x18,0x75,0x62,0x6c,0x65,0x71,0x75,0x6f,0x74,0x65,0x41,2,
+0x63,0x32,0x6e,0x3c,0x6f,0x22,0x12,0x70,0x65,0x6e,0x23,0x24,0x13,0x6c,0x6f,0x73,
+0x65,0x25,0x20,0x12,0x6f,0x6e,0x65,0x21,6,0x6f,0x65,0x6f,0x4a,0x72,0x5c,0x74,
+0x64,0x76,0x1d,0x69,0x73,0x75,0x61,0x6c,0x6f,0x72,0x64,0x65,0x72,0x6c,0x65,0x66,
+0x74,0x3d,0x18,0x76,0x65,0x72,0x73,0x74,0x72,0x75,0x63,0x6b,0x2d,0x13,0x69,0x67,
+0x68,0x74,0x2f,0x11,0x6f,0x70,0x30,0x12,0x61,0x6e,0x64,2,0x62,0x32,0x6c,0x62,
+0x72,0x13,0x69,0x67,0x68,0x74,0x3b,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x32,0x12,0x61,
+0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x35,0x12,0x65,0x66,0x74,
+0x3f,0x12,0x65,0x66,0x74,0x36,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74,0x39,
+0x62,0x2c,0x6c,0x5c,0x6e,0x10,0x61,0x21,0x14,0x6f,0x74,0x74,0x6f,0x6d,0x22,0x12,
+0x61,0x6e,0x64,1,0x6c,0x2e,0x72,0x13,0x69,0x67,0x68,0x74,0x27,0x12,0x65,0x66,
+0x74,0x25,0x12,0x65,0x66,0x74,0x28,0x17,0x61,0x6e,0x64,0x72,0x69,0x67,0x68,0x74,
+0x2b,0xd,0x6e,0xaa,0x72,0x70,0x72,0x92,0x73,0xa2,0x46,0x74,0xa2,0x54,0x76,1,
+0x69,0x60,0x6f,0x12,0x77,0x65,0x6c,0x62,1,0x64,0x3a,0x69,0x19,0x6e,0x64,0x65,
+0x70,0x65,0x6e,0x64,0x65,0x6e,0x74,0x67,0x17,0x65,0x70,0x65,0x6e,0x64,0x65,0x6e,
+0x74,0x65,1,0x72,0x2e,0x73,0x13,0x61,0x72,0x67,0x61,0x61,0x12,0x61,0x6d,0x61,
+0x5f,0x1d,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x73,0x68,0x69,0x66,0x74,0x65,0x72,
+0x57,0x1e,0x79,0x6c,0x6c,0x61,0x62,0x6c,0x65,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,
+0x72,0x59,0x12,0x6f,0x6e,0x65,1,0x6c,0x2c,0x6d,0x12,0x61,0x72,0x6b,0x5d,0x14,
+0x65,0x74,0x74,0x65,0x72,0x5b,0x6e,0x3c,0x6f,0x7c,0x70,0x18,0x75,0x72,0x65,0x6b,
+0x69,0x6c,0x6c,0x65,0x72,0x55,1,0x6f,0x4c,0x75,1,0x6b,0x3c,0x6d,0x12,0x62,
+0x65,0x72,0x50,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x53,0x11,0x74,0x61,0x4f,0x16,
+0x6e,0x6a,0x6f,0x69,0x6e,0x65,0x72,0x4d,0x13,0x74,0x68,0x65,0x72,0x21,0x67,0x3e,
+0x67,0x4a,0x69,0x64,0x6a,0x82,0x6d,0x1d,0x6f,0x64,0x69,0x66,0x79,0x69,0x6e,0x67,
+0x6c,0x65,0x74,0x74,0x65,0x72,0x4b,0x1c,0x65,0x6d,0x69,0x6e,0x61,0x74,0x69,0x6f,
+0x6e,0x6d,0x61,0x72,0x6b,0x45,0x1e,0x6e,0x76,0x69,0x73,0x69,0x62,0x6c,0x65,0x73,
+0x74,0x61,0x63,0x6b,0x65,0x72,0x47,0x14,0x6f,0x69,0x6e,0x65,0x72,0x49,0x61,0xa2,
+0xba,0x62,0xa2,0xc0,0x63,1,0x61,0xa2,0xa2,0x6f,0x16,0x6e,0x73,0x6f,0x6e,0x61,
+0x6e,0x74,0x2a,8,0x6b,0x67,0x6b,0x48,0x6d,0x52,0x70,0x5c,0x73,0xa2,0x42,0x77,
+0x19,0x69,0x74,0x68,0x73,0x74,0x61,0x63,0x6b,0x65,0x72,0x43,0x14,0x69,0x6c,0x6c,
+0x65,0x72,0x35,0x14,0x65,0x64,0x69,0x61,0x6c,0x37,1,0x6c,0x52,0x72,0x10,0x65,
+1,0x63,0x2e,0x66,0x13,0x69,0x78,0x65,0x64,0x3d,0x19,0x65,0x64,0x69,0x6e,0x67,
+0x72,0x65,0x70,0x68,0x61,0x3b,0x18,0x61,0x63,0x65,0x68,0x6f,0x6c,0x64,0x65,0x72,
+0x39,0x10,0x75,1,0x62,0x3e,0x63,0x1b,0x63,0x65,0x65,0x64,0x69,0x6e,0x67,0x72,
+0x65,0x70,0x68,0x61,0x41,0x15,0x6a,0x6f,0x69,0x6e,0x65,0x64,0x3f,0x64,0x4c,0x66,
+0x52,0x68,0x5a,0x69,0x1e,0x6e,0x69,0x74,0x69,0x61,0x6c,0x70,0x6f,0x73,0x74,0x66,
+0x69,0x78,0x65,0x64,0x33,0x12,0x65,0x61,0x64,0x2d,0x13,0x69,0x6e,0x61,0x6c,0x2f,
+0x18,0x65,0x61,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,0x1d,0x6e,0x74,0x69,0x6c,
+0x6c,0x61,0x74,0x69,0x6f,0x6e,0x6d,0x61,0x72,0x6b,0x29,0x16,0x76,0x61,0x67,0x72,
+0x61,0x68,0x61,0x23,1,0x69,0x4a,0x72,0x10,0x61,0x1f,0x68,0x6d,0x69,0x6a,0x6f,
+0x69,0x6e,0x69,0x6e,0x67,0x6e,0x75,0x6d,0x62,0x65,0x72,0x27,0x12,0x6e,0x64,0x75,
+0x25,2,0x72,0x38,0x74,0x46,0x75,0x26,0x15,0x70,0x72,0x69,0x67,0x68,0x74,0x27,
+0x20,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x21,1,0x72,0x24,0x75,0x25,0x22,0x18,
+0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x65,0x64,1,0x72,0x32,0x75,0x15,0x70,0x72,
+0x69,0x67,0x68,0x74,0x25,0x15,0x6f,0x74,0x61,0x74,0x65,0x64,0x23,0xd,0x6e,0xc1,
+0x86,0x73,0xa8,0x73,0x4c,0x74,0xa2,0x76,0x75,0xa2,0x83,0x7a,0xd8,0x70,0,2,
+0x6c,0xd9,0x20,0,0x70,0xd9,0x40,0,0x73,0xc3,0,0xfe,0xf,0,0,0,
+7,0x6f,0x3c,0x6f,0xff,8,0,0,0,0x70,0x3a,0x75,0x6e,0x79,0x13,0x6d,
+0x62,0x6f,0x6c,0xff,0xf,0,0,0,0x11,0x61,0x63,1,0x65,0x34,0x69,0x15,
+0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0,0x18,0x73,0x65,0x70,0x61,0x72,0x61,0x74,
+0x6f,0x72,0xc3,0,0x16,0x72,0x72,0x6f,0x67,0x61,0x74,0x65,0xe1,0,0,0x63,
+0xff,2,0,0,0,0x65,0x38,0x6b,0xff,4,0,0,0,0x6d,0xff,1,
+0,0,0,0x16,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x70,0,0x1d,0x69,
+0x74,0x6c,0x65,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x31,1,0x6e,
+0x40,0x70,0x1c,0x70,0x65,0x72,0x63,0x61,0x73,0x65,0x6c,0x65,0x74,0x74,0x65,0x72,
+0x25,0x17,0x61,0x73,0x73,0x69,0x67,0x6e,0x65,0x64,0x23,0x6e,0xa2,0x69,0x6f,0xa2,
+0x89,0x70,0xfe,0x30,0xf8,0,0,9,0x69,0x33,0x69,0xff,0x10,0,0,0,
+0x6f,0xfd,0x80,0,0,0x72,0x54,0x73,0xf9,0,0,0x75,0x12,0x6e,0x63,0x74,
+0xfe,0x30,0xf8,0,0,0x15,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x30,0xf8,0,
+0,0x17,0x69,0x76,0x61,0x74,0x65,0x75,0x73,0x65,0xdd,0,0,0x61,0x48,0x63,
+0xfd,0x40,0,0,0x64,0xe9,0,0,0x65,0xfd,0x20,0,0,0x66,0xff,0x20,
+0,0,0,0x1f,0x72,0x61,0x67,0x72,0x61,0x70,0x68,0x73,0x65,0x70,0x61,0x72,
+0x61,0x74,0x6f,0x72,0xd9,0x40,0,0xbe,0,3,0x64,0xa7,0,0x6c,0xab,0,
+0x6f,0x30,0x75,0x13,0x6d,0x62,0x65,0x72,0xbf,0,0xb2,0,0x1b,0x6e,0x73,0x70,
+0x61,0x63,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa1,1,0x70,0x92,0x74,0x12,0x68,
+0x65,0x72,0xe6,0x80,1,3,0x6c,0x40,0x6e,0x4a,0x70,0x56,0x73,0x14,0x79,0x6d,
+0x62,0x6f,0x6c,0xff,8,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x61,0x14,
+0x75,0x6d,0x62,0x65,0x72,0xb3,0,0x19,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,
+0x6f,0x6e,0xfd,0x80,0,0,0x1c,0x65,0x6e,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,
+0x74,0x69,0x6f,0x6e,0xf9,0,0,0x66,0xc0,0xc4,0x66,0xa2,0x47,0x69,0xa2,0x64,
+0x6c,0xa2,0x79,0x6d,0xa4,0xc0,4,0x61,0x6c,0x63,0xa5,0,0x65,0xa3,0x80,0x6e,
+0xa1,0x6f,0x15,0x64,0x69,0x66,0x69,0x65,0x72,1,0x6c,0x38,0x73,0x14,0x79,0x6d,
+0x62,0x6f,0x6c,0xff,4,0,0,0,0x14,0x65,0x74,0x74,0x65,0x72,0x41,1,
+0x72,0x3c,0x74,0x16,0x68,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,1,0,0,0,
+0x10,0x6b,0xa5,0xc0,1,0x69,0x32,0x6f,0x13,0x72,0x6d,0x61,0x74,0xdb,0,0,
+0x1d,0x6e,0x61,0x6c,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,
+0x20,0,0,0,0x10,0x6e,0x1f,0x69,0x74,0x69,0x61,0x6c,0x70,0x75,0x6e,0x63,
+0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xff,0x10,0,0,0,0x9c,7,0x6d,0x18,
+0x6d,0x41,0x6f,0x28,0x74,0x31,0x75,0x25,0x60,0x1c,0x77,0x65,0x72,0x63,0x61,0x73,
+0x65,0x6c,0x65,0x74,0x74,0x65,0x72,0x29,0x63,0x3d,0x65,0x28,0x69,0x42,0x6c,0x29,
+0x13,0x74,0x74,0x65,0x72,0x9c,0x15,0x6e,0x75,0x6d,0x62,0x65,0x72,0xab,0,0x1a,
+0x6e,0x65,0x73,0x65,0x70,0x61,0x72,0x61,0x74,0x6f,0x72,0xd9,0x20,0,0x63,0x46,
+0x64,0xa2,0x96,0x65,0x1b,0x6e,0x63,0x6c,0x6f,0x73,0x69,0x6e,0x67,0x6d,0x61,0x72,
+0x6b,0xa3,0x80,0xe6,0x80,1,7,0x6e,0x57,0x6e,0x52,0x6f,0x5e,0x73,0xe1,0,
+0,0x75,0x1b,0x72,0x72,0x65,0x6e,0x63,0x79,0x73,0x79,0x6d,0x62,0x6f,0x6c,0xff,
+2,0,0,0,0x22,0x12,0x74,0x72,0x6c,0xd9,0x80,0,0xdc,0,0,1,
+0x6d,0x62,0x6e,1,0x6e,0x30,0x74,0x12,0x72,0x6f,0x6c,0xd9,0x80,0,0x1f,0x65,
+0x63,0x74,0x6f,0x72,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,
+0x40,0,0,0x19,0x62,0x69,0x6e,0x69,0x6e,0x67,0x6d,0x61,0x72,0x6b,0xa5,0xc0,
+0x61,0x58,0x63,0xd9,0x80,0,0x66,0xdb,0,0,0x6c,0x1d,0x6f,0x73,0x65,0x70,
+0x75,0x6e,0x63,0x74,0x75,0x61,0x74,0x69,0x6f,0x6e,0xfd,0x20,0,0,0x18,0x73,
+0x65,0x64,0x6c,0x65,0x74,0x74,0x65,0x72,0x3d,2,0x61,0x32,0x65,0x50,0x69,0x12,
+0x67,0x69,0x74,0xa7,0,0x1c,0x73,0x68,0x70,0x75,0x6e,0x63,0x74,0x75,0x61,0x74,
+0x69,0x6f,0x6e,0xe9,0,0,0x1a,0x63,0x69,0x6d,0x61,0x6c,0x6e,0x75,0x6d,0x62,
+0x65,0x72,0xa7,0
};
-const char PropNameData::nameGroups[22855]={
+const char PropNameData::nameGroups[23100]={
2,'A','l','p','h','a',0,'A','l','p','h','a','b','e','t','i','c',0,
4,'N',0,'N','o',0,'F',0,'F','a','l','s','e',0,4,'Y',0,'Y','e','s',0,'T',0,'T','r','u','e',0,
2,'N','R',0,'N','o','t','_','R','e','o','r','d','e','r','e','d',0,
@@ -1553,9 +1559,18 @@ const char PropNameData::nameGroups[22855]={
'r','i','g','i','n','a','l','_','S','y','l','l','a','b','i','c','s','_','E','x','t','e','n','d','e','d','_','A',0,
2,'V','i','t','h','k','u','q','i',0,'V','i','t','h','k','u','q','i',0,
2,'Z','n','a','m','e','n','n','y','_','M','u','s','i','c',0,'Z','n','a','m','e','n','n','y','_','M','u','s','i','c','a','l',
-'_','N','o','t','a','t','i','o','n',0,2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i','n','i',
-'n','g','_','C','l','a','s','s',0,2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p','e',0,
-3,'N','o','n','e',0,'N','o','n','e',0,'n','o','n','e',0,
+'_','N','o','t','a','t','i','o','n',0,2,'A','r','a','b','i','c','_','E','x','t','_','C',0,
+'A','r','a','b','i','c','_','E','x','t','e','n','d','e','d','_','C',0,
+2,'C','J','K','_','E','x','t','_','H',0,'C','J','K','_','U','n','i','f','i','e','d','_','I','d','e','o','g','r','a','p','h',
+'s','_','E','x','t','e','n','s','i','o','n','_','H',0,2,'C','y','r','i','l','l','i','c','_','E','x','t','_','D',0,
+'C','y','r','i','l','l','i','c','_','E','x','t','e','n','d','e','d','_','D',0,
+2,'D','e','v','a','n','a','g','a','r','i','_','E','x','t','_','A',0,'D','e','v','a','n','a','g','a','r','i','_','E','x','t',
+'e','n','d','e','d','_','A',0,2,'K','a','k','t','o','v','i','k','_','N','u','m','e','r','a','l','s',0,
+'K','a','k','t','o','v','i','k','_','N','u','m','e','r','a','l','s',0,
+2,'K','a','w','i',0,'K','a','w','i',0,2,'N','a','g','_','M','u','n','d','a','r','i',0,
+'N','a','g','_','M','u','n','d','a','r','i',0,2,'c','c','c',0,'C','a','n','o','n','i','c','a','l','_','C','o','m','b','i',
+'n','i','n','g','_','C','l','a','s','s',0,2,'d','t',0,'D','e','c','o','m','p','o','s','i','t','i','o','n','_','T','y','p',
+'e',0,3,'N','o','n','e',0,'N','o','n','e',0,'n','o','n','e',0,
3,'C','a','n',0,'C','a','n','o','n','i','c','a','l',0,'c','a','n',0,
3,'C','o','m',0,'C','o','m','p','a','t',0,'c','o','m',0,
3,'E','n','c',0,'C','i','r','c','l','e',0,'e','n','c',0,
@@ -1844,6 +1859,7 @@ const char PropNameData::nameGroups[22855]={
2,'Y','e','z','i',0,'Y','e','z','i','d','i',0,2,'C','p','m','n',0,'C','y','p','r','o','_','M','i','n','o','a','n',0,
2,'O','u','g','r',0,'O','l','d','_','U','y','g','h','u','r',0,
2,'T','n','s','a',0,'T','a','n','g','s','a',0,2,'V','i','t','h',0,'V','i','t','h','k','u','q','i',0,
+2,'N','a','g','m',0,'N','a','g','_','M','u','n','d','a','r','i',0,
2,'h','s','t',0,'H','a','n','g','u','l','_','S','y','l','l','a','b','l','e','_','T','y','p','e',0,
2,'N','A',0,'N','o','t','_','A','p','p','l','i','c','a','b','l','e',0,
2,'L',0,'L','e','a','d','i','n','g','_','J','a','m','o',0,
diff --git a/thirdparty/icu4c/common/propsvec.cpp b/thirdparty/icu4c/common/propsvec.cpp
index 056fcda9cf..e5caa4b9d2 100644
--- a/thirdparty/icu4c/common/propsvec.cpp
+++ b/thirdparty/icu4c/common/propsvec.cpp
@@ -351,7 +351,7 @@ upvec_compact(UPropsVectors *pv, UPVecCompactHandler *handler, void *context, UE
}
/* Set the flag now: Sorting and compacting destroys the builder data structure. */
- pv->isCompacted=TRUE;
+ pv->isCompacted=true;
rows=pv->rows;
columns=pv->columns;
@@ -360,7 +360,7 @@ upvec_compact(UPropsVectors *pv, UPVecCompactHandler *handler, void *context, UE
/* sort the properties vectors to find unique vector values */
uprv_sortArray(pv->v, rows, columns*4,
- upvec_compareRows, pv, FALSE, pErrorCode);
+ upvec_compareRows, pv, false, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
return;
}
@@ -503,7 +503,7 @@ upvec_compactToUTrie2Handler(void *context,
(void)columns;
UPVecToUTrie2Context *toUTrie2=(UPVecToUTrie2Context *)context;
if(start<UPVEC_FIRST_SPECIAL_CP) {
- utrie2_setRange32(toUTrie2->trie, start, end, (uint32_t)rowIndex, TRUE, pErrorCode);
+ utrie2_setRange32(toUTrie2->trie, start, end, (uint32_t)rowIndex, true, pErrorCode);
} else {
switch(start) {
case UPVEC_INITIAL_VALUE_CP:
diff --git a/thirdparty/icu4c/common/punycode.cpp b/thirdparty/icu4c/common/punycode.cpp
index 4832938ff7..f95722da27 100644
--- a/thirdparty/icu4c/common/punycode.cpp
+++ b/thirdparty/icu4c/common/punycode.cpp
@@ -573,7 +573,7 @@ u_strFromPunycode(const UChar *src, int32_t srcLength,
/* Case of last character determines uppercase flag: */
caseFlags[codeUnitIndex]=IS_BASIC_UPPERCASE(src[in-1]);
if(cpLength==2) {
- caseFlags[codeUnitIndex+1]=FALSE;
+ caseFlags[codeUnitIndex+1]=false;
}
}
}
diff --git a/thirdparty/icu4c/common/putil.cpp b/thirdparty/icu4c/common/putil.cpp
index 68be079b3a..f27c8737d2 100644
--- a/thirdparty/icu4c/common/putil.cpp
+++ b/thirdparty/icu4c/common/putil.cpp
@@ -244,7 +244,7 @@ u_signBit(double d) {
*/
UDate fakeClock_t0 = 0; /** Time to start the clock from **/
UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/
-UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/
+UBool fakeClock_set = false; /** True if fake clock has spun up **/
static UDate getUTCtime_real() {
struct timeval posixTime;
@@ -269,7 +269,7 @@ static UDate getUTCtime_fake() {
fprintf(stderr,"U_DEBUG_FAKETIME was set at compile time, but U_FAKETIME_START was not set.\n"
"Set U_FAKETIME_START to the number of milliseconds since 1/1/1970 to set the ICU clock.\n");
}
- fakeClock_set = TRUE;
+ fakeClock_set = true;
}
umtx_unlock(&fakeClockMutex);
@@ -905,7 +905,7 @@ static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFil
int32_t sizeFileRead;
int32_t sizeFileToRead;
char bufferFile[MAX_READ_SIZE];
- UBool result = TRUE;
+ UBool result = true;
if (tzInfo->defaultTZFilePtr == NULL) {
tzInfo->defaultTZFilePtr = fopen(defaultTZFileName, "r");
@@ -925,7 +925,7 @@ static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFil
sizeFileLeft = sizeFile;
if (sizeFile != tzInfo->defaultTZFileSize) {
- result = FALSE;
+ result = false;
} else {
/* Store the data from the files in separate buffers and
* compare each byte to determine equality.
@@ -942,7 +942,7 @@ static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFil
sizeFileRead = fread(bufferFile, 1, sizeFileToRead, file);
if (memcmp(tzInfo->defaultTZBuffer + tzInfo->defaultTZPosition, bufferFile, sizeFileRead) != 0) {
- result = FALSE;
+ result = false;
break;
}
sizeFileLeft -= sizeFileRead;
@@ -950,7 +950,7 @@ static UBool compareBinaryFiles(const char* defaultTZFileName, const char* TZFil
}
}
} else {
- result = FALSE;
+ result = false;
}
if (file != NULL) {
@@ -1189,7 +1189,7 @@ uprv_tzname(int n)
tzInfo->defaultTZBuffer = NULL;
tzInfo->defaultTZFileSize = 0;
tzInfo->defaultTZFilePtr = NULL;
- tzInfo->defaultTZstatus = FALSE;
+ tzInfo->defaultTZstatus = false;
tzInfo->defaultTZPosition = 0;
gTimeZoneBufferPtr = searchForTZFile(TZZONEINFO, tzInfo);
@@ -1260,10 +1260,10 @@ uprv_tzname(int n)
/* Get and set the ICU data directory --------------------------------------- */
-static icu::UInitOnce gDataDirInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gDataDirInitOnce {};
static char *gDataDirectory = NULL;
-UInitOnce gTimeZoneFilesInitOnce = U_INITONCE_INITIALIZER;
+UInitOnce gTimeZoneFilesInitOnce {};
static CharString *gTimeZoneFilesDirectory = NULL;
#if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
@@ -1295,7 +1295,7 @@ static UBool U_CALLCONV putil_cleanup(void)
gCorrectedPOSIXLocaleHeapAllocated = false;
}
#endif
- return TRUE;
+ return true;
}
/*
@@ -1344,16 +1344,16 @@ U_CAPI UBool U_EXPORT2
uprv_pathIsAbsolute(const char *path)
{
if(!path || !*path) {
- return FALSE;
+ return false;
}
if(*path == U_FILE_SEP_CHAR) {
- return TRUE;
+ return true;
}
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
if(*path == U_FILE_ALT_SEP_CHAR) {
- return TRUE;
+ return true;
}
#endif
@@ -1361,11 +1361,11 @@ uprv_pathIsAbsolute(const char *path)
if( (((path[0] >= 'A') && (path[0] <= 'Z')) ||
((path[0] >= 'a') && (path[0] <= 'z'))) &&
path[1] == ':' ) {
- return TRUE;
+ return true;
}
#endif
- return FALSE;
+ return false;
}
/* Backup setting of ICU_DATA_DIR_PREFIX_ENV_VAR
@@ -1402,12 +1402,12 @@ static BOOL U_CALLCONV getIcuDataDirectoryUnderWindowsDirectory(char* directoryB
if ((windowsPathUtf8Len + UPRV_LENGTHOF(ICU_DATA_DIR_WINDOWS)) < bufferLength) {
uprv_strcpy(directoryBuffer, windowsPathUtf8);
uprv_strcat(directoryBuffer, ICU_DATA_DIR_WINDOWS);
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
#endif
diff --git a/thirdparty/icu4c/common/rbbi.cpp b/thirdparty/icu4c/common/rbbi.cpp
index cae8d154b3..2769263894 100644
--- a/thirdparty/icu4c/common/rbbi.cpp
+++ b/thirdparty/icu4c/common/rbbi.cpp
@@ -39,7 +39,7 @@
#include "uvectr32.h"
#ifdef RBBI_DEBUG
-static UBool gTrace = FALSE;
+static UBool gTrace = false;
#endif
U_NAMESPACE_BEGIN
@@ -267,7 +267,7 @@ RuleBasedBreakIterator::operator=(const RuleBasedBreakIterator& that) {
}
// TODO: clone fLanguageBreakEngines from "that"
UErrorCode status = U_ZERO_ERROR;
- utext_clone(&fText, &that.fText, FALSE, TRUE, &status);
+ utext_clone(&fText, &that.fText, false, true, &status);
if (fCharIter != &fSCharIter) {
delete fCharIter;
@@ -354,13 +354,13 @@ void RuleBasedBreakIterator::init(UErrorCode &status) {
}
#ifdef RBBI_DEBUG
- static UBool debugInitDone = FALSE;
- if (debugInitDone == FALSE) {
+ static UBool debugInitDone = false;
+ if (debugInitDone == false) {
char *debugEnv = getenv("U_RBBIDEBUG");
if (debugEnv && uprv_strstr(debugEnv, "trace")) {
- gTrace = TRUE;
+ gTrace = true;
}
- debugInitDone = TRUE;
+ debugInitDone = true;
}
#endif
}
@@ -439,7 +439,7 @@ void RuleBasedBreakIterator::setText(UText *ut, UErrorCode &status) {
}
fBreakCache->reset();
fDictionaryCache->reset();
- utext_clone(&fText, ut, FALSE, TRUE, &status);
+ utext_clone(&fText, ut, false, true, &status);
// Set up a dummy CharacterIterator to be returned if anyone
// calls getText(). With input from UText, there is no reasonable
@@ -460,7 +460,7 @@ void RuleBasedBreakIterator::setText(UText *ut, UErrorCode &status) {
UText *RuleBasedBreakIterator::getUText(UText *fillIn, UErrorCode &status) const {
- UText *result = utext_clone(fillIn, &fText, FALSE, TRUE, &status);
+ UText *result = utext_clone(fillIn, &fText, false, true, &status);
return result;
}
@@ -548,7 +548,7 @@ RuleBasedBreakIterator &RuleBasedBreakIterator::refreshInputText(UText *input, U
}
int64_t pos = utext_getNativeIndex(&fText);
// Shallow read-only clone of the new UText into the existing input UText
- utext_clone(&fText, input, FALSE, TRUE, &status);
+ utext_clone(&fText, input, false, true, &status);
if (U_FAILURE(status)) {
return *this;
}
@@ -696,7 +696,7 @@ UBool RuleBasedBreakIterator::isBoundary(int32_t offset) {
// out-of-range indexes are never boundary positions
if (offset < 0) {
first(); // For side effects on current position, tag values.
- return FALSE;
+ return false;
}
// Adjust offset to be on a code point boundary and not beyond the end of the text.
@@ -713,9 +713,9 @@ UBool RuleBasedBreakIterator::isBoundary(int32_t offset) {
}
if (result && adjustedOffset < offset && utext_char32At(&fText, offset) == U_SENTINEL) {
- // Original offset is beyond the end of the text. Return FALSE, it's not a boundary,
+ // Original offset is beyond the end of the text. Return false, it's not a boundary,
// but the iteration position remains set to the end of the text, which is a boundary.
- return FALSE;
+ return false;
}
if (!result) {
// Not on a boundary. isBoundary() must leave iterator on the following boundary.
@@ -838,7 +838,7 @@ int32_t RuleBasedBreakIterator::handleNext() {
result = initialPosition;
c = UTEXT_NEXT32(&fText);
if (c==U_SENTINEL) {
- fDone = TRUE;
+ fDone = true;
return UBRK_DONE;
}
@@ -1153,8 +1153,8 @@ U_NAMESPACE_END
static icu::UStack *gLanguageBreakFactories = nullptr;
static const icu::UnicodeString *gEmptyString = nullptr;
-static icu::UInitOnce gLanguageBreakFactoriesInitOnce = U_INITONCE_INITIALIZER;
-static icu::UInitOnce gRBBIInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gLanguageBreakFactoriesInitOnce {};
+static icu::UInitOnce gRBBIInitOnce {};
/**
* Release all static memory held by breakiterator.
@@ -1167,7 +1167,7 @@ UBool U_CALLCONV rbbi_cleanup(void) {
gEmptyString = nullptr;
gLanguageBreakFactoriesInitOnce.reset();
gRBBIInitOnce.reset();
- return TRUE;
+ return true;
}
U_CDECL_END
diff --git a/thirdparty/icu4c/common/rbbi_cache.cpp b/thirdparty/icu4c/common/rbbi_cache.cpp
index 26d82df781..45e02528cf 100644
--- a/thirdparty/icu4c/common/rbbi_cache.cpp
+++ b/thirdparty/icu4c/common/rbbi_cache.cpp
@@ -45,7 +45,7 @@ void RuleBasedBreakIterator::DictionaryCache::reset() {
UBool RuleBasedBreakIterator::DictionaryCache::following(int32_t fromPos, int32_t *result, int32_t *statusIndex) {
if (fromPos >= fLimit || fromPos < fStart) {
fPositionInCache = -1;
- return FALSE;
+ return false;
}
// Sequential iteration, move from previous boundary to the following
@@ -55,13 +55,13 @@ UBool RuleBasedBreakIterator::DictionaryCache::following(int32_t fromPos, int32_
++fPositionInCache;
if (fPositionInCache >= fBreaks.size()) {
fPositionInCache = -1;
- return FALSE;
+ return false;
}
r = fBreaks.elementAti(fPositionInCache);
U_ASSERT(r > fromPos);
*result = r;
*statusIndex = fOtherRuleStatusIndex;
- return TRUE;
+ return true;
}
// Random indexing. Linear search for the boundary following the given position.
@@ -71,7 +71,7 @@ UBool RuleBasedBreakIterator::DictionaryCache::following(int32_t fromPos, int32_
if (r > fromPos) {
*result = r;
*statusIndex = fOtherRuleStatusIndex;
- return TRUE;
+ return true;
}
}
UPRV_UNREACHABLE_EXIT;
@@ -81,7 +81,7 @@ UBool RuleBasedBreakIterator::DictionaryCache::following(int32_t fromPos, int32_
UBool RuleBasedBreakIterator::DictionaryCache::preceding(int32_t fromPos, int32_t *result, int32_t *statusIndex) {
if (fromPos <= fStart || fromPos > fLimit) {
fPositionInCache = -1;
- return FALSE;
+ return false;
}
if (fromPos == fLimit) {
@@ -98,12 +98,12 @@ UBool RuleBasedBreakIterator::DictionaryCache::preceding(int32_t fromPos, int32_
U_ASSERT(r < fromPos);
*result = r;
*statusIndex = ( r== fStart) ? fFirstRuleStatusIndex : fOtherRuleStatusIndex;
- return TRUE;
+ return true;
}
if (fPositionInCache == 0) {
fPositionInCache = -1;
- return FALSE;
+ return false;
}
for (fPositionInCache = fBreaks.size()-1; fPositionInCache >= 0; --fPositionInCache) {
@@ -111,7 +111,7 @@ UBool RuleBasedBreakIterator::DictionaryCache::preceding(int32_t fromPos, int32_
if (r < fromPos) {
*result = r;
*statusIndex = ( r == fStart) ? fFirstRuleStatusIndex : fOtherRuleStatusIndex;
- return TRUE;
+ return true;
}
}
UPRV_UNREACHABLE_EXIT;
@@ -227,7 +227,7 @@ void RuleBasedBreakIterator::BreakCache::reset(int32_t pos, int32_t ruleStatus)
int32_t RuleBasedBreakIterator::BreakCache::current() {
fBI->fPosition = fTextIdx;
fBI->fRuleStatusIndex = fStatuses[fBufIdx];
- fBI->fDone = FALSE;
+ fBI->fDone = false;
return fTextIdx;
}
@@ -302,18 +302,18 @@ void RuleBasedBreakIterator::BreakCache::previous(UErrorCode &status) {
UBool RuleBasedBreakIterator::BreakCache::seek(int32_t pos) {
if (pos < fBoundaries[fStartBufIdx] || pos > fBoundaries[fEndBufIdx]) {
- return FALSE;
+ return false;
}
if (pos == fBoundaries[fStartBufIdx]) {
// Common case: seek(0), from BreakIterator::first()
fBufIdx = fStartBufIdx;
fTextIdx = fBoundaries[fBufIdx];
- return TRUE;
+ return true;
}
if (pos == fBoundaries[fEndBufIdx]) {
fBufIdx = fEndBufIdx;
fTextIdx = fBoundaries[fBufIdx];
- return TRUE;
+ return true;
}
int32_t min = fStartBufIdx;
@@ -331,51 +331,97 @@ UBool RuleBasedBreakIterator::BreakCache::seek(int32_t pos) {
fBufIdx = modChunkSize(max - 1);
fTextIdx = fBoundaries[fBufIdx];
U_ASSERT(fTextIdx <= pos);
- return TRUE;
+ return true;
}
UBool RuleBasedBreakIterator::BreakCache::populateNear(int32_t position, UErrorCode &status) {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
U_ASSERT(position < fBoundaries[fStartBufIdx] || position > fBoundaries[fEndBufIdx]);
- // Find a boundary somewhere in the vicinity of the requested position.
- // Depending on the safe rules and the text data, it could be either before, at, or after
- // the requested position.
-
+ // Add boundaries to the cache near the specified position.
+ // The given position need not be a boundary itself.
+ // The input position must be within the range of the text, and
+ // on a code point boundary.
+ // If the requested position is a break boundary, leave the iteration
+ // position on it.
+ // If the requested position is not a boundary, leave the iteration
+ // position on the preceding boundary and include both the
+ // preceding and following boundaries in the cache.
+ // Additional boundaries, either preceding or following, may be added
+ // to the cache as a side effect.
// If the requested position is not near already cached positions, clear the existing cache,
// find a near-by boundary and begin new cache contents there.
- if ((position < fBoundaries[fStartBufIdx] - 15) || position > (fBoundaries[fEndBufIdx] + 15)) {
- int32_t aBoundary = 0;
- int32_t ruleStatusIndex = 0;
- if (position > 20) {
- int32_t backupPos = fBI->handleSafePrevious(position);
-
- if (backupPos > 0) {
- // Advance to the boundary following the backup position.
- // There is a complication: the safe reverse rules identify pairs of code points
- // that are safe. If advancing from the safe point moves forwards by less than
- // two code points, we need to advance one more time to ensure that the boundary
- // is good, including a correct rules status value.
- //
- fBI->fPosition = backupPos;
- aBoundary = fBI->handleNext();
- if (aBoundary <= backupPos + 4) {
- // +4 is a quick test for possibly having advanced only one codepoint.
- // Four being the length of the longest potential code point, a supplementary in UTF-8
- utext_setNativeIndex(&fBI->fText, aBoundary);
- if (backupPos == utext_getPreviousNativeIndex(&fBI->fText)) {
- // The initial handleNext() only advanced by a single code point. Go again.
- aBoundary = fBI->handleNext(); // Safe rules identify safe pairs.
- }
+ // Threshold for a text position to be considered near to existing cache contents.
+ // TODO: See issue ICU-22024 "perf tuning of Cache needed."
+ // This value is subject to change. See the ticket for more details.
+ static constexpr int32_t CACHE_NEAR = 15;
+
+ int32_t aBoundary = -1;
+ int32_t ruleStatusIndex = 0;
+ bool retainCache = false;
+ if ((position > fBoundaries[fStartBufIdx] - CACHE_NEAR) && position < (fBoundaries[fEndBufIdx] + CACHE_NEAR)) {
+ // Requested position is near the existing cache. Retain it.
+ retainCache = true;
+ } else if (position <= CACHE_NEAR) {
+ // Requested position is near the start of the text. Fill cache from start, skipping
+ // the need to find a safe point.
+ retainCache = false;
+ aBoundary = 0;
+ } else {
+ // Requested position is not near the existing cache.
+ // Find a safe point to refill the cache from.
+ int32_t backupPos = fBI->handleSafePrevious(position);
+
+ if (fBoundaries[fEndBufIdx] < position && fBoundaries[fEndBufIdx] >= (backupPos - CACHE_NEAR)) {
+ // The requested position is beyond the end of the existing cache, but the
+ // reverse rules produced a position near or before the cached region.
+ // Retain the existing cache, and fill from the end of it.
+ retainCache = true;
+ } else if (backupPos < CACHE_NEAR) {
+ // The safe reverse rules moved us to near the start of text.
+ // Take that (index 0) as the backup boundary, avoiding the complication
+ // (in the following block) of moving forward from the safe point to a known boundary.
+ //
+ // Retain the cache if it begins not too far from the requested position.
+ aBoundary = 0;
+ retainCache = (fBoundaries[fStartBufIdx] <= (position + CACHE_NEAR));
+ } else {
+ // The safe reverse rules produced a position that is neither near the existing
+ // cache, nor near the start of text.
+ // Advance to the boundary following.
+ // There is a complication: the safe reverse rules identify pairs of code points
+ // that are safe. If advancing from the safe point moves forwards by less than
+ // two code points, we need to advance one more time to ensure that the boundary
+ // is good, including a correct rules status value.
+ retainCache = false;
+ fBI->fPosition = backupPos;
+ aBoundary = fBI->handleNext();
+ if (aBoundary != UBRK_DONE && aBoundary <= backupPos + 4) {
+ // +4 is a quick test for possibly having advanced only one codepoint.
+ // Four being the length of the longest potential code point, a supplementary in UTF-8
+ utext_setNativeIndex(&fBI->fText, aBoundary);
+ if (backupPos == utext_getPreviousNativeIndex(&fBI->fText)) {
+ // The initial handleNext() only advanced by a single code point. Go again.
+ aBoundary = fBI->handleNext(); // Safe rules identify safe pairs.
}
- ruleStatusIndex = fBI->fRuleStatusIndex;
}
+ if (aBoundary == UBRK_DONE) {
+ // Note (Andy Heninger): I don't think this condition can occur, but it's hard
+ // to prove that it can't. We ran off the end of the string looking a boundary
+ // following a safe point; choose the end of the string as that boundary.
+ aBoundary = utext_nativeLength(&fBI->fText);
+ }
+ ruleStatusIndex = fBI->fRuleStatusIndex;
}
+ }
+
+ if (!retainCache) {
+ U_ASSERT(aBoundary != -1);
reset(aBoundary, ruleStatusIndex); // Reset cache to hold aBoundary as a single starting point.
}
@@ -430,13 +476,13 @@ UBool RuleBasedBreakIterator::BreakCache::populateFollowing() {
if (fBI->fDictionaryCache->following(fromPosition, &pos, &ruleStatusIdx)) {
addFollowing(pos, ruleStatusIdx, UpdateCachePosition);
- return TRUE;
+ return true;
}
fBI->fPosition = fromPosition;
pos = fBI->handleNext();
if (pos == UBRK_DONE) {
- return FALSE;
+ return false;
}
ruleStatusIdx = fBI->fRuleStatusIndex;
@@ -446,7 +492,7 @@ UBool RuleBasedBreakIterator::BreakCache::populateFollowing() {
fBI->fDictionaryCache->populateDictionary(fromPosition, pos, fromRuleStatusIdx, ruleStatusIdx);
if (fBI->fDictionaryCache->following(fromPosition, &pos, &ruleStatusIdx)) {
addFollowing(pos, ruleStatusIdx, UpdateCachePosition);
- return TRUE;
+ return true;
// TODO: may want to move a sizable chunk of dictionary cache to break cache at this point.
// But be careful with interactions with populateNear().
}
@@ -469,18 +515,18 @@ UBool RuleBasedBreakIterator::BreakCache::populateFollowing() {
addFollowing(pos, fBI->fRuleStatusIndex, RetainCachePosition);
}
- return TRUE;
+ return true;
}
UBool RuleBasedBreakIterator::BreakCache::populatePreceding(UErrorCode &status) {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
int32_t fromPosition = fBoundaries[fStartBufIdx];
if (fromPosition == 0) {
- return FALSE;
+ return false;
}
int32_t position = 0;
@@ -488,7 +534,7 @@ UBool RuleBasedBreakIterator::BreakCache::populatePreceding(UErrorCode &status)
if (fBI->fDictionaryCache->preceding(fromPosition, &position, &positionStatusIdx)) {
addPreceding(position, positionStatusIdx, UpdateCachePosition);
- return TRUE;
+ return true;
}
int32_t backupPosition = fromPosition;
@@ -542,7 +588,7 @@ UBool RuleBasedBreakIterator::BreakCache::populatePreceding(UErrorCode &status)
break;
}
- UBool segmentHandledByDictionary = FALSE;
+ UBool segmentHandledByDictionary = false;
if (fBI->fDictionaryCharCount != 0) {
// Segment from the rules includes dictionary characters.
// Subdivide it, with subdivided results going into the dictionary cache.
@@ -569,12 +615,12 @@ UBool RuleBasedBreakIterator::BreakCache::populatePreceding(UErrorCode &status)
} while (position < fromPosition);
// Move boundaries from the side buffer to the main circular buffer.
- UBool success = FALSE;
+ UBool success = false;
if (!fSideBuffer.isEmpty()) {
positionStatusIdx = fSideBuffer.popi();
position = fSideBuffer.popi();
addPreceding(position, positionStatusIdx, UpdateCachePosition);
- success = TRUE;
+ success = true;
}
while (!fSideBuffer.isEmpty()) {
diff --git a/thirdparty/icu4c/common/rbbidata.cpp b/thirdparty/icu4c/common/rbbidata.cpp
index 6338ed3ed8..f50fc458a5 100644
--- a/thirdparty/icu4c/common/rbbidata.cpp
+++ b/thirdparty/icu4c/common/rbbidata.cpp
@@ -38,7 +38,7 @@ RBBIDataWrapper::RBBIDataWrapper(const RBBIDataHeader *data, UErrorCode &status)
RBBIDataWrapper::RBBIDataWrapper(const RBBIDataHeader *data, enum EDontAdopt, UErrorCode &status) {
init0();
init(data, status);
- fDontFreeData = TRUE;
+ fDontFreeData = true;
}
RBBIDataWrapper::RBBIDataWrapper(UDataMemory* udm, UErrorCode &status) {
@@ -86,7 +86,7 @@ void RBBIDataWrapper::init0() {
fTrie = NULL;
fUDataMem = NULL;
fRefCount = 0;
- fDontFreeData = TRUE;
+ fDontFreeData = true;
}
void RBBIDataWrapper::init(const RBBIDataHeader *data, UErrorCode &status) {
@@ -102,7 +102,7 @@ void RBBIDataWrapper::init(const RBBIDataHeader *data, UErrorCode &status) {
// that is no longer supported. At that time fFormatVersion was
// an int32_t field, rather than an array of 4 bytes.
- fDontFreeData = FALSE;
+ fDontFreeData = false;
if (data->fFTableLen != 0) {
fForwardTable = (RBBIStateTable *)((char *)data + fHeader->fFTable);
}
diff --git a/thirdparty/icu4c/common/rbbinode.cpp b/thirdparty/icu4c/common/rbbinode.cpp
index 27bcd8f8fe..da5937cafd 100644
--- a/thirdparty/icu4c/common/rbbinode.cpp
+++ b/thirdparty/icu4c/common/rbbinode.cpp
@@ -58,10 +58,10 @@ RBBINode::RBBINode(NodeType t) : UMemory() {
fInputSet = NULL;
fFirstPos = 0;
fLastPos = 0;
- fNullable = FALSE;
- fLookAheadEnd = FALSE;
- fRuleRoot = FALSE;
- fChainIn = FALSE;
+ fNullable = false;
+ fLookAheadEnd = false;
+ fRuleRoot = false;
+ fChainIn = false;
fVal = 0;
fPrecedence = precZero;
@@ -92,7 +92,7 @@ RBBINode::RBBINode(const RBBINode &other) : UMemory(other) {
fLastPos = other.fLastPos;
fNullable = other.fNullable;
fVal = other.fVal;
- fRuleRoot = FALSE;
+ fRuleRoot = false;
fChainIn = other.fChainIn;
UErrorCode status = U_ZERO_ERROR;
fFirstPosSet = new UVector(status); // TODO - get a real status from somewhere
@@ -355,11 +355,11 @@ void RBBINode::printTree(const RBBINode *node, UBool printHeading) {
// Unconditionally dump children of all other node types.
if (node->fType != varRef) {
if (node->fLeftChild != NULL) {
- printTree(node->fLeftChild, FALSE);
+ printTree(node->fLeftChild, false);
}
if (node->fRightChild != NULL) {
- printTree(node->fRightChild, FALSE);
+ printTree(node->fRightChild, false);
}
}
}
diff --git a/thirdparty/icu4c/common/rbbirb.cpp b/thirdparty/icu4c/common/rbbirb.cpp
index e5c250dfe4..a9d76f2482 100644
--- a/thirdparty/icu4c/common/rbbirb.cpp
+++ b/thirdparty/icu4c/common/rbbirb.cpp
@@ -65,9 +65,9 @@ RBBIRuleBuilder::RBBIRuleBuilder(const UnicodeString &rules,
fDefaultTree = &fForwardTree;
fForwardTable = NULL;
fRuleStatusVals = NULL;
- fChainRules = FALSE;
- fLBCMNoChain = FALSE;
- fLookAheadHardBreak = FALSE;
+ fChainRules = false;
+ fLBCMNoChain = false;
+ fLookAheadHardBreak = false;
fUSetNodes = NULL;
fRuleStatusVals = NULL;
fScanner = NULL;
diff --git a/thirdparty/icu4c/common/rbbirb.h b/thirdparty/icu4c/common/rbbirb.h
index 11dbf343ec..d983a184b6 100644
--- a/thirdparty/icu4c/common/rbbirb.h
+++ b/thirdparty/icu4c/common/rbbirb.h
@@ -54,8 +54,8 @@ public: // of these structs for each ent
~RBBISymbolTableEntry();
private:
- RBBISymbolTableEntry(const RBBISymbolTableEntry &other); // forbid copying of this class
- RBBISymbolTableEntry &operator=(const RBBISymbolTableEntry &other); // forbid copying of this class
+ RBBISymbolTableEntry(const RBBISymbolTableEntry &other) = delete; // forbid copying of this class
+ RBBISymbolTableEntry &operator=(const RBBISymbolTableEntry &other) = delete; // forbid copying of this class
};
@@ -177,8 +177,8 @@ public:
RBBIDataHeader *flattenData(); // Create the flattened (runtime format)
// data tables..
private:
- RBBIRuleBuilder(const RBBIRuleBuilder &other); // forbid copying of this class
- RBBIRuleBuilder &operator=(const RBBIRuleBuilder &other); // forbid copying of this class
+ RBBIRuleBuilder(const RBBIRuleBuilder &other) = delete; // forbid copying of this class
+ RBBIRuleBuilder &operator=(const RBBIRuleBuilder &other) = delete; // forbid copying of this class
};
diff --git a/thirdparty/icu4c/common/rbbirpt.h b/thirdparty/icu4c/common/rbbirpt.h
index 586953c90c..ca1bcf45dc 100644
--- a/thirdparty/icu4c/common/rbbirpt.h
+++ b/thirdparty/icu4c/common/rbbirpt.h
@@ -79,110 +79,110 @@ struct RBBIRuleTableEl {
};
static const struct RBBIRuleTableEl gRuleParseStateTable[] = {
- {doNOP, 0, 0, 0, TRUE}
- , {doExprStart, 254, 29, 9, FALSE} // 1 start
- , {doNOP, 132, 1,0, TRUE} // 2
- , {doNoChain, 94 /* ^ */, 12, 9, TRUE} // 3
- , {doExprStart, 36 /* $ */, 88, 98, FALSE} // 4
- , {doNOP, 33 /* ! */, 19,0, TRUE} // 5
- , {doNOP, 59 /* ; */, 1,0, TRUE} // 6
- , {doNOP, 252, 0,0, FALSE} // 7
- , {doExprStart, 255, 29, 9, FALSE} // 8
- , {doEndOfRule, 59 /* ; */, 1,0, TRUE} // 9 break-rule-end
- , {doNOP, 132, 9,0, TRUE} // 10
- , {doRuleError, 255, 103,0, FALSE} // 11
- , {doExprStart, 254, 29,0, FALSE} // 12 start-after-caret
- , {doNOP, 132, 12,0, TRUE} // 13
- , {doRuleError, 94 /* ^ */, 103,0, FALSE} // 14
- , {doExprStart, 36 /* $ */, 88, 37, FALSE} // 15
- , {doRuleError, 59 /* ; */, 103,0, FALSE} // 16
- , {doRuleError, 252, 103,0, FALSE} // 17
- , {doExprStart, 255, 29,0, FALSE} // 18
- , {doNOP, 33 /* ! */, 21,0, TRUE} // 19 rev-option
- , {doReverseDir, 255, 28, 9, FALSE} // 20
- , {doOptionStart, 130, 23,0, TRUE} // 21 option-scan1
- , {doRuleError, 255, 103,0, FALSE} // 22
- , {doNOP, 129, 23,0, TRUE} // 23 option-scan2
- , {doOptionEnd, 255, 25,0, FALSE} // 24
- , {doNOP, 59 /* ; */, 1,0, TRUE} // 25 option-scan3
- , {doNOP, 132, 25,0, TRUE} // 26
- , {doRuleError, 255, 103,0, FALSE} // 27
- , {doExprStart, 255, 29, 9, FALSE} // 28 reverse-rule
- , {doRuleChar, 254, 38,0, TRUE} // 29 term
- , {doNOP, 132, 29,0, TRUE} // 30
- , {doRuleChar, 131, 38,0, TRUE} // 31
- , {doNOP, 91 /* [ */, 94, 38, FALSE} // 32
- , {doLParen, 40 /* ( */, 29, 38, TRUE} // 33
- , {doNOP, 36 /* $ */, 88, 37, FALSE} // 34
- , {doDotAny, 46 /* . */, 38,0, TRUE} // 35
- , {doRuleError, 255, 103,0, FALSE} // 36
- , {doCheckVarDef, 255, 38,0, FALSE} // 37 term-var-ref
- , {doNOP, 132, 38,0, TRUE} // 38 expr-mod
- , {doUnaryOpStar, 42 /* * */, 43,0, TRUE} // 39
- , {doUnaryOpPlus, 43 /* + */, 43,0, TRUE} // 40
- , {doUnaryOpQuestion, 63 /* ? */, 43,0, TRUE} // 41
- , {doNOP, 255, 43,0, FALSE} // 42
- , {doExprCatOperator, 254, 29,0, FALSE} // 43 expr-cont
- , {doNOP, 132, 43,0, TRUE} // 44
- , {doExprCatOperator, 131, 29,0, FALSE} // 45
- , {doExprCatOperator, 91 /* [ */, 29,0, FALSE} // 46
- , {doExprCatOperator, 40 /* ( */, 29,0, FALSE} // 47
- , {doExprCatOperator, 36 /* $ */, 29,0, FALSE} // 48
- , {doExprCatOperator, 46 /* . */, 29,0, FALSE} // 49
- , {doExprCatOperator, 47 /* / */, 55,0, FALSE} // 50
- , {doExprCatOperator, 123 /* { */, 67,0, TRUE} // 51
- , {doExprOrOperator, 124 /* | */, 29,0, TRUE} // 52
- , {doExprRParen, 41 /* ) */, 255,0, TRUE} // 53
- , {doExprFinished, 255, 255,0, FALSE} // 54
- , {doSlash, 47 /* / */, 57,0, TRUE} // 55 look-ahead
- , {doNOP, 255, 103,0, FALSE} // 56
- , {doExprCatOperator, 254, 29,0, FALSE} // 57 expr-cont-no-slash
- , {doNOP, 132, 43,0, TRUE} // 58
- , {doExprCatOperator, 131, 29,0, FALSE} // 59
- , {doExprCatOperator, 91 /* [ */, 29,0, FALSE} // 60
- , {doExprCatOperator, 40 /* ( */, 29,0, FALSE} // 61
- , {doExprCatOperator, 36 /* $ */, 29,0, FALSE} // 62
- , {doExprCatOperator, 46 /* . */, 29,0, FALSE} // 63
- , {doExprOrOperator, 124 /* | */, 29,0, TRUE} // 64
- , {doExprRParen, 41 /* ) */, 255,0, TRUE} // 65
- , {doExprFinished, 255, 255,0, FALSE} // 66
- , {doNOP, 132, 67,0, TRUE} // 67 tag-open
- , {doStartTagValue, 128, 70,0, FALSE} // 68
- , {doTagExpectedError, 255, 103,0, FALSE} // 69
- , {doNOP, 132, 74,0, TRUE} // 70 tag-value
- , {doNOP, 125 /* } */, 74,0, FALSE} // 71
- , {doTagDigit, 128, 70,0, TRUE} // 72
- , {doTagExpectedError, 255, 103,0, FALSE} // 73
- , {doNOP, 132, 74,0, TRUE} // 74 tag-close
- , {doTagValue, 125 /* } */, 77,0, TRUE} // 75
- , {doTagExpectedError, 255, 103,0, FALSE} // 76
- , {doExprCatOperator, 254, 29,0, FALSE} // 77 expr-cont-no-tag
- , {doNOP, 132, 77,0, TRUE} // 78
- , {doExprCatOperator, 131, 29,0, FALSE} // 79
- , {doExprCatOperator, 91 /* [ */, 29,0, FALSE} // 80
- , {doExprCatOperator, 40 /* ( */, 29,0, FALSE} // 81
- , {doExprCatOperator, 36 /* $ */, 29,0, FALSE} // 82
- , {doExprCatOperator, 46 /* . */, 29,0, FALSE} // 83
- , {doExprCatOperator, 47 /* / */, 55,0, FALSE} // 84
- , {doExprOrOperator, 124 /* | */, 29,0, TRUE} // 85
- , {doExprRParen, 41 /* ) */, 255,0, TRUE} // 86
- , {doExprFinished, 255, 255,0, FALSE} // 87
- , {doStartVariableName, 36 /* $ */, 90,0, TRUE} // 88 scan-var-name
- , {doNOP, 255, 103,0, FALSE} // 89
- , {doNOP, 130, 92,0, TRUE} // 90 scan-var-start
- , {doVariableNameExpectedErr, 255, 103,0, FALSE} // 91
- , {doNOP, 129, 92,0, TRUE} // 92 scan-var-body
- , {doEndVariableName, 255, 255,0, FALSE} // 93
- , {doScanUnicodeSet, 91 /* [ */, 255,0, TRUE} // 94 scan-unicode-set
- , {doScanUnicodeSet, 112 /* p */, 255,0, TRUE} // 95
- , {doScanUnicodeSet, 80 /* P */, 255,0, TRUE} // 96
- , {doNOP, 255, 103,0, FALSE} // 97
- , {doNOP, 132, 98,0, TRUE} // 98 assign-or-rule
- , {doStartAssign, 61 /* = */, 29, 101, TRUE} // 99
- , {doNOP, 255, 37, 9, FALSE} // 100
- , {doEndAssign, 59 /* ; */, 1,0, TRUE} // 101 assign-end
- , {doRuleErrorAssignExpr, 255, 103,0, FALSE} // 102
- , {doExit, 255, 103,0, TRUE} // 103 errorDeath
+ {doNOP, 0, 0, 0, true}
+ , {doExprStart, 254, 29, 9, false} // 1 start
+ , {doNOP, 132, 1,0, true} // 2
+ , {doNoChain, 94 /* ^ */, 12, 9, true} // 3
+ , {doExprStart, 36 /* $ */, 88, 98, false} // 4
+ , {doNOP, 33 /* ! */, 19,0, true} // 5
+ , {doNOP, 59 /* ; */, 1,0, true} // 6
+ , {doNOP, 252, 0,0, false} // 7
+ , {doExprStart, 255, 29, 9, false} // 8
+ , {doEndOfRule, 59 /* ; */, 1,0, true} // 9 break-rule-end
+ , {doNOP, 132, 9,0, true} // 10
+ , {doRuleError, 255, 103,0, false} // 11
+ , {doExprStart, 254, 29,0, false} // 12 start-after-caret
+ , {doNOP, 132, 12,0, true} // 13
+ , {doRuleError, 94 /* ^ */, 103,0, false} // 14
+ , {doExprStart, 36 /* $ */, 88, 37, false} // 15
+ , {doRuleError, 59 /* ; */, 103,0, false} // 16
+ , {doRuleError, 252, 103,0, false} // 17
+ , {doExprStart, 255, 29,0, false} // 18
+ , {doNOP, 33 /* ! */, 21,0, true} // 19 rev-option
+ , {doReverseDir, 255, 28, 9, false} // 20
+ , {doOptionStart, 130, 23,0, true} // 21 option-scan1
+ , {doRuleError, 255, 103,0, false} // 22
+ , {doNOP, 129, 23,0, true} // 23 option-scan2
+ , {doOptionEnd, 255, 25,0, false} // 24
+ , {doNOP, 59 /* ; */, 1,0, true} // 25 option-scan3
+ , {doNOP, 132, 25,0, true} // 26
+ , {doRuleError, 255, 103,0, false} // 27
+ , {doExprStart, 255, 29, 9, false} // 28 reverse-rule
+ , {doRuleChar, 254, 38,0, true} // 29 term
+ , {doNOP, 132, 29,0, true} // 30
+ , {doRuleChar, 131, 38,0, true} // 31
+ , {doNOP, 91 /* [ */, 94, 38, false} // 32
+ , {doLParen, 40 /* ( */, 29, 38, true} // 33
+ , {doNOP, 36 /* $ */, 88, 37, false} // 34
+ , {doDotAny, 46 /* . */, 38,0, true} // 35
+ , {doRuleError, 255, 103,0, false} // 36
+ , {doCheckVarDef, 255, 38,0, false} // 37 term-var-ref
+ , {doNOP, 132, 38,0, true} // 38 expr-mod
+ , {doUnaryOpStar, 42 /* * */, 43,0, true} // 39
+ , {doUnaryOpPlus, 43 /* + */, 43,0, true} // 40
+ , {doUnaryOpQuestion, 63 /* ? */, 43,0, true} // 41
+ , {doNOP, 255, 43,0, false} // 42
+ , {doExprCatOperator, 254, 29,0, false} // 43 expr-cont
+ , {doNOP, 132, 43,0, true} // 44
+ , {doExprCatOperator, 131, 29,0, false} // 45
+ , {doExprCatOperator, 91 /* [ */, 29,0, false} // 46
+ , {doExprCatOperator, 40 /* ( */, 29,0, false} // 47
+ , {doExprCatOperator, 36 /* $ */, 29,0, false} // 48
+ , {doExprCatOperator, 46 /* . */, 29,0, false} // 49
+ , {doExprCatOperator, 47 /* / */, 55,0, false} // 50
+ , {doExprCatOperator, 123 /* { */, 67,0, true} // 51
+ , {doExprOrOperator, 124 /* | */, 29,0, true} // 52
+ , {doExprRParen, 41 /* ) */, 255,0, true} // 53
+ , {doExprFinished, 255, 255,0, false} // 54
+ , {doSlash, 47 /* / */, 57,0, true} // 55 look-ahead
+ , {doNOP, 255, 103,0, false} // 56
+ , {doExprCatOperator, 254, 29,0, false} // 57 expr-cont-no-slash
+ , {doNOP, 132, 43,0, true} // 58
+ , {doExprCatOperator, 131, 29,0, false} // 59
+ , {doExprCatOperator, 91 /* [ */, 29,0, false} // 60
+ , {doExprCatOperator, 40 /* ( */, 29,0, false} // 61
+ , {doExprCatOperator, 36 /* $ */, 29,0, false} // 62
+ , {doExprCatOperator, 46 /* . */, 29,0, false} // 63
+ , {doExprOrOperator, 124 /* | */, 29,0, true} // 64
+ , {doExprRParen, 41 /* ) */, 255,0, true} // 65
+ , {doExprFinished, 255, 255,0, false} // 66
+ , {doNOP, 132, 67,0, true} // 67 tag-open
+ , {doStartTagValue, 128, 70,0, false} // 68
+ , {doTagExpectedError, 255, 103,0, false} // 69
+ , {doNOP, 132, 74,0, true} // 70 tag-value
+ , {doNOP, 125 /* } */, 74,0, false} // 71
+ , {doTagDigit, 128, 70,0, true} // 72
+ , {doTagExpectedError, 255, 103,0, false} // 73
+ , {doNOP, 132, 74,0, true} // 74 tag-close
+ , {doTagValue, 125 /* } */, 77,0, true} // 75
+ , {doTagExpectedError, 255, 103,0, false} // 76
+ , {doExprCatOperator, 254, 29,0, false} // 77 expr-cont-no-tag
+ , {doNOP, 132, 77,0, true} // 78
+ , {doExprCatOperator, 131, 29,0, false} // 79
+ , {doExprCatOperator, 91 /* [ */, 29,0, false} // 80
+ , {doExprCatOperator, 40 /* ( */, 29,0, false} // 81
+ , {doExprCatOperator, 36 /* $ */, 29,0, false} // 82
+ , {doExprCatOperator, 46 /* . */, 29,0, false} // 83
+ , {doExprCatOperator, 47 /* / */, 55,0, false} // 84
+ , {doExprOrOperator, 124 /* | */, 29,0, true} // 85
+ , {doExprRParen, 41 /* ) */, 255,0, true} // 86
+ , {doExprFinished, 255, 255,0, false} // 87
+ , {doStartVariableName, 36 /* $ */, 90,0, true} // 88 scan-var-name
+ , {doNOP, 255, 103,0, false} // 89
+ , {doNOP, 130, 92,0, true} // 90 scan-var-start
+ , {doVariableNameExpectedErr, 255, 103,0, false} // 91
+ , {doNOP, 129, 92,0, true} // 92 scan-var-body
+ , {doEndVariableName, 255, 255,0, false} // 93
+ , {doScanUnicodeSet, 91 /* [ */, 255,0, true} // 94 scan-unicode-set
+ , {doScanUnicodeSet, 112 /* p */, 255,0, true} // 95
+ , {doScanUnicodeSet, 80 /* P */, 255,0, true} // 96
+ , {doNOP, 255, 103,0, false} // 97
+ , {doNOP, 132, 98,0, true} // 98 assign-or-rule
+ , {doStartAssign, 61 /* = */, 29, 101, true} // 99
+ , {doNOP, 255, 37, 9, false} // 100
+ , {doEndAssign, 59 /* ; */, 1,0, true} // 101 assign-end
+ , {doRuleErrorAssignExpr, 255, 103,0, false} // 102
+ , {doExit, 255, 103,0, true} // 103 errorDeath
};
#ifdef RBBI_DEBUG
static const char * const RBBIRuleStateNames[] = { 0,
diff --git a/thirdparty/icu4c/common/rbbiscan.cpp b/thirdparty/icu4c/common/rbbiscan.cpp
index 1304f7e37e..92cf77664f 100644
--- a/thirdparty/icu4c/common/rbbiscan.cpp
+++ b/thirdparty/icu4c/common/rbbiscan.cpp
@@ -92,7 +92,7 @@ RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder *rb)
fRB = rb;
fScanIndex = 0;
fNextIndex = 0;
- fQuoteMode = FALSE;
+ fQuoteMode = false;
fLineNum = 1;
fCharNum = 0;
fLastChar = 0;
@@ -103,9 +103,9 @@ RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder *rb)
fNodeStack[0] = NULL;
fNodeStackPtr = 0;
- fReverseRule = FALSE;
- fLookAheadRule = FALSE;
- fNoChainInRule = FALSE;
+ fReverseRule = false;
+ fLookAheadRule = false;
+ fNoChainInRule = false;
fSymbolTable = NULL;
fSetTable = NULL;
@@ -201,7 +201,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
{
RBBINode *n = NULL;
- UBool returnVal = TRUE;
+ UBool returnVal = true;
switch (action) {
@@ -213,7 +213,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doNoChain:
// Scanned a '^' while on the rule start state.
- fNoChainInRule = TRUE;
+ fNoChainInRule = true;
break;
@@ -345,7 +345,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
catNode->fRightChild = endNode;
fNodeStack[fNodeStackPtr] = catNode;
endNode->fVal = fRuleNum;
- endNode->fLookAheadEnd = TRUE;
+ endNode->fLookAheadEnd = true;
thisRule = catNode;
// TODO: Disable chaining out of look-ahead (hard break) rules.
@@ -354,13 +354,13 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
}
// Mark this node as being the root of a rule.
- thisRule->fRuleRoot = TRUE;
+ thisRule->fRuleRoot = true;
// Flag if chaining into this rule is wanted.
//
if (fRB->fChainRules && // If rule chaining is enabled globally via !!chain
!fNoChainInRule) { // and no '^' chain-in inhibit was on this rule
- thisRule->fChainIn = TRUE;
+ thisRule->fChainIn = true;
}
@@ -398,9 +398,9 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
// Just move its parse tree from the stack to *destRules.
*destRules = fNodeStack[fNodeStackPtr];
}
- fReverseRule = FALSE; // in preparation for the next rule.
- fLookAheadRule = FALSE;
- fNoChainInRule = FALSE;
+ fReverseRule = false; // in preparation for the next rule.
+ fLookAheadRule = false;
+ fNoChainInRule = false;
fNodeStackPtr = 0;
}
break;
@@ -408,7 +408,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doRuleError:
error(U_BRK_RULE_SYNTAX);
- returnVal = FALSE;
+ returnVal = false;
break;
@@ -484,7 +484,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
if (U_FAILURE(*fRB->fStatus)) {
break;
}
- findSetFor(UnicodeString(TRUE, kAny, 3), n);
+ findSetFor(UnicodeString(true, kAny, 3), n);
n->fFirstPos = fScanIndex;
n->fLastPos = fNextIndex;
fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
@@ -501,7 +501,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
n->fFirstPos = fScanIndex;
n->fLastPos = fNextIndex;
fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);
- fLookAheadRule = TRUE;
+ fLookAheadRule = true;
break;
@@ -534,7 +534,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doTagExpectedError:
error(U_BRK_MALFORMED_RULE_TAG);
- returnVal = FALSE;
+ returnVal = false;
break;
case doOptionStart:
@@ -546,9 +546,9 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
{
UnicodeString opt(fRB->fRules, fOptionStart, fScanIndex-fOptionStart);
if (opt == UNICODE_STRING("chain", 5)) {
- fRB->fChainRules = TRUE;
+ fRB->fChainRules = true;
} else if (opt == UNICODE_STRING("LBCMNoChain", 11)) {
- fRB->fLBCMNoChain = TRUE;
+ fRB->fLBCMNoChain = true;
} else if (opt == UNICODE_STRING("forward", 7)) {
fRB->fDefaultTree = &fRB->fForwardTree;
} else if (opt == UNICODE_STRING("reverse", 7)) {
@@ -558,7 +558,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
} else if (opt == UNICODE_STRING("safe_reverse", 12)) {
fRB->fDefaultTree = &fRB->fSafeRevTree;
} else if (opt == UNICODE_STRING("lookAheadHardBreak", 18)) {
- fRB->fLookAheadHardBreak = TRUE;
+ fRB->fLookAheadHardBreak = true;
} else if (opt == UNICODE_STRING("quoted_literals_only", 20)) {
fRuleSets[kRuleSet_rule_char-128].clear();
} else if (opt == UNICODE_STRING("unquoted_literals", 17)) {
@@ -570,7 +570,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
break;
case doReverseDir:
- fReverseRule = TRUE;
+ fReverseRule = true;
break;
case doStartVariableName:
@@ -600,7 +600,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
n = fNodeStack[fNodeStackPtr];
if (n->fLeftChild == NULL) {
error(U_BRK_UNDEFINED_VARIABLE);
- returnVal = FALSE;
+ returnVal = false;
}
break;
@@ -609,11 +609,11 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
case doRuleErrorAssignExpr:
error(U_BRK_ASSIGN_ERROR);
- returnVal = FALSE;
+ returnVal = false;
break;
case doExit:
- returnVal = FALSE;
+ returnVal = false;
break;
case doScanUnicodeSet:
@@ -622,7 +622,7 @@ UBool RBBIRuleScanner::doParseActions(int32_t action)
default:
error(U_BRK_INTERNAL_ERROR);
- returnVal = FALSE;
+ returnVal = false;
break;
}
return returnVal && U_SUCCESS(*fRB->fStatus);
@@ -872,7 +872,7 @@ UChar32 RBBIRuleScanner::nextCharLL() {
fCharNum=0;
if (fQuoteMode) {
error(U_BRK_NEW_LINE_IN_QUOTED_STRING);
- fQuoteMode = FALSE;
+ fQuoteMode = false;
}
}
else {
@@ -901,7 +901,7 @@ void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
fScanIndex = fNextIndex;
c.fChar = nextCharLL();
- c.fEscaped = FALSE;
+ c.fEscaped = false;
//
// check for '' sequence.
@@ -910,7 +910,7 @@ void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
if (c.fChar == chApos) {
if (fRB->fRules.char32At(fNextIndex) == chApos) {
c.fChar = nextCharLL(); // get nextChar officially so character counts
- c.fEscaped = TRUE; // stay correct.
+ c.fEscaped = true; // stay correct.
}
else
{
@@ -918,18 +918,18 @@ void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
// Toggle quoting mode.
// Return either '(' or ')', because quotes cause a grouping of the quoted text.
fQuoteMode = !fQuoteMode;
- if (fQuoteMode == TRUE) {
+ if (fQuoteMode == true) {
c.fChar = chLParen;
} else {
c.fChar = chRParen;
}
- c.fEscaped = FALSE; // The paren that we return is not escaped.
+ c.fEscaped = false; // The paren that we return is not escaped.
return;
}
}
if (fQuoteMode) {
- c.fEscaped = TRUE;
+ c.fEscaped = true;
}
else
{
@@ -963,7 +963,7 @@ void RBBIRuleScanner::nextChar(RBBIRuleChar &c) {
// Use UnicodeString::unescapeAt() to handle them.
//
if (c.fChar == chBackSlash) {
- c.fEscaped = TRUE;
+ c.fEscaped = true;
int32_t startX = fNextIndex;
c.fChar = fRB->fRules.unescapeAt(fNextIndex);
if (fNextIndex == startX) {
@@ -1032,7 +1032,7 @@ void RBBIRuleScanner::parse() {
#ifdef RBBI_DEBUG
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { RBBIDebugPrintf("."); fflush(stdout);}
#endif
- if (tableEl->fCharClass < 127 && fC.fEscaped == FALSE && tableEl->fCharClass == fC.fChar) {
+ if (tableEl->fCharClass < 127 && fC.fEscaped == false && tableEl->fCharClass == fC.fChar) {
// Table row specified an individual character, not a set, and
// the input character is not escaped, and
// the input character matched it.
@@ -1057,7 +1057,7 @@ void RBBIRuleScanner::parse() {
}
if (tableEl->fCharClass >= 128 && tableEl->fCharClass < 240 && // Table specs a char class &&
- fC.fEscaped == FALSE && // char is not escaped &&
+ fC.fEscaped == false && // char is not escaped &&
fC.fChar != (UChar32)-1) { // char is not EOF
U_ASSERT((tableEl->fCharClass-128) < UPRV_LENGTHOF(fRuleSets));
if (fRuleSets[tableEl->fCharClass-128].contains(fC.fChar)) {
@@ -1076,7 +1076,7 @@ void RBBIRuleScanner::parse() {
// We've found the row of the state table that matches the current input
// character from the rules string.
// Perform any action specified by this row in the state table.
- if (doParseActions((int32_t)tableEl->fAction) == FALSE) {
+ if (doParseActions((int32_t)tableEl->fAction) == false) {
// Break out of the state machine loop if the
// the action signalled some kind of error, or
// the action was to exit, occurs on normal end-of-rules-input.
@@ -1133,13 +1133,13 @@ void RBBIRuleScanner::parse() {
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "symbols")) {fSymbolTable->rbbiSymtablePrint();}
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "ptree")) {
RBBIDebugPrintf("Completed Forward Rules Parse Tree...\n");
- RBBINode::printTree(fRB->fForwardTree, TRUE);
+ RBBINode::printTree(fRB->fForwardTree, true);
RBBIDebugPrintf("\nCompleted Reverse Rules Parse Tree...\n");
- RBBINode::printTree(fRB->fReverseTree, TRUE);
+ RBBINode::printTree(fRB->fReverseTree, true);
RBBIDebugPrintf("\nCompleted Safe Point Forward Rules Parse Tree...\n");
- RBBINode::printTree(fRB->fSafeFwdTree, TRUE);
+ RBBINode::printTree(fRB->fSafeFwdTree, true);
RBBIDebugPrintf("\nCompleted Safe Point Reverse Rules Parse Tree...\n");
- RBBINode::printTree(fRB->fSafeRevTree, TRUE);
+ RBBINode::printTree(fRB->fSafeRevTree, true);
}
#endif
}
@@ -1154,7 +1154,7 @@ void RBBIRuleScanner::parse() {
void RBBIRuleScanner::printNodeStack(const char *title) {
int i;
RBBIDebugPrintf("%s. Dumping node stack...\n", title);
- for (i=fNodeStackPtr; i>0; i--) {RBBINode::printTree(fNodeStack[i], TRUE);}
+ for (i=fNodeStackPtr; i>0; i--) {RBBINode::printTree(fNodeStack[i], true);}
}
#endif
diff --git a/thirdparty/icu4c/common/rbbiscan.h b/thirdparty/icu4c/common/rbbiscan.h
index 33fdf03354..bf3203880b 100644
--- a/thirdparty/icu4c/common/rbbiscan.h
+++ b/thirdparty/icu4c/common/rbbiscan.h
@@ -158,8 +158,8 @@ private:
UnicodeSet *gRuleSet_name_char;
UnicodeSet *gRuleSet_name_start_char;
- RBBIRuleScanner(const RBBIRuleScanner &other); // forbid copying of this class
- RBBIRuleScanner &operator=(const RBBIRuleScanner &other); // forbid copying of this class
+ RBBIRuleScanner(const RBBIRuleScanner &other) = delete; // forbid copying of this class
+ RBBIRuleScanner &operator=(const RBBIRuleScanner &other) = delete; // forbid copying of this class
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/rbbisetb.cpp b/thirdparty/icu4c/common/rbbisetb.cpp
index 29faeb8c45..11c47156d6 100644
--- a/thirdparty/icu4c/common/rbbisetb.cpp
+++ b/thirdparty/icu4c/common/rbbisetb.cpp
@@ -261,7 +261,7 @@ void RBBISetBuilder::buildRanges() {
}
if (inputSet->contains(bofString)) {
addValToSet(usetNode, 2);
- fSawBOF = TRUE;
+ fSawBOF = true;
}
}
@@ -569,7 +569,7 @@ void RBBISetBuilder::printSets() {
RBBI_DEBUG_printUnicodeString(usetNode->fText);
RBBIDebugPrintf("\n");
if (usetNode->fLeftChild != NULL) {
- RBBINode::printTree(usetNode->fLeftChild, TRUE);
+ RBBINode::printTree(usetNode->fLeftChild, true);
}
}
RBBIDebugPrintf("\n");
diff --git a/thirdparty/icu4c/common/rbbisetb.h b/thirdparty/icu4c/common/rbbisetb.h
index 6409a4ea57..cd09d3317a 100644
--- a/thirdparty/icu4c/common/rbbisetb.h
+++ b/thirdparty/icu4c/common/rbbisetb.h
@@ -134,8 +134,8 @@ private:
UBool fSawBOF;
- RBBISetBuilder(const RBBISetBuilder &other); // forbid copying of this class
- RBBISetBuilder &operator=(const RBBISetBuilder &other); // forbid copying of this class
+ RBBISetBuilder(const RBBISetBuilder &other) = delete; // forbid copying of this class
+ RBBISetBuilder &operator=(const RBBISetBuilder &other) = delete; // forbid copying of this class
};
diff --git a/thirdparty/icu4c/common/rbbistbl.cpp b/thirdparty/icu4c/common/rbbistbl.cpp
index 627ec1827c..554aeb793f 100644
--- a/thirdparty/icu4c/common/rbbistbl.cpp
+++ b/thirdparty/icu4c/common/rbbistbl.cpp
@@ -254,8 +254,8 @@ void RBBISymbolTable::rbbiSymtablePrint() const {
}
RBBISymbolTableEntry *s = (RBBISymbolTableEntry *)e->value.pointer;
RBBIDebugPrintf("%s\n", CStr(s->key)());
- RBBINode::printTree(s->val, TRUE);
- RBBINode::printTree(s->val->fLeftChild, FALSE);
+ RBBINode::printTree(s->val, true);
+ RBBINode::printTree(s->val->fLeftChild, false);
RBBIDebugPrintf("\n");
}
}
diff --git a/thirdparty/icu4c/common/rbbitblb.cpp b/thirdparty/icu4c/common/rbbitblb.cpp
index a495f17a87..0e3ec7999f 100644
--- a/thirdparty/icu4c/common/rbbitblb.cpp
+++ b/thirdparty/icu4c/common/rbbitblb.cpp
@@ -85,7 +85,7 @@ void RBBITableBuilder::buildForwardTable() {
#ifdef RBBI_DEBUG
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "ftree")) {
RBBIDebugPuts("\nParse tree after flattening variable references.");
- RBBINode::printTree(fTree, TRUE);
+ RBBINode::printTree(fTree, true);
}
#endif
@@ -143,7 +143,7 @@ void RBBITableBuilder::buildForwardTable() {
#ifdef RBBI_DEBUG
if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "stree")) {
RBBIDebugPuts("\nParse tree after flattening Unicode Set references.");
- RBBINode::printTree(fTree, TRUE);
+ RBBINode::printTree(fTree, true);
}
#endif
@@ -209,14 +209,14 @@ void RBBITableBuilder::calcNullable(RBBINode *n) {
if (n->fType == RBBINode::setRef ||
n->fType == RBBINode::endMark ) {
// These are non-empty leaf node types.
- n->fNullable = FALSE;
+ n->fNullable = false;
return;
}
if (n->fType == RBBINode::lookAhead || n->fType == RBBINode::tag) {
// Lookahead marker node. It's a leaf, so no recursion on children.
// It's nullable because it does not match any literal text from the input stream.
- n->fNullable = TRUE;
+ n->fNullable = true;
return;
}
@@ -234,10 +234,10 @@ void RBBITableBuilder::calcNullable(RBBINode *n) {
n->fNullable = n->fLeftChild->fNullable && n->fRightChild->fNullable;
}
else if (n->fType == RBBINode::opStar || n->fType == RBBINode::opQuestion) {
- n->fNullable = TRUE;
+ n->fNullable = true;
}
else {
- n->fNullable = FALSE;
+ n->fNullable = false;
}
}
@@ -618,7 +618,7 @@ void RBBITableBuilder::buildStateTable() {
for (tx=1; tx<fDStates->size(); tx++) {
RBBIStateDescriptor *temp;
temp = (RBBIStateDescriptor *)fDStates->elementAt(tx);
- if (temp->fMarked == FALSE) {
+ if (temp->fMarked == false) {
T = temp;
break;
}
@@ -628,7 +628,7 @@ void RBBITableBuilder::buildStateTable() {
}
// mark T;
- T->fMarked = TRUE;
+ T->fMarked = true;
// for each input symbol a do begin
int32_t a;
@@ -655,7 +655,7 @@ void RBBITableBuilder::buildStateTable() {
// if U is not empty and not in DStates then
int32_t ux = 0;
- UBool UinDstates = FALSE;
+ UBool UinDstates = false;
if (U != NULL) {
U_ASSERT(U->size() > 0);
int ix;
@@ -666,7 +666,7 @@ void RBBITableBuilder::buildStateTable() {
delete U;
U = temp2->fPositions;
ux = ix;
- UinDstates = TRUE;
+ UinDstates = true;
break;
}
}
@@ -1131,7 +1131,7 @@ void RBBITableBuilder::printPosSets(RBBINode *n) {
printf("\n");
RBBINode::printNodeHeader();
RBBINode::printNode(n);
- RBBIDebugPrintf(" Nullable: %s\n", n->fNullable?"TRUE":"FALSE");
+ RBBIDebugPrintf(" Nullable: %s\n", n->fNullable?"true":"false");
RBBIDebugPrintf(" firstpos: ");
printSet(n->fFirstPosSet);
@@ -1773,7 +1773,7 @@ void RBBITableBuilder::printRuleStatusTable() {
//-----------------------------------------------------------------------------
RBBIStateDescriptor::RBBIStateDescriptor(int lastInputSymbol, UErrorCode *fStatus) {
- fMarked = FALSE;
+ fMarked = false;
fAccepting = 0;
fLookAhead = 0;
fTagsIdx = 0;
diff --git a/thirdparty/icu4c/common/rbbitblb.h b/thirdparty/icu4c/common/rbbitblb.h
index 38607a819a..2ac66da11f 100644
--- a/thirdparty/icu4c/common/rbbitblb.h
+++ b/thirdparty/icu4c/common/rbbitblb.h
@@ -219,8 +219,8 @@ public:
~RBBIStateDescriptor();
private:
- RBBIStateDescriptor(const RBBIStateDescriptor &other); // forbid copying of this class
- RBBIStateDescriptor &operator=(const RBBIStateDescriptor &other); // forbid copying of this class
+ RBBIStateDescriptor(const RBBIStateDescriptor &other) = delete; // forbid copying of this class
+ RBBIStateDescriptor &operator=(const RBBIStateDescriptor &other) = delete; // forbid copying of this class
};
diff --git a/thirdparty/icu4c/common/resbund.cpp b/thirdparty/icu4c/common/resbund.cpp
index 47c0fe1c6e..8591a625f9 100644
--- a/thirdparty/icu4c/common/resbund.cpp
+++ b/thirdparty/icu4c/common/resbund.cpp
@@ -254,7 +254,7 @@ ResourceBundle::clone() const {
UnicodeString ResourceBundle::getString(UErrorCode& status) const {
int32_t len = 0;
const UChar *r = ures_getString(fResource, &len, &status);
- return UnicodeString(TRUE, r, len);
+ return UnicodeString(true, r, len);
}
const uint8_t *ResourceBundle::getBinary(int32_t& len, UErrorCode& status) const {
@@ -312,13 +312,13 @@ ResourceBundle ResourceBundle::getNext(UErrorCode& status) {
UnicodeString ResourceBundle::getNextString(UErrorCode& status) {
int32_t len = 0;
const UChar* r = ures_getNextString(fResource, &len, 0, &status);
- return UnicodeString(TRUE, r, len);
+ return UnicodeString(true, r, len);
}
UnicodeString ResourceBundle::getNextString(const char ** key, UErrorCode& status) {
int32_t len = 0;
const UChar* r = ures_getNextString(fResource, &len, key, &status);
- return UnicodeString(TRUE, r, len);
+ return UnicodeString(true, r, len);
}
ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
@@ -336,7 +336,7 @@ ResourceBundle ResourceBundle::get(int32_t indexR, UErrorCode& status) const {
UnicodeString ResourceBundle::getStringEx(int32_t indexS, UErrorCode& status) const {
int32_t len = 0;
const UChar* r = ures_getStringByIndex(fResource, indexS, &len, &status);
- return UnicodeString(TRUE, r, len);
+ return UnicodeString(true, r, len);
}
ResourceBundle ResourceBundle::get(const char* key, UErrorCode& status) const {
@@ -364,7 +364,7 @@ ResourceBundle ResourceBundle::getWithFallback(const char* key, UErrorCode& stat
UnicodeString ResourceBundle::getStringEx(const char* key, UErrorCode& status) const {
int32_t len = 0;
const UChar* r = ures_getStringByKey(fResource, key, &len, &status);
- return UnicodeString(TRUE, r, len);
+ return UnicodeString(true, r, len);
}
const char*
diff --git a/thirdparty/icu4c/common/resource.h b/thirdparty/icu4c/common/resource.h
index 48f5b9fa6e..1483f7d6bc 100644
--- a/thirdparty/icu4c/common/resource.h
+++ b/thirdparty/icu4c/common/resource.h
@@ -286,8 +286,8 @@ public:
UErrorCode &errorCode) = 0;
private:
- ResourceSink(const ResourceSink &); // no copy constructor
- ResourceSink &operator=(const ResourceSink &); // no assignment operator
+ ResourceSink(const ResourceSink &) = delete; // no copy constructor
+ ResourceSink &operator=(const ResourceSink &) = delete; // no assignment operator
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/ruleiter.cpp b/thirdparty/icu4c/common/ruleiter.cpp
index 41eea23c0d..33ffd3d833 100644
--- a/thirdparty/icu4c/common/ruleiter.cpp
+++ b/thirdparty/icu4c/common/ruleiter.cpp
@@ -39,7 +39,7 @@ UChar32 RuleCharacterIterator::next(int32_t options, UBool& isEscaped, UErrorCod
if (U_FAILURE(ec)) return DONE;
UChar32 c = DONE;
- isEscaped = FALSE;
+ isEscaped = false;
for (;;) {
c = _current();
@@ -75,7 +75,7 @@ UChar32 RuleCharacterIterator::next(int32_t options, UBool& isEscaped, UErrorCod
int32_t offset = 0;
c = lookahead(tempEscape, MAX_U_NOTATION_LEN).unescapeAt(offset);
jumpahead(offset);
- isEscaped = TRUE;
+ isEscaped = true;
if (c < 0) {
ec = U_MALFORMED_UNICODE_ESCAPE;
return DONE;
diff --git a/thirdparty/icu4c/common/ruleiter.h b/thirdparty/icu4c/common/ruleiter.h
index 09af129784..41731407da 100644
--- a/thirdparty/icu4c/common/ruleiter.h
+++ b/thirdparty/icu4c/common/ruleiter.h
@@ -66,28 +66,28 @@ public:
/**
* Value returned when there are no more characters to iterate.
*/
- enum { DONE = -1 };
+ static constexpr int32_t DONE = -1;
/**
* Bitmask option to enable parsing of variable names. If (options &
* PARSE_VARIABLES) != 0, then an embedded variable will be expanded to
* its value. Variables are parsed using the SymbolTable API.
*/
- enum { PARSE_VARIABLES = 1 };
+ static constexpr int32_t PARSE_VARIABLES = 1;
/**
* Bitmask option to enable parsing of escape sequences. If (options &
* PARSE_ESCAPES) != 0, then an embedded escape sequence will be expanded
* to its value. Escapes are parsed using Utility.unescapeAt().
*/
- enum { PARSE_ESCAPES = 2 };
+ static constexpr int32_t PARSE_ESCAPES = 2;
/**
* Bitmask option to enable skipping of whitespace. If (options &
* SKIP_WHITESPACE) != 0, then Pattern_White_Space characters will be silently
* skipped, as if they were not present in the input.
*/
- enum { SKIP_WHITESPACE = 4 };
+ static constexpr int32_t SKIP_WHITESPACE = 4;
/**
* Constructs an iterator over the given text, starting at the given
diff --git a/thirdparty/icu4c/common/serv.cpp b/thirdparty/icu4c/common/serv.cpp
index c26dbca1a9..9d8c04149c 100644
--- a/thirdparty/icu4c/common/serv.cpp
+++ b/thirdparty/icu4c/common/serv.cpp
@@ -64,7 +64,7 @@ ICUServiceKey::currentDescriptor(UnicodeString& result) const
UBool
ICUServiceKey::fallback()
{
- return FALSE;
+ return false;
}
UBool
@@ -249,7 +249,7 @@ public:
}
/**
- * Return TRUE if there is at least one reference to this and the
+ * Return true if there is at least one reference to this and the
* resource has not been released.
*/
UBool isShared() const {
@@ -454,11 +454,11 @@ ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUSer
UnicodeString currentDescriptor;
LocalPointer<UVector> cacheDescriptorList;
- UBool putInCache = FALSE;
+ UBool putInCache = false;
int32_t startIndex = 0;
int32_t limit = factories->size();
- UBool cacheResult = TRUE;
+ UBool cacheResult = true;
if (factory != NULL) {
for (int32_t i = 0; i < limit; ++i) {
@@ -472,7 +472,7 @@ ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUSer
status = U_ILLEGAL_ARGUMENT_ERROR;
return NULL;
}
- cacheResult = FALSE;
+ cacheResult = false;
}
do {
@@ -486,7 +486,7 @@ ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUSer
// first test of cache failed, so we'll have to update
// the cache if we eventually succeed-- that is, if we're
// going to update the cache at all.
- putInCache = TRUE;
+ putInCache = true;
int32_t index = startIndex;
while (index < limit) {
@@ -796,7 +796,7 @@ ICUService::getDisplayNames(UVector& result,
URegistryKey
ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status)
{
- return registerInstance(objToAdopt, id, TRUE, status);
+ return registerInstance(objToAdopt, id, true, status);
}
URegistryKey
@@ -864,13 +864,13 @@ UBool
ICUService::unregister(URegistryKey rkey, UErrorCode& status)
{
ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
- UBool result = FALSE;
+ UBool result = false;
if (factory != NULL && factories != NULL) {
Mutex mutex(&lock);
if (factories->removeElement(factory)) {
clearCaches();
- result = TRUE;
+ result = true;
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
delete factory;
diff --git a/thirdparty/icu4c/common/servlk.cpp b/thirdparty/icu4c/common/servlk.cpp
index 538982ca36..7021806659 100644
--- a/thirdparty/icu4c/common/servlk.cpp
+++ b/thirdparty/icu4c/common/servlk.cpp
@@ -126,24 +126,24 @@ LocaleKey::fallback() {
int x = _currentID.lastIndexOf(UNDERSCORE_CHAR);
if (x != -1) {
_currentID.remove(x); // truncate current or fallback, whichever we're pointing to
- return TRUE;
+ return true;
}
if (!_fallbackID.isBogus()) {
_currentID = _fallbackID;
_fallbackID.setToBogus();
- return TRUE;
+ return true;
}
if (_currentID.length() > 0) {
_currentID.remove(0); // completely truncate
- return TRUE;
+ return true;
}
_currentID.setToBogus();
}
- return FALSE;
+ return false;
}
UBool
diff --git a/thirdparty/icu4c/common/servlkf.cpp b/thirdparty/icu4c/common/servlkf.cpp
index 84f2347cdd..7ccb0c72aa 100644
--- a/thirdparty/icu4c/common/servlkf.cpp
+++ b/thirdparty/icu4c/common/servlkf.cpp
@@ -65,7 +65,7 @@ LocaleKeyFactory::handlesKey(const ICUServiceKey& key, UErrorCode& status) const
key.currentID(id);
return supported->get(id) != NULL;
}
- return FALSE;
+ return false;
}
void
diff --git a/thirdparty/icu4c/common/servls.cpp b/thirdparty/icu4c/common/servls.cpp
index 98f0a8a12b..19481122ef 100644
--- a/thirdparty/icu4c/common/servls.cpp
+++ b/thirdparty/icu4c/common/servls.cpp
@@ -215,11 +215,11 @@ public:
UBool upToDate(UErrorCode& status) const {
if (U_SUCCESS(status)) {
if (_timestamp == _service->getTimestamp()) {
- return TRUE;
+ return true;
}
status = U_ENUM_OUT_OF_SYNC_ERROR;
}
- return FALSE;
+ return false;
}
virtual int32_t count(UErrorCode& status) const override {
diff --git a/thirdparty/icu4c/common/sharedobject.h b/thirdparty/icu4c/common/sharedobject.h
index 6ccfb27b01..6298662bba 100644
--- a/thirdparty/icu4c/common/sharedobject.h
+++ b/thirdparty/icu4c/common/sharedobject.h
@@ -38,8 +38,8 @@ public:
virtual ~UnifiedCacheBase();
private:
- UnifiedCacheBase(const UnifiedCacheBase &);
- UnifiedCacheBase &operator=(const UnifiedCacheBase &);
+ UnifiedCacheBase(const UnifiedCacheBase &) = delete;
+ UnifiedCacheBase &operator=(const UnifiedCacheBase &) = delete;
};
/**
diff --git a/thirdparty/icu4c/common/simpleformatter.cpp b/thirdparty/icu4c/common/simpleformatter.cpp
index f7f7aead61..01d3024cfc 100644
--- a/thirdparty/icu4c/common/simpleformatter.cpp
+++ b/thirdparty/icu4c/common/simpleformatter.cpp
@@ -65,7 +65,7 @@ UBool SimpleFormatter::applyPatternMinMaxArguments(
int32_t min, int32_t max,
UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
// Parse consistent with MessagePattern, but
// - support only simple numbered arguments
@@ -76,7 +76,7 @@ UBool SimpleFormatter::applyPatternMinMaxArguments(
compiledPattern.setTo((UChar)0);
int32_t textLength = 0;
int32_t maxArg = -1;
- UBool inQuote = FALSE;
+ UBool inQuote = false;
for (int32_t i = 0; i < patternLength;) {
UChar c = patternBuffer[i++];
if (c == APOS) {
@@ -85,12 +85,12 @@ UBool SimpleFormatter::applyPatternMinMaxArguments(
++i;
} else if (inQuote) {
// skip the quote-ending apostrophe
- inQuote = FALSE;
+ inQuote = false;
continue;
} else if (c == OPEN_BRACE || c == CLOSE_BRACE) {
// Skip the quote-starting apostrophe, find the end of the quoted literal text.
++i;
- inQuote = TRUE;
+ inQuote = true;
} else {
// The apostrophe is part of literal text.
c = APOS;
@@ -123,7 +123,7 @@ UBool SimpleFormatter::applyPatternMinMaxArguments(
}
if (argNumber < 0 || c != CLOSE_BRACE) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
}
if (argNumber > maxArg) {
@@ -149,10 +149,10 @@ UBool SimpleFormatter::applyPatternMinMaxArguments(
int32_t argCount = maxArg + 1;
if (argCount < min || max < argCount) {
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
compiledPattern.setCharAt(0, (UChar)argCount);
- return TRUE;
+ return true;
}
UnicodeString& SimpleFormatter::format(
@@ -192,7 +192,7 @@ UnicodeString& SimpleFormatter::formatAndAppend(
return appendTo;
}
return format(compiledPattern.getBuffer(), compiledPattern.length(), values,
- appendTo, NULL, TRUE,
+ appendTo, NULL, true,
offsets, offsetsLength, errorCode);
}
@@ -241,7 +241,7 @@ UnicodeString &SimpleFormatter::formatAndReplace(
result.remove();
}
return format(cp, cpLength, values,
- result, &resultCopy, FALSE,
+ result, &resultCopy, false,
offsets, offsetsLength, errorCode);
}
diff --git a/thirdparty/icu4c/common/static_unicode_sets.cpp b/thirdparty/icu4c/common/static_unicode_sets.cpp
index 5dab3931a7..db9432f49a 100644
--- a/thirdparty/icu4c/common/static_unicode_sets.cpp
+++ b/thirdparty/icu4c/common/static_unicode_sets.cpp
@@ -31,7 +31,7 @@ alignas(UnicodeSet)
char gEmptyUnicodeSet[sizeof(UnicodeSet)];
// Whether the gEmptyUnicodeSet is initialized and ready to use.
-UBool gEmptyUnicodeSetInitialized = FALSE;
+UBool gEmptyUnicodeSetInitialized = false;
inline UnicodeSet* getImpl(Key key) {
UnicodeSet* candidate = gUnicodeSets[key];
@@ -118,7 +118,7 @@ class ParseDataSink : public ResourceSink {
} else {
// Unknown class of parse lenients
// TODO(ICU-20428): Make ICU automatically accept new classes?
- U_ASSERT(FALSE);
+ U_ASSERT(false);
}
if (U_FAILURE(status)) { return; }
}
@@ -129,19 +129,19 @@ class ParseDataSink : public ResourceSink {
};
-icu::UInitOnce gNumberParseUniSetsInitOnce = U_INITONCE_INITIALIZER;
+icu::UInitOnce gNumberParseUniSetsInitOnce {};
UBool U_CALLCONV cleanupNumberParseUniSets() {
if (gEmptyUnicodeSetInitialized) {
reinterpret_cast<UnicodeSet*>(gEmptyUnicodeSet)->~UnicodeSet();
- gEmptyUnicodeSetInitialized = FALSE;
+ gEmptyUnicodeSetInitialized = false;
}
for (int32_t i = 0; i < UNISETS_KEY_COUNT; i++) {
delete gUnicodeSets[i];
gUnicodeSets[i] = nullptr;
}
gNumberParseUniSetsInitOnce.reset();
- return TRUE;
+ return true;
}
void U_CALLCONV initNumberParseUniSets(UErrorCode& status) {
@@ -150,7 +150,7 @@ void U_CALLCONV initNumberParseUniSets(UErrorCode& status) {
// Initialize the empty instance for well-defined fallback behavior
new(gEmptyUnicodeSet) UnicodeSet();
reinterpret_cast<UnicodeSet*>(gEmptyUnicodeSet)->freeze();
- gEmptyUnicodeSetInitialized = TRUE;
+ gEmptyUnicodeSetInitialized = true;
// These sets were decided after discussion with icu-design@. See tickets #13084 and #13309.
// Zs+TAB is "horizontal whitespace" according to UTS #18 (blank property).
diff --git a/thirdparty/icu4c/common/stringtriebuilder.cpp b/thirdparty/icu4c/common/stringtriebuilder.cpp
index 4d52a88af7..e6670d1cb7 100644
--- a/thirdparty/icu4c/common/stringtriebuilder.cpp
+++ b/thirdparty/icu4c/common/stringtriebuilder.cpp
@@ -85,16 +85,16 @@ StringTrieBuilder::build(UStringTrieBuildOption buildOption, int32_t elementsLen
// have a common prefix of length unitIndex.
int32_t
StringTrieBuilder::writeNode(int32_t start, int32_t limit, int32_t unitIndex) {
- UBool hasValue=FALSE;
+ UBool hasValue=false;
int32_t value=0;
int32_t type;
if(unitIndex==getElementStringLength(start)) {
// An intermediate or final value.
value=getElementValue(start++);
if(start==limit) {
- return writeValueAndFinal(value, TRUE); // final-value node
+ return writeValueAndFinal(value, true); // final-value node
}
- hasValue=TRUE;
+ hasValue=true;
}
// Now all [start..limit[ strings are longer than unitIndex.
int32_t minUnit=getElementUnit(start, unitIndex);
@@ -209,7 +209,7 @@ StringTrieBuilder::makeNode(int32_t start, int32_t limit, int32_t unitIndex, UEr
if(U_FAILURE(errorCode)) {
return NULL;
}
- UBool hasValue=FALSE;
+ UBool hasValue=false;
int32_t value=0;
if(unitIndex==getElementStringLength(start)) {
// An intermediate or final value.
@@ -217,7 +217,7 @@ StringTrieBuilder::makeNode(int32_t start, int32_t limit, int32_t unitIndex, UEr
if(start==limit) {
return registerFinalValue(value, errorCode);
}
- hasValue=TRUE;
+ hasValue=true;
}
Node *node;
// Now all [start..limit[ strings are longer than unitIndex.
@@ -410,7 +410,7 @@ StringTrieBuilder::FinalValueNode::operator==(const Node &other) const {
void
StringTrieBuilder::FinalValueNode::write(StringTrieBuilder &builder) {
- offset=builder.writeValueAndFinal(value, TRUE);
+ offset=builder.writeValueAndFinal(value, true);
}
bool
@@ -448,7 +448,7 @@ StringTrieBuilder::IntermediateValueNode::markRightEdgesFirst(int32_t edgeNumber
void
StringTrieBuilder::IntermediateValueNode::write(StringTrieBuilder &builder) {
next->write(builder);
- offset=builder.writeValueAndFinal(value, FALSE);
+ offset=builder.writeValueAndFinal(value, false);
}
bool
@@ -526,7 +526,7 @@ StringTrieBuilder::ListBranchNode::write(StringTrieBuilder &builder) {
// not jump for it at all.
unitNumber=length-1;
if(rightEdge==NULL) {
- builder.writeValueAndFinal(values[unitNumber], TRUE);
+ builder.writeValueAndFinal(values[unitNumber], true);
} else {
rightEdge->write(builder);
}
@@ -538,12 +538,12 @@ StringTrieBuilder::ListBranchNode::write(StringTrieBuilder &builder) {
if(equal[unitNumber]==NULL) {
// Write the final value for the one string ending with this unit.
value=values[unitNumber];
- isFinal=TRUE;
+ isFinal=true;
} else {
// Write the delta to the start position of the sub-node.
U_ASSERT(equal[unitNumber]->getOffset()>0);
value=offset-equal[unitNumber]->getOffset();
- isFinal=FALSE;
+ isFinal=false;
}
builder.writeValueAndFinal(value, isFinal);
offset=builder.write(units[unitNumber]);
diff --git a/thirdparty/icu4c/common/uarrsort.cpp b/thirdparty/icu4c/common/uarrsort.cpp
index c17dbb2e2b..17b6964ffe 100644
--- a/thirdparty/icu4c/common/uarrsort.cpp
+++ b/thirdparty/icu4c/common/uarrsort.cpp
@@ -75,7 +75,7 @@ U_CAPI int32_t U_EXPORT2
uprv_stableBinarySearch(char *array, int32_t limit, void *item, int32_t itemSize,
UComparator *cmp, const void *context) {
int32_t start=0;
- UBool found=FALSE;
+ UBool found=false;
/* Binary search until we get down to a tiny sub-array. */
while((limit-start)>=MIN_QSORT) {
@@ -90,10 +90,10 @@ uprv_stableBinarySearch(char *array, int32_t limit, void *item, int32_t itemSize
* However, if there are many equal items, then it should be
* faster to continue with the binary search.
* It seems likely that we either have all unique items
- * (where found will never become TRUE in the insertion sort)
+ * (where found will never become true in the insertion sort)
* or potentially many duplicates.
*/
- found=TRUE;
+ found=true;
start=i+1;
} else if(diff<0) {
limit=i;
@@ -106,7 +106,7 @@ uprv_stableBinarySearch(char *array, int32_t limit, void *item, int32_t itemSize
while(start<limit) {
int32_t diff=cmp(context, item, array+start*itemSize);
if(diff==0) {
- found=TRUE;
+ found=true;
} else if(diff<0) {
break;
}
diff --git a/thirdparty/icu4c/common/ubidi.cpp b/thirdparty/icu4c/common/ubidi.cpp
index 6d27827c50..eb40a212e1 100644
--- a/thirdparty/icu4c/common/ubidi.cpp
+++ b/thirdparty/icu4c/common/ubidi.cpp
@@ -149,7 +149,7 @@ ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode)
return NULL;
}
- /* reset the object, all pointers NULL, all flags FALSE, all sizes 0 */
+ /* reset the object, all pointers NULL, all flags false, all sizes 0 */
uprv_memset(pBiDi, 0, sizeof(UBiDi));
/* allocate memory for arrays as requested */
@@ -160,7 +160,7 @@ ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode)
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
}
} else {
- pBiDi->mayAllocateText=TRUE;
+ pBiDi->mayAllocateText=true;
}
if(maxRunCount>0) {
@@ -171,7 +171,7 @@ ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode)
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
}
} else {
- pBiDi->mayAllocateRuns=TRUE;
+ pBiDi->mayAllocateRuns=true;
}
if(U_SUCCESS(*pErrorCode)) {
@@ -184,7 +184,7 @@ ubidi_openSized(int32_t maxLength, int32_t maxRunCount, UErrorCode *pErrorCode)
/*
* We are allowed to allocate memory if memory==NULL or
- * mayAllocate==TRUE for each array that we need.
+ * mayAllocate==true for each array that we need.
* We also try to grow memory as needed if we
* allocate it.
*
@@ -203,18 +203,18 @@ ubidi_getMemory(BidiMemoryForAllocation *bidiMem, int32_t *pSize, UBool mayAlloc
/* we need to allocate memory */
if(mayAllocate && (*pMemory=uprv_malloc(sizeNeeded))!=NULL) {
*pSize=sizeNeeded;
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
} else {
if(sizeNeeded<=*pSize) {
/* there is already enough memory */
- return TRUE;
+ return true;
}
else if(!mayAllocate) {
/* not enough memory, and we must not allocate */
- return FALSE;
+ return false;
} else {
/* we try to grow */
void *memory;
@@ -225,10 +225,10 @@ ubidi_getMemory(BidiMemoryForAllocation *bidiMem, int32_t *pSize, UBool mayAlloc
if((memory=uprv_realloc(*pMemory, sizeNeeded))!=NULL) {
*pMemory=memory;
*pSize=sizeNeeded;
- return TRUE;
+ return true;
} else {
/* we failed to grow */
- return FALSE;
+ return false;
}
}
}
@@ -280,7 +280,7 @@ ubidi_isInverse(UBiDi *pBiDi) {
if(pBiDi!=NULL) {
return pBiDi->isInverse;
} else {
- return FALSE;
+ return false;
}
}
@@ -403,17 +403,17 @@ checkParaCount(UBiDi *pBiDi) {
int32_t count=pBiDi->paraCount;
if(pBiDi->paras==pBiDi->simpleParas) {
if(count<=SIMPLE_PARAS_COUNT)
- return TRUE;
+ return true;
if(!getInitialParasMemory(pBiDi, SIMPLE_PARAS_COUNT * 2))
- return FALSE;
+ return false;
pBiDi->paras=pBiDi->parasMemory;
uprv_memcpy(pBiDi->parasMemory, pBiDi->simpleParas, SIMPLE_PARAS_COUNT * sizeof(Para));
- return TRUE;
+ return true;
}
if(!getInitialParasMemory(pBiDi, count * 2))
- return FALSE;
+ return false;
pBiDi->paras=pBiDi->parasMemory;
- return TRUE;
+ return true;
}
/*
@@ -579,8 +579,8 @@ getDirProps(UBiDi *pBiDi) {
}
if(i<originalLength) { /* B not last char in text */
pBiDi->paraCount++;
- if(checkParaCount(pBiDi)==FALSE) /* not enough memory for a new para entry */
- return FALSE;
+ if(checkParaCount(pBiDi)==false) /* not enough memory for a new para entry */
+ return false;
if(isDefaultLevel) {
pBiDi->paras[pBiDi->paraCount-1].level=defaultParaLevel;
state=SEEKING_STRONG_FOR_PARA;
@@ -636,7 +636,7 @@ getDirProps(UBiDi *pBiDi) {
}
pBiDi->flags=flags;
pBiDi->lastArabicPos=lastArabicPos;
- return TRUE;
+ return true;
}
/* determine the paragraph level at position index */
@@ -743,14 +743,14 @@ bracketProcessPDI(BracketData *bd) {
}
/* newly found opening bracket: create an openings entry */
-static UBool /* return TRUE if success */
+static UBool /* return true if success */
bracketAddOpening(BracketData *bd, UChar match, int32_t position) {
IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
Opening *pOpening;
if(pLastIsoRun->limit>=bd->openingsCount) { /* no available new entry */
UBiDi *pBiDi=bd->pBiDi;
if(!getInitialOpeningsMemory(pBiDi, pLastIsoRun->limit * 2))
- return FALSE;
+ return false;
if(bd->openings==bd->simpleOpenings)
uprv_memcpy(pBiDi->openingsMemory, bd->simpleOpenings,
SIMPLE_OPENINGS_COUNT * sizeof(Opening));
@@ -764,7 +764,7 @@ bracketAddOpening(BracketData *bd, UChar match, int32_t position) {
pOpening->contextPos=pLastIsoRun->contextPos;
pOpening->flags=0;
pLastIsoRun->limit++;
- return TRUE;
+ return true;
}
/* change N0c1 to N0c2 when a preceding bracket is assigned the embedding level */
@@ -804,7 +804,7 @@ bracketProcessClosing(BracketData *bd, int32_t openIdx, int32_t position) {
DirProp newProp;
pOpening=&bd->openings[openIdx];
direction=(UBiDiDirection)(pLastIsoRun->level&1);
- stable=TRUE; /* assume stable until proved otherwise */
+ stable=true; /* assume stable until proved otherwise */
/* The stable flag is set when brackets are paired and their
level is resolved and cannot be changed by what will be
@@ -873,7 +873,7 @@ bracketProcessClosing(BracketData *bd, int32_t openIdx, int32_t position) {
}
/* handle strong characters, digits and candidates for closing brackets */
-static UBool /* return TRUE if success */
+static UBool /* return true if success */
bracketProcessChar(BracketData *bd, int32_t position) {
IsoRun *pLastIsoRun=&bd->isoRuns[bd->isoRunLast];
DirProp *dirProps, dirProp, newProp;
@@ -912,7 +912,7 @@ bracketProcessChar(BracketData *bd, int32_t position) {
}
/* matching brackets are not overridden by LRO/RLO */
bd->pBiDi->levels[bd->openings[idx].position]&=~UBIDI_LEVEL_OVERRIDE;
- return TRUE;
+ return true;
}
/* We get here only if the ON character is not a matching closing
bracket or it is a case of N0d */
@@ -927,14 +927,14 @@ bracketProcessChar(BracketData *bd, int32_t position) {
create an opening entry for each synonym */
if(match==0x232A) { /* RIGHT-POINTING ANGLE BRACKET */
if(!bracketAddOpening(bd, 0x3009, position))
- return FALSE;
+ return false;
}
else if(match==0x3009) { /* RIGHT ANGLE BRACKET */
if(!bracketAddOpening(bd, 0x232A, position))
- return FALSE;
+ return false;
}
if(!bracketAddOpening(bd, match, position))
- return FALSE;
+ return false;
}
}
level=bd->pBiDi->levels[position];
@@ -998,7 +998,7 @@ bracketProcessChar(BracketData *bd, int32_t position) {
if(position>bd->openings[i].position)
bd->openings[i].flags|=flag;
}
- return TRUE;
+ return true;
}
/* perform (X1)..(X9) ------------------------------------------------------- */
@@ -2432,11 +2432,11 @@ setParaRunsOnly(UBiDi *pBiDi, const UChar *text, int32_t length,
* than the original text. But we don't want the levels memory to be
* reallocated shorter than the original length, since we need to restore
* the levels as after the first call to ubidi_setpara() before returning.
- * We will force mayAllocateText to FALSE before the second call to
+ * We will force mayAllocateText to false before the second call to
* ubidi_setpara(), and will restore it afterwards.
*/
saveMayAllocateText=pBiDi->mayAllocateText;
- pBiDi->mayAllocateText=FALSE;
+ pBiDi->mayAllocateText=false;
ubidi_setPara(pBiDi, visualText, visualLength, paraLevel, NULL, pErrorCode);
pBiDi->mayAllocateText=saveMayAllocateText;
ubidi_getRuns(pBiDi, pErrorCode);
@@ -2866,7 +2866,7 @@ ubidi_isOrderParagraphsLTR(UBiDi *pBiDi) {
if(pBiDi!=NULL) {
return pBiDi->orderParagraphsLTR;
} else {
- return FALSE;
+ return false;
}
}
diff --git a/thirdparty/icu4c/common/ubidi_props.cpp b/thirdparty/icu4c/common/ubidi_props.cpp
index afcc4aaf4f..3ba58f7af9 100644
--- a/thirdparty/icu4c/common/ubidi_props.cpp
+++ b/thirdparty/icu4c/common/ubidi_props.cpp
@@ -53,7 +53,7 @@ _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32
/* add the start code point to the USet */
const USetAdder *sa=(const USetAdder *)context;
sa->add(sa->set, start);
- return TRUE;
+ return true;
}
U_CFUNC void
diff --git a/thirdparty/icu4c/common/ubidi_props_data.h b/thirdparty/icu4c/common/ubidi_props_data.h
index aad919fa2e..01fcc968cb 100644
--- a/thirdparty/icu4c/common/ubidi_props_data.h
+++ b/thirdparty/icu4c/common/ubidi_props_data.h
@@ -9,11 +9,11 @@
#ifdef INCLUDED_FROM_UBIDI_PROPS_C
-static const UVersionInfo ubidi_props_dataVersion={0xe,0,0,0};
+static const UVersionInfo ubidi_props_dataVersion={0xf,0,0,0};
-static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x6a98,0x64a8,0x28,0x620,0x8cc,0x10ac0,0x10d24,0,0,0,0,0,0,0,0x6702b6};
+static const int32_t ubidi_props_indexes[UBIDI_IX_TOP]={0x10,0x6bc0,0x65d0,0x28,0x620,0x8cc,0x10ac0,0x10d24,0,0,0,0,0,0,0,0x6702b6};
-static const uint16_t ubidi_props_trieIndex[12876]={
+static const uint16_t ubidi_props_trieIndex[13024]={
0x387,0x38f,0x397,0x39f,0x3b7,0x3bf,0x3c7,0x3cf,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af,
0x3a7,0x3af,0x3a7,0x3af,0x3d5,0x3dd,0x3e5,0x3ed,0x3f5,0x3fd,0x3f9,0x401,0x409,0x411,0x40c,0x414,
0x3a7,0x3af,0x3a7,0x3af,0x41c,0x424,0x3a7,0x3af,0x3a7,0x3af,0x3a7,0x3af,0x42a,0x432,0x43a,0x442,
@@ -185,61 +185,61 @@ static const uint16_t ubidi_props_trieIndex[12876]={
0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9a6,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,
0x9ae,0x9b2,0x43c,0x43c,0x43c,0x43c,0x9c2,0x9ba,0x43c,0x9ca,0x43c,0x43c,0x9d2,0x9d8,0x43c,0x43c,
0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x9e8,0x9e0,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,
-0x43c,0x43c,0x43c,0x9f0,0x43c,0x9f8,0x43c,0x43c,0x43c,0x9fc,0xa03,0xa09,0xa11,0xa15,0xa1d,0x43c,
-0x51b,0xa25,0xa2c,0xa33,0x41e,0xa3b,0x569,0x3a7,0x501,0xa42,0x3a7,0xa48,0x41e,0xa4d,0xa55,0x3a7,
-0x3a7,0xa5a,0x3a7,0x3a7,0x3a7,0x3a7,0x836,0xa62,0x41e,0x5a3,0x57e,0xa69,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0xa25,0xa71,0x3a7,0x3a7,0xa79,0xa81,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa85,0xa8d,0x3a7,
-0x3a7,0xa95,0x57e,0xa9d,0x3a7,0xaa3,0x3a7,0x3a7,0x60f,0xaab,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0xab0,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xab7,0xabf,0x3a7,0x3a7,0x3a7,0xac2,0x57e,0xaca,
-0xace,0xad6,0x3a7,0xadd,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0xae4,0x3a7,0x3a7,0xaf2,0xaec,0x3a7,0x3a7,0x3a7,0xafa,0xb02,0x3a7,0xb06,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x5a5,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb13,0xb0e,0x3a7,
+0x43c,0x43c,0x43c,0x9f0,0x43c,0x9f8,0x4a6,0xa00,0x43c,0xa08,0xa0f,0xa15,0xa1d,0xa21,0xa29,0x43c,
+0x51b,0xa31,0xa38,0xa3f,0x41e,0xa47,0x569,0x3a7,0x501,0xa4e,0x3a7,0xa54,0x41e,0xa59,0xa61,0x3a7,
+0x3a7,0xa66,0x51b,0x3a7,0x3a7,0x3a7,0x836,0xa6e,0x41e,0x5a3,0x57e,0xa75,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0xa31,0xa7d,0x3a7,0x3a7,0xa85,0xa8d,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa91,0xa99,0x3a7,
+0x3a7,0xaa1,0x57e,0xaa9,0x3a7,0xaaf,0x3a7,0x3a7,0x60f,0xab7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0xabc,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xac3,0xacb,0x3a7,0x3a7,0x3a7,0xace,0x57e,0xad6,
+0xada,0xae2,0x3a7,0xae9,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0xaf0,0x3a7,0x3a7,0xafe,0xaf8,0x3a7,0x3a7,0x3a7,0xb06,0xb0e,0x3a7,0xb12,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x5a5,0x41e,0x99e,0xb1a,0x3a7,0x3a7,0x3a7,0xb27,0xb22,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0xb1b,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb22,
-0x3a7,0xb28,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0xb2f,0xb37,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb3d,
+0x3a7,0xb43,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0xa49,0x3a7,0xb2e,0x3a7,0x3a7,0xb36,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0xa55,0x3a7,0xb49,0x3a7,0x3a7,0xb51,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x535,0xb3e,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x535,0xb59,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xb46,0x500,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0xb4e,0xb56,0xb5c,0x3a7,0xb62,0x67c,0x67c,0xb6a,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x67c,0x67c,0xb72,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb78,
-0x3a7,0xb7f,0x3a7,0xb7b,0x3a7,0xb82,0x3a7,0xb8a,0xb8e,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xb96,0x3f5,0xb9d,0xba4,0xbac,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xb61,0x500,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0xb69,0xb71,0xb77,0x3a7,0xb7d,0x67c,0x67c,0xb85,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x67c,0x67c,0xb8d,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xb93,
+0x3a7,0xb9a,0x3a7,0xb96,0x3a7,0xb9d,0x3a7,0xba5,0xba9,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3f5,0xbb1,0x3f5,0xbb8,0xbbf,0xbc7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xbb4,0xbbc,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0xb28,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa75,0x3a7,
-0xbc1,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0xbc9,
-0x43c,0xbd1,0xbd1,0xbd8,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xbcf,0xbd7,0x3a7,0x3a7,0xa55,0x3a7,0x3a7,
+0x3a7,0x3a7,0xb43,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xa81,0x3a7,
+0xbdc,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0xbe4,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0xbec,
+0x43c,0xbf4,0xbf4,0xbfb,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,
0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x91e,0x4a6,0x4a6,0x43c,
-0x43c,0x4a6,0x4a6,0xbe0,0x43c,0x43c,0x43c,0x43c,0x43c,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,
-0xbe8,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x67c,0xbf0,0x67c,0x67c,0x67f,0xbf5,0xbf9,
-0x858,0xc01,0x3c9,0x3a7,0xc07,0x3a7,0xc0c,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x783,0x3a7,0x3a7,0x3a7,
+0x43c,0x4a6,0x4a6,0xc03,0x43c,0x43c,0x43c,0x43c,0x43c,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,0x4a6,
+0xc0b,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x43c,0x67c,0xc13,0x67c,0x67c,0x67f,0xc18,0xc1c,
+0x858,0xc24,0x3c9,0x3a7,0xc2a,0x3a7,0xc2f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x783,0x3a7,0x3a7,0x3a7,
0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,
-0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0xc14,
-0x98f,0x67c,0x67c,0x67c,0x67f,0x67c,0x67c,0xc1c,0xc24,0xbf0,0x67c,0xc2c,0x67c,0xc34,0xc39,0x3a7,
-0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67f,0xc41,0xc4d,0xc52,0xc5a,
-0xc49,0x67c,0x67c,0x67c,0x67c,0xc62,0x67c,0x792,0xc6a,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0xc37,
+0x98f,0x67c,0x67c,0x67c,0xc3e,0x67c,0x67c,0xc45,0xc4d,0xc13,0x67c,0xc55,0x67c,0xc5d,0xc62,0x3a7,
+0x3a7,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67c,0x67f,0xc6a,0xc73,0xc77,0xc7f,
+0xc6f,0x67c,0x67c,0x67c,0x67c,0xc87,0x67c,0x792,0xc8f,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc71,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc96,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,
-0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc71,0xc81,0xc79,0xc79,0xc79,0xc82,0xc82,0xc82,
-0xc82,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0xc8a,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,
-0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,
-0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,
-0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,
-0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0xc82,0x386,0x386,0x386,0x12,0x12,0x12,0x12,
+0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0x3a7,0xc96,0xca6,0xc9e,0xc9e,0xc9e,0xca7,0xca7,0xca7,
+0xca7,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0x3f5,0xcaf,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,
+0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,
+0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,
+0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,
+0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0xca7,0x386,0x386,0x386,0x12,0x12,0x12,0x12,
0x12,0x12,0x12,0x12,0x12,8,7,8,9,7,0x12,0x12,0x12,0x12,0x12,0x12,
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,7,7,7,8,9,0xa,0xa,4,
4,4,0xa,0xa,0x310a,0xf20a,0xa,3,6,3,6,6,2,2,2,2,
@@ -384,7 +384,7 @@ static const uint16_t ubidi_props_trieIndex[12876]={
0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
0xb1,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0xb1,0,0xb1,0,0xb1,0x310a,0xf20a,0x310a,0xf20a,0,0,
@@ -654,6 +654,9 @@ static const uint16_t ubidi_props_trieIndex[12876]={
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,1,
1,1,1,1,1,1,1,1,1,1,1,0xb1,0xb1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xb1,0xb1,0xb1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0x4d,0x4d,0x4d,0x8d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,0x4d,
0x4d,0xd,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0x4d,0x4d,0x4d,
0x8d,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
@@ -721,104 +724,110 @@ static const uint16_t ubidi_props_trieIndex[12876]={
0,0,0xb1,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0xb1,0xb1,0,0,0,0xb1,0,0xb1,
+0,0,0,0,0,0,0,0,0xb1,0,0xb1,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,4,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,4,4,4,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0xa0,0xa0,0xa0,0xa0,
-0xa0,0xa0,0xa0,0xa0,0xa0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,
+0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xb1,0,0,0,
+0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0xa,0,0xb1,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0xa,0,0xb1,0,0,0,
+0,0,0,0,0xb2,0xb2,0xb2,0xb2,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0,0,0,0,
+0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0,0,
+0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0xb1,
-0xb1,0xb1,0,0,0,0,0,0,0,0,0,0xb2,0xb2,0xb2,0xb2,0xb2,
-0xb2,0xb2,0xb2,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,
+0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xa,0xa,0xb1,0xb1,0xb1,0xa,0,0,
+0,0,0,0,0xa,0xa,0xb1,0xb1,0xb1,0xa,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0x100a,0,0,0,0,
+0,0,0,0,0,0,0,0x100a,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x100a,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0x100a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0x100a,0,0,0,0,
-0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,
+0,0,0,0,0,0,0,0x100a,0,0,0,0,0,0,0,0,
+0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,
-0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0,0,0,0,0,0,0,0,0xb1,0,0,0,0,0,0,
-0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,
-0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,
+2,2,2,2,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,
+0,0,0,0,0,0xb1,0,0,0,0,0,0,0,0,0,0,
+0xb1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0,0xb1,
+0xb1,0,0xb1,0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0xb1,0xb1,0xb1,0xb1,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0xb1,0xb1,0xb1,0xb1,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,4,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,
-1,1,1,1,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
-0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
-0x41,0x41,0x41,0x41,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
-0xa,0xa,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,2,2,2,2,2,2,2,2,2,2,2,0xa,
-0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0xa,0,0,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,1,1,1,1,1,1,1,1,1,
+0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
+0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xa1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,0xd,0xd,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa,0xd,0xd,
+0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xd,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+2,2,2,2,2,2,2,2,2,2,2,0xa,0xa,0xa,0xa,0xa,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0xa,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,
0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
-0xa,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0,0,0xa,0xa,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,
-0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
-0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,
+0,0,0,0,0xa,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,
-0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,
-2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0,0,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0,0,0,0,0,0,0,0,0xa,0xa,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,0xa,0xa,0xa,0xa,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,
+0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0xa,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,
+2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0x12,0x12,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
+0,0,0,0,0,0,0x12,0x12,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,
-0xb2,0xb2,0xb2,0xb2,0x12,0xb2,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
+0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0xb2,0x12,0xb2,0x12,0x12,0x12,0x12,0x12,0x12,
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
-0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
-0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0,0,0
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0x12,0x12,0x12,0x12,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0,0,0,0
};
static const uint32_t ubidi_props_mirrors[40]={
@@ -926,14 +935,14 @@ static const UBiDiProps ubidi_props_singleton={
ubidi_props_trieIndex+3612,
NULL,
3612,
- 9264,
+ 9412,
0x1a0,
0xe9c,
0x0,
0x0,
0x110000,
- 0x3248,
- NULL, 0, FALSE, FALSE, 0, NULL
+ 0x32dc,
+ NULL, 0, false, false, 0, NULL
},
{ 2,2,0,0 }
};
diff --git a/thirdparty/icu4c/common/ubidiln.cpp b/thirdparty/icu4c/common/ubidiln.cpp
index fea239380a..430ece39d2 100644
--- a/thirdparty/icu4c/common/ubidiln.cpp
+++ b/thirdparty/icu4c/common/ubidiln.cpp
@@ -101,7 +101,7 @@ setTrailingWSStart(UBiDi *pBiDi) {
are already set to paragraph level.
Setting trailingWSStart to pBidi->length will avoid changing the
level of B chars from 0 to paraLevel in ubidi_getLevels when
- orderParagraphsLTR==TRUE.
+ orderParagraphsLTR==true.
*/
if(dirProps[start-1]==B) {
pBiDi->trailingWSStart=start; /* currently == pBiDi->length */
@@ -535,7 +535,7 @@ static int32_t getRunFromLogicalIndex(UBiDi *pBiDi, int32_t logicalIndex) {
/*
* Compute the runs array from the levels array.
- * After ubidi_getRuns() returns TRUE, runCount is guaranteed to be >0
+ * After ubidi_getRuns() returns true, runCount is guaranteed to be >0
* and the runs are reordered.
* Odd-level runs have visualStart on their visual right edge and
* they progress visually to the left.
@@ -551,7 +551,7 @@ ubidi_getRuns(UBiDi *pBiDi, UErrorCode*) {
* includes the case of length==0 (handled in setPara)..
*/
if (pBiDi->runCount>=0) {
- return TRUE;
+ return true;
}
if(pBiDi->direction!=UBIDI_MIXED) {
@@ -608,7 +608,7 @@ ubidi_getRuns(UBiDi *pBiDi, UErrorCode*) {
if(getRunsMemory(pBiDi, runCount)) {
runs=pBiDi->runsMemory;
} else {
- return FALSE;
+ return false;
}
/* set the runs */
@@ -703,7 +703,7 @@ ubidi_getRuns(UBiDi *pBiDi, UErrorCode*) {
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -714,7 +714,7 @@ prepareReorder(const UBiDiLevel *levels, int32_t length,
UBiDiLevel level, minLevel, maxLevel;
if(levels==NULL || length<=0) {
- return FALSE;
+ return false;
}
/* determine minLevel and maxLevel */
@@ -723,7 +723,7 @@ prepareReorder(const UBiDiLevel *levels, int32_t length,
for(start=length; start>0;) {
level=levels[--start];
if(level>UBIDI_MAX_EXPLICIT_LEVEL+1) {
- return FALSE;
+ return false;
}
if(level<minLevel) {
minLevel=level;
@@ -741,7 +741,7 @@ prepareReorder(const UBiDiLevel *levels, int32_t length,
indexMap[start]=start;
}
- return TRUE;
+ return true;
}
/* reorder a line based on a levels array (L2) ------------------------------ */
diff --git a/thirdparty/icu4c/common/ubiditransform.cpp b/thirdparty/icu4c/common/ubiditransform.cpp
index d56bf1518b..24fffd9c46 100644
--- a/thirdparty/icu4c/common/ubiditransform.cpp
+++ b/thirdparty/icu4c/common/ubiditransform.cpp
@@ -130,7 +130,7 @@ action_resolve(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
ubidi_setPara(pTransform->pBidi, pTransform->src, pTransform->srcLength,
pTransform->pActiveScheme->baseLevel, NULL, pErrorCode);
- return FALSE;
+ return false;
}
/**
@@ -150,7 +150,7 @@ action_reorder(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
*pTransform->pDestLength = pTransform->srcLength;
pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
- return TRUE;
+ return true;
}
/**
@@ -166,9 +166,9 @@ static UBool
action_setInverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
(void)pErrorCode;
- ubidi_setInverse(pTransform->pBidi, TRUE);
+ ubidi_setInverse(pTransform->pBidi, true);
ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_INVERSE_LIKE_DIRECT);
- return FALSE;
+ return false;
}
/**
@@ -186,7 +186,7 @@ action_setRunsOnly(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
(void)pErrorCode;
ubidi_setReorderingMode(pTransform->pBidi, UBIDI_REORDER_RUNS_ONLY);
- return FALSE;
+ return false;
}
/**
@@ -205,7 +205,7 @@ action_reverse(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
pTransform->dest, pTransform->destSize,
UBIDI_REORDER_DEFAULT, pErrorCode);
*pTransform->pDestLength = pTransform->srcLength;
- return TRUE;
+ return true;
}
/**
@@ -274,7 +274,7 @@ static UBool
action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
{
if ((pTransform->letters | pTransform->digits) == 0) {
- return FALSE;
+ return false;
}
if (pTransform->pActiveScheme->lettersDir == pTransform->pActiveScheme->digitsDir) {
doShape(pTransform, pTransform->letters | pTransform->digits | pTransform->pActiveScheme->lettersDir,
@@ -288,7 +288,7 @@ action_shapeArabic(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
pErrorCode);
}
}
- return TRUE;
+ return true;
}
/**
@@ -306,11 +306,11 @@ action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
UChar32 c;
uint32_t i = 0, j = 0;
if (0 == (pTransform->reorderingOptions & UBIDI_DO_MIRRORING)) {
- return FALSE;
+ return false;
}
if (pTransform->destSize < pTransform->srcLength) {
*pErrorCode = U_BUFFER_OVERFLOW_ERROR;
- return FALSE;
+ return false;
}
do {
UBool isOdd = ubidi_getLevelAt(pTransform->pBidi, i) & 1;
@@ -320,7 +320,7 @@ action_mirror(UBiDiTransform *pTransform, UErrorCode *pErrorCode)
*pTransform->pDestLength = pTransform->srcLength;
pTransform->reorderingOptions = UBIDI_REORDER_DEFAULT;
- return TRUE;
+ return true;
}
/**
@@ -444,7 +444,7 @@ ubiditransform_transform(UBiDiTransform *pBiDiTransform,
UErrorCode *pErrorCode)
{
uint32_t destLength = 0;
- UBool textChanged = FALSE;
+ UBool textChanged = false;
const UBiDiTransform *pOrigTransform = pBiDiTransform;
const UBiDiAction *action = NULL;
@@ -503,10 +503,10 @@ ubiditransform_transform(UBiDiTransform *pBiDiTransform,
updateSrc(pBiDiTransform, pBiDiTransform->dest, *pBiDiTransform->pDestLength,
*pBiDiTransform->pDestLength, pErrorCode);
}
- textChanged = TRUE;
+ textChanged = true;
}
}
- ubidi_setInverse(pBiDiTransform->pBidi, FALSE);
+ ubidi_setInverse(pBiDiTransform->pBidi, false);
if (!textChanged && U_SUCCESS(*pErrorCode)) {
/* Text was not changed - just copy src to dest */
diff --git a/thirdparty/icu4c/common/ucase.cpp b/thirdparty/icu4c/common/ucase.cpp
index 388c86b1bb..3d1750265b 100644
--- a/thirdparty/icu4c/common/ucase.cpp
+++ b/thirdparty/icu4c/common/ucase.cpp
@@ -40,7 +40,7 @@ _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 /*end*/, ui
/* add the start code point to the USet */
const USetAdder *sa=(const USetAdder *)context;
sa->add(sa->set, start);
- return TRUE;
+ return true;
}
U_CFUNC void U_EXPORT2
@@ -354,7 +354,7 @@ ucase_addStringCaseClosure(const UChar *s, int32_t length, const USetAdder *sa)
int32_t i, start, limit, result, unfoldRows, unfoldRowWidth, unfoldStringWidth;
if(ucase_props_singleton.unfold==NULL || s==NULL) {
- return FALSE; /* no reverse case folding data, or no string */
+ return false; /* no reverse case folding data, or no string */
}
if(length<=1) {
/* the string is too short to find any match */
@@ -364,7 +364,7 @@ ucase_addStringCaseClosure(const UChar *s, int32_t length, const USetAdder *sa)
* but this does not make much practical difference because
* a single supplementary code point would just not be found
*/
- return FALSE;
+ return false;
}
const uint16_t *unfold=ucase_props_singleton.unfold;
@@ -375,7 +375,7 @@ ucase_addStringCaseClosure(const UChar *s, int32_t length, const USetAdder *sa)
if(length>unfoldStringWidth) {
/* the string is too long to find any match */
- return FALSE;
+ return false;
}
/* do a binary search for the string */
@@ -395,7 +395,7 @@ ucase_addStringCaseClosure(const UChar *s, int32_t length, const USetAdder *sa)
sa->add(sa->set, c);
ucase_addCaseClosure(c, sa);
}
- return TRUE;
+ return true;
} else if(result<0) {
limit=i;
} else /* result>0 */ {
@@ -403,7 +403,7 @@ ucase_addStringCaseClosure(const UChar *s, int32_t length, const USetAdder *sa)
}
}
- return FALSE; /* string not found */
+ return false; /* string not found */
}
U_NAMESPACE_BEGIN
@@ -431,7 +431,7 @@ FullCaseFoldingIterator::next(UnicodeString &full) {
// Set "full" to the NUL-terminated string in the first unfold column.
int32_t length=unfoldStringWidth;
while(length>0 && p[length-1]==0) { --length; }
- full.setTo(FALSE, p, length);
+ full.setTo(false, p, length);
// Return the code point.
UChar32 c;
U16_NEXT_UNSAFE(p, rowCpIndex, c);
@@ -905,7 +905,7 @@ isFollowedByCasedLetter(UCaseContextIterator *iter, void *context, int8_t dir) {
UChar32 c;
if(iter==NULL) {
- return FALSE;
+ return false;
}
for(/* dir!=0 sets direction */; (c=iter(context, dir))>=0; dir=0) {
@@ -913,13 +913,13 @@ isFollowedByCasedLetter(UCaseContextIterator *iter, void *context, int8_t dir) {
if(type&4) {
/* case-ignorable, continue with the loop */
} else if(type!=UCASE_NONE) {
- return TRUE; /* followed by cased letter */
+ return true; /* followed by cased letter */
} else {
- return FALSE; /* uncased and not case-ignorable */
+ return false; /* uncased and not case-ignorable */
}
}
- return FALSE; /* not followed by cased letter */
+ return false; /* not followed by cased letter */
}
/* Is preceded by Soft_Dotted character with no intervening cc=230 ? */
@@ -930,19 +930,19 @@ isPrecededBySoftDotted(UCaseContextIterator *iter, void *context) {
int8_t dir;
if(iter==NULL) {
- return FALSE;
+ return false;
}
for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
dotType=getDotType(c);
if(dotType==UCASE_SOFT_DOTTED) {
- return TRUE; /* preceded by TYPE_i */
+ return true; /* preceded by TYPE_i */
} else if(dotType!=UCASE_OTHER_ACCENT) {
- return FALSE; /* preceded by different base character (not TYPE_i), or intervening cc==230 */
+ return false; /* preceded by different base character (not TYPE_i), or intervening cc==230 */
}
}
- return FALSE; /* not preceded by TYPE_i */
+ return false; /* not preceded by TYPE_i */
}
/*
@@ -987,20 +987,20 @@ isPrecededBy_I(UCaseContextIterator *iter, void *context) {
int8_t dir;
if(iter==NULL) {
- return FALSE;
+ return false;
}
for(dir=-1; (c=iter(context, dir))>=0; dir=0) {
if(c==0x49) {
- return TRUE; /* preceded by I */
+ return true; /* preceded by I */
}
dotType=getDotType(c);
if(dotType!=UCASE_OTHER_ACCENT) {
- return FALSE; /* preceded by different base character (not I), or intervening cc==230 */
+ return false; /* preceded by different base character (not I), or intervening cc==230 */
}
}
- return FALSE; /* not preceded by I */
+ return false; /* not preceded by I */
}
/* Is followed by one or more cc==230 ? */
@@ -1011,19 +1011,19 @@ isFollowedByMoreAbove(UCaseContextIterator *iter, void *context) {
int8_t dir;
if(iter==NULL) {
- return FALSE;
+ return false;
}
for(dir=1; (c=iter(context, dir))>=0; dir=0) {
dotType=getDotType(c);
if(dotType==UCASE_ABOVE) {
- return TRUE; /* at least one cc==230 following */
+ return true; /* at least one cc==230 following */
} else if(dotType!=UCASE_OTHER_ACCENT) {
- return FALSE; /* next base character, no more cc==230 following */
+ return false; /* next base character, no more cc==230 following */
}
}
- return FALSE; /* no more cc==230 following */
+ return false; /* no more cc==230 following */
}
/* Is followed by a dot above (without cc==230 in between) ? */
@@ -1034,20 +1034,20 @@ isFollowedByDotAbove(UCaseContextIterator *iter, void *context) {
int8_t dir;
if(iter==NULL) {
- return FALSE;
+ return false;
}
for(dir=1; (c=iter(context, dir))>=0; dir=0) {
if(c==0x307) {
- return TRUE;
+ return true;
}
dotType=getDotType(c);
if(dotType!=UCASE_OTHER_ACCENT) {
- return FALSE; /* next base character or cc==230 in between */
+ return false; /* next base character or cc==230 in between */
}
}
- return FALSE; /* no dot above following */
+ return false; /* no dot above following */
}
U_CAPI int32_t U_EXPORT2
@@ -1317,7 +1317,7 @@ ucase_toFullUpper(UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
int32_t caseLocale) {
- return toUpperOrTitle(c, iter, context, pString, caseLocale, TRUE);
+ return toUpperOrTitle(c, iter, context, pString, caseLocale, true);
}
U_CAPI int32_t U_EXPORT2
@@ -1325,7 +1325,7 @@ ucase_toFullTitle(UChar32 c,
UCaseContextIterator *iter, void *context,
const UChar **pString,
int32_t caseLocale) {
- return toUpperOrTitle(c, iter, context, pString, caseLocale, FALSE);
+ return toUpperOrTitle(c, iter, context, pString, caseLocale, false);
}
/* case folding ------------------------------------------------------------- */
@@ -1601,6 +1601,6 @@ ucase_hasBinaryProperty(UChar32 c, UProperty which) {
ucase_toFullUpper(c, NULL, NULL, &resultString, UCASE_LOC_ROOT)>=0 ||
ucase_toFullTitle(c, NULL, NULL, &resultString, UCASE_LOC_ROOT)>=0);
default:
- return FALSE;
+ return false;
}
}
diff --git a/thirdparty/icu4c/common/ucase.h b/thirdparty/icu4c/common/ucase.h
index 7bf57fd370..049f042912 100644
--- a/thirdparty/icu4c/common/ucase.h
+++ b/thirdparty/icu4c/common/ucase.h
@@ -139,8 +139,8 @@ public:
*/
UChar32 next(UnicodeString &full);
private:
- FullCaseFoldingIterator(const FullCaseFoldingIterator &); // no copy
- FullCaseFoldingIterator &operator=(const FullCaseFoldingIterator &); // no assignment
+ FullCaseFoldingIterator(const FullCaseFoldingIterator &) = delete; // no copy
+ FullCaseFoldingIterator &operator=(const FullCaseFoldingIterator &) = delete; // no assignment
const UChar *unfold;
int32_t unfoldRows;
diff --git a/thirdparty/icu4c/common/ucase_props_data.h b/thirdparty/icu4c/common/ucase_props_data.h
index 8bbf403cdc..b7797d14d7 100644
--- a/thirdparty/icu4c/common/ucase_props_data.h
+++ b/thirdparty/icu4c/common/ucase_props_data.h
@@ -9,145 +9,145 @@
#ifdef INCLUDED_FROM_UCASE_CPP
-static const UVersionInfo ucase_props_dataVersion={0xe,0,0,0};
+static const UVersionInfo ucase_props_dataVersion={0xf,0,0,0};
-static const int32_t ucase_props_indexes[UCASE_IX_TOP]={0x10,0x7512,0x64e8,0x683,0x172,0,0,0,0,0,0,0,0,0,0,3};
+static const int32_t ucase_props_indexes[UCASE_IX_TOP]={0x10,0x76f2,0x66c8,0x683,0x172,0,0,0,0,0,0,0,0,0,0,3};
-static const uint16_t ucase_props_trieIndex[12908]={
-0x354,0x35c,0x364,0x36c,0x37a,0x382,0x38a,0x392,0x39a,0x3a2,0x3a9,0x3b1,0x3b9,0x3c1,0x3c9,0x3d1,
-0x3d7,0x3df,0x3e7,0x3ef,0x3f7,0x3ff,0x407,0x40f,0x417,0x41f,0x427,0x42f,0x437,0x43f,0x447,0x44f,
-0x457,0x45f,0x467,0x46f,0x477,0x47f,0x487,0x48f,0x48b,0x493,0x498,0x4a0,0x4a7,0x4af,0x4b7,0x4bf,
-0x4c7,0x4cf,0x4d7,0x4df,0x373,0x37b,0x4e4,0x4ec,0x4f1,0x4f9,0x501,0x509,0x508,0x510,0x515,0x51d,
-0x525,0x52c,0x530,0x373,0x537,0x354,0x547,0x53f,0x54f,0x551,0x559,0x561,0x565,0x566,0x56e,0x576,
-0x57e,0x566,0x586,0x58b,0x57e,0x566,0x593,0x59b,0x565,0x5a3,0x5ab,0x5b3,0x5bb,0x373,0x5c3,0x373,
-0x5cb,0x5cd,0x5d5,0x5b3,0x565,0x5a3,0x5dc,0x5b3,0x5e4,0x5e6,0x56e,0x5b3,0x565,0x373,0x5ee,0x373,
-0x373,0x5f4,0x5fb,0x373,0x373,0x5ff,0x607,0x373,0x60b,0x612,0x373,0x619,0x621,0x628,0x630,0x373,
-0x373,0x635,0x63d,0x645,0x64d,0x655,0x65c,0x664,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x66c,0x373,0x373,0x67c,0x67c,0x674,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x684,0x68a,0x572,0x572,0x373,0x690,0x698,0x373,
-0x6a0,0x373,0x6a8,0x373,0x6af,0x6b5,0x373,0x373,0x373,0x6bd,0x373,0x373,0x373,0x373,0x373,0x373,
-0x6c4,0x373,0x6cb,0x6d3,0x373,0x6db,0x6e3,0x373,0x5a2,0x6e7,0x6ef,0x6f5,0x5e4,0x6fd,0x373,0x704,
-0x373,0x709,0x373,0x70f,0x717,0x71b,0x723,0x72b,0x733,0x738,0x73b,0x743,0x753,0x74b,0x763,0x75b,
-0x39a,0x76b,0x39a,0x773,0x776,0x39a,0x77e,0x39a,0x786,0x78e,0x796,0x79e,0x7a6,0x7ae,0x7b6,0x7be,
-0x7c6,0x7cd,0x373,0x7d5,0x7dd,0x373,0x7e5,0x7ed,0x7f5,0x7fd,0x805,0x80d,0x815,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x818,0x81e,0x824,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x82c,0x830,0x834,0x83c,0x39a,0x39a,0x39a,0x844,0x84c,0x853,0x373,0x858,0x373,0x373,0x373,0x860,
-0x373,0x6a5,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x564,0x868,0x373,0x373,0x86f,0x373,0x373,0x877,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x87f,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x70f,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x885,0x373,0x88d,0x892,0x89a,0x373,0x373,0x8a2,0x8aa,0x8b2,0x39a,0x8b7,0x8bf,0x8c5,0x8cc,0x8d3,
-0x8db,0x8e2,0x373,0x373,0x373,0x373,0x8e9,0x8f1,0x373,0x8f9,0x900,0x373,0x54f,0x905,0x90d,0x6af,
-0x373,0x913,0x91b,0x91f,0x373,0x927,0x92f,0x937,0x373,0x93d,0x941,0x949,0x959,0x951,0x373,0x961,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x969,0x373,0x373,0x373,0x373,0x971,0x54f,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x976,0x97e,0x982,0x373,0x373,0x373,0x373,0x356,0x35c,0x98a,0x992,0x999,0x50a,0x373,0x373,0x9a1,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0xdd0,0xdd0,0xde8,0xe28,0xe68,0xea4,0xee4,0xf24,0xf5c,0xf9c,0xfdc,0x101c,0x105c,0x109c,0x10dc,0x111c,
-0x115c,0x119c,0x11dc,0x121c,0x122c,0x1260,0x129c,0x12dc,0x131c,0x135c,0xdcc,0x1390,0x13c4,0x1404,0x1420,0x1454,
-0x9e1,0xa1f,0xa5f,0xa9e,0x188,0x188,0xad6,0x188,0x188,0x188,0x188,0x188,0x188,0xaff,0x188,0x188,
-0x188,0x188,0x188,0x188,0x188,0xb3f,0x188,0xb7f,0x188,0xba5,0xbe0,0xc1f,0xc5f,0xc99,0xcd0,0x188,
+static const uint16_t ucase_props_trieIndex[13148]={
+0x355,0x35d,0x365,0x36d,0x37b,0x383,0x38b,0x393,0x39b,0x3a3,0x3aa,0x3b2,0x3ba,0x3c2,0x3ca,0x3d2,
+0x3d8,0x3e0,0x3e8,0x3f0,0x3f8,0x400,0x408,0x410,0x418,0x420,0x428,0x430,0x438,0x440,0x448,0x450,
+0x458,0x460,0x468,0x470,0x478,0x480,0x488,0x490,0x48c,0x494,0x499,0x4a1,0x4a8,0x4b0,0x4b8,0x4c0,
+0x4c8,0x4d0,0x4d8,0x4e0,0x374,0x37c,0x4e5,0x4ed,0x4f2,0x4fa,0x502,0x50a,0x509,0x511,0x516,0x51e,
+0x526,0x52d,0x531,0x374,0x538,0x355,0x548,0x540,0x550,0x552,0x55a,0x562,0x566,0x567,0x56f,0x577,
+0x57f,0x567,0x587,0x58c,0x57f,0x567,0x594,0x59c,0x566,0x5a4,0x5ac,0x5b4,0x5bc,0x374,0x5c4,0x374,
+0x5cc,0x5ce,0x5d6,0x5b4,0x566,0x5a4,0x5dd,0x5b4,0x5e5,0x5e7,0x56f,0x5b4,0x566,0x374,0x5ef,0x374,
+0x374,0x5f5,0x5fc,0x374,0x374,0x600,0x608,0x374,0x60c,0x613,0x374,0x61a,0x622,0x629,0x631,0x374,
+0x374,0x636,0x63e,0x646,0x64e,0x656,0x65d,0x665,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x66d,0x374,0x374,0x67d,0x67d,0x675,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x685,0x68b,0x573,0x573,0x374,0x691,0x699,0x374,
+0x6a1,0x374,0x6a9,0x374,0x6b0,0x6b6,0x374,0x374,0x374,0x6be,0x374,0x374,0x374,0x374,0x374,0x374,
+0x6c5,0x374,0x6cc,0x6d4,0x374,0x6dc,0x6e4,0x374,0x5a3,0x6e8,0x6f0,0x6f6,0x5e5,0x6fe,0x374,0x705,
+0x374,0x70a,0x374,0x710,0x718,0x71c,0x724,0x72c,0x734,0x739,0x73c,0x744,0x754,0x74c,0x764,0x75c,
+0x39b,0x76c,0x39b,0x774,0x777,0x39b,0x77f,0x39b,0x787,0x78f,0x797,0x79f,0x7a7,0x7af,0x7b7,0x7bf,
+0x7c7,0x7ce,0x374,0x7d6,0x7de,0x374,0x7e6,0x7ee,0x7f6,0x7fe,0x806,0x80e,0x816,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x819,0x81f,0x825,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x82d,0x831,0x835,0x83d,0x39b,0x39b,0x39b,0x845,0x84d,0x854,0x374,0x859,0x374,0x374,0x374,0x861,
+0x374,0x6a6,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x565,0x869,0x374,0x374,0x870,0x374,0x374,0x878,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x880,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x710,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x886,0x374,0x88e,0x893,0x89b,0x374,0x374,0x8a3,0x8ab,0x8b3,0x39b,0x8b8,0x8c0,0x8c6,0x8cd,0x8d4,
+0x8dc,0x8e3,0x374,0x374,0x374,0x374,0x8ea,0x8f2,0x374,0x8fa,0x901,0x374,0x550,0x906,0x90e,0x6b0,
+0x374,0x914,0x91c,0x920,0x374,0x928,0x930,0x938,0x374,0x93e,0x942,0x94a,0x95a,0x952,0x374,0x962,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x96a,0x374,0x374,0x374,0x374,0x972,0x550,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x977,0x97f,0x983,0x374,0x374,0x374,0x374,0x357,0x35d,0x98b,0x993,0x99a,0x50b,0x374,0x374,0x9a2,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0xdd4,0xdd4,0xdec,0xe2c,0xe6c,0xea8,0xee8,0xf28,0xf60,0xfa0,0xfe0,0x1020,0x1060,0x10a0,0x10e0,0x1120,
+0x1160,0x11a0,0x11e0,0x1220,0x1230,0x1264,0x12a0,0x12e0,0x1320,0x1360,0xdd0,0x1394,0x13c8,0x1408,0x1424,0x1458,
+0x9e1,0xa1f,0xa5f,0xa9e,0x188,0x188,0xad9,0x188,0x188,0x188,0x188,0x188,0x188,0xb02,0x188,0x188,
+0x188,0x188,0x188,0x188,0x188,0xb42,0x188,0xb82,0x188,0xba8,0xbe3,0xc22,0xc62,0xc9c,0xcd3,0x188,
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
@@ -172,642 +172,657 @@ static const uint16_t ucase_props_trieIndex[12908]={
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,0x188,
-0xd10,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x9a8,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x9b0,0x373,0x373,0x373,0x9b3,0x373,0x373,0x373,
-0x373,0x9bb,0x9c1,0x9c5,0x373,0x373,0x9c9,0x9cd,0x9d3,0x373,0x373,0x373,0x9da,0x9de,0x9e6,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x9f6,0x9ee,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x9fe,
-0xa02,0x373,0x373,0x373,0x373,0x373,0xa0a,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0xa12,0xa16,0xa1e,0xa22,0x373,0xa29,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0xa2f,0x373,0x373,0x373,0x373,0xa36,0x373,0xa3e,0x373,0x373,0x373,0x565,
-0xa40,0xa47,0xa4b,0x5e4,0xa53,0xa5b,0x373,0xa63,0xa6a,0x373,0xa70,0x5e4,0xa75,0xa7d,0x373,0x373,
-0xa82,0x373,0x373,0x373,0x373,0x356,0xa8a,0x5e4,0x5e6,0xa92,0xa99,0x373,0x373,0x373,0x373,0x373,
-0xa40,0xaa1,0x373,0x373,0xaa9,0xab1,0x373,0x373,0x373,0x373,0x373,0x373,0xab5,0xabd,0x373,0x373,
-0xac5,0x4ce,0x373,0x373,0xacd,0x373,0x373,0xad3,0xadb,0x373,0x373,0x373,0x373,0x373,0x373,0xae0,
-0x373,0x373,0x373,0xae8,0xaf0,0x373,0x373,0xaf8,0xb00,0x373,0x373,0x373,0xb03,0x9b0,0xb0b,0xb0f,
-0xb17,0x373,0xb1e,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xb25,
-0x373,0x373,0x971,0xb2d,0x373,0x373,0x373,0xb33,0xb3b,0x373,0xb3f,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0xb45,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xb4b,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0xb52,0x373,0xb58,0x5a2,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0xae8,0xaf0,0x373,0x373,0x373,0x373,0x373,0x373,0x6a5,0x373,0xb5e,0x373,0x373,0xb66,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xb6b,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0xb73,0x5a2,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x8aa,0xb7b,0xb82,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xb89,0xb91,0xb97,0x373,0x373,
-0x373,0x373,0xb9f,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0xba7,0xbaf,0xbb4,0xbba,0xbc2,0xbca,0xbd2,0xbab,0xbda,0xbe2,0xbea,0xbf1,0xbac,0xba7,0xbaf,0xbaa,
-0xbba,0xbad,0xba8,0xbf9,0xbab,0xc01,0xc09,0xc11,0xc18,0xc04,0xc0c,0xc14,0xc1b,0xc07,0xc23,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x8aa,
-0xc2b,0x8aa,0xc32,0xc39,0xc41,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xc51,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xc49,
-0xc59,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xc5d,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0xaa5,0x373,0xa27,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xc65,
-0x373,0xc6d,0xc75,0xc7c,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xba3,0xc84,0xc84,0xc8a,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0xa65,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x565,0x8aa,0x8aa,0x8aa,0x373,0x373,0x373,0x373,0x8aa,0x8aa,0x8aa,0x8aa,0x8aa,0x8aa,0x8aa,0xc92,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,0x373,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,0,0,0,0,0,0,4,0,
-0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
-0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0xa,0x5a,0x7a,0x1012,0x1012,0x1012,0x1012,
-0x1012,0x1012,0x1012,0xba,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0,0,0,4,0,
-4,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf9,0xf031,0x149,0xf011,0xf011,0xf011,0xf011,
-0xf011,0xf011,0xf011,0x189,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-4,0,1,0,0,4,0,4,0,0,0,0,4,0x1c9,0,4,
-4,0,1,0,0,0,0,0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1fa,0x1012,0x1012,
-0x1012,0x1012,0x1012,0x1012,0x5a,0x5a,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0,
-0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x239,0xf011,0xf011,0xf011,0xf011,0xf011,0x2d9,0xf011,0xf011,
-0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0,
-0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x3c91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0xd13,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x9a9,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x9b1,0x374,0x374,0x374,0x9b4,0x374,0x374,0x374,
+0x374,0x9bc,0x9c2,0x9c6,0x374,0x374,0x9ca,0x9ce,0x9d4,0x374,0x374,0x374,0x9db,0x9df,0x9e7,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x9f7,0x9ef,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x9ff,
+0xa03,0x374,0x374,0x374,0x374,0x374,0xa0b,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0xa13,0xa17,0xa1f,0xa23,0x374,0xa2a,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0xa30,0x374,0xa34,0x374,0x374,0xa3c,0x374,0xa44,0x374,0x374,0x374,0x566,
+0xa46,0xa4d,0xa51,0x5e5,0xa59,0xa61,0x374,0xa69,0xa70,0x374,0xa76,0x5e5,0xa7b,0xa83,0x374,0x374,
+0xa88,0x566,0x374,0x374,0x374,0x357,0xa90,0x5e5,0x5e7,0xa98,0xa9f,0x374,0x374,0x374,0x374,0x374,
+0xa46,0xaa7,0x374,0x374,0xaaf,0xab7,0x374,0x374,0x374,0x374,0x374,0x374,0xabb,0xac3,0x374,0x374,
+0xacb,0x4cf,0x374,0x374,0xad3,0x374,0x374,0xad9,0xae1,0x374,0x374,0x374,0x374,0x374,0x374,0xae6,
+0x374,0x374,0x374,0xaee,0xaf6,0x374,0x374,0xafe,0xb06,0x374,0x374,0x374,0xb09,0x9b1,0xb11,0xb15,
+0xb1d,0x374,0xb24,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xb2b,
+0x374,0x374,0x972,0xb33,0x374,0x374,0x374,0xb39,0xb41,0x374,0xb45,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0xb4b,0x5e5,0xb51,0xb59,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xb5d,0xb65,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xb6b,0x374,0xb71,0x5a3,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0xaee,0xaf6,0x374,0x374,0x374,0x374,0x374,0x374,0x6a6,0x374,0xb77,0x374,
+0x374,0xb7f,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0xb84,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0xb8c,0x5a3,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x8ab,0xb94,0xb9b,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xba2,0xbaa,
+0xbb0,0x374,0x374,0x374,0x374,0xbb8,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0xbc0,0xbc8,0xbcd,0xbd3,0xbdb,0xbe3,0xbeb,0xbc4,0xbf3,0xbfb,0xc03,0xc0a,0xbc5,
+0xbc0,0xbc8,0xbc3,0xbd3,0xbc6,0xbc1,0xc12,0xbc4,0xc1a,0xc22,0xc2a,0xc31,0xc1d,0xc25,0xc2d,0xc34,
+0xc20,0xc3c,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x8ab,0xc44,0x8ab,0xc4b,0xc52,0xc5a,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xc6a,0xc72,0x374,0x374,0x374,0x374,
+0x374,0x374,0xc62,0xc7a,0xc8d,0xc80,0xc85,0x374,0x374,0x374,0x374,0xc95,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xaab,0x374,0xa28,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xc9d,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0xca1,0x374,0xca9,0xcb1,0xcb8,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0xbbc,0xcc0,0xcc0,0xcc6,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0xa6b,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x566,0x8ab,0x8ab,0x8ab,0x374,0x374,0x374,0x374,0x8ab,0x8ab,0x8ab,0x8ab,0x8ab,
+0x8ab,0x8ab,0xcce,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,0x374,
+0x374,0x374,0x374,0x354,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,
+0,0,0,0,0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0xa,0x5a,0x7a,
+0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0xba,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0,
+0,0,4,0,4,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf9,0xf031,0x149,
+0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x189,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,1,0,0,4,0,4,0,0,0,0,
+4,0x1c9,0,4,4,0,1,0,0,0,0,0,0x1012,0x1012,0x1012,0x1012,
+0x1012,0x1fa,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x5a,0x5a,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
+0x1012,0x1012,0x1012,0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x239,0xf011,0xf011,0xf011,0xf011,
+0xf011,0x2d9,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
+0xf011,0xf011,0xf011,0,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x3c91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x31a,0xff91,0x92,0xff91,0x92,0xff91,0x31a,0xffb1,0x33a,0x389,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x3d9,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x31a,0xff91,0x92,0xff91,0x92,0xff91,0x31a,0xffb1,0x33a,0x389,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,
+0xff91,0x3d9,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xc392,0x92,0xff91,0x92,
-0xff91,0x92,0xff91,0x459,0x6191,0x6912,0x92,0xff91,0x92,0xff91,0x6712,0x92,0xff91,0x6692,0x6692,0x92,
-0xff91,1,0x2792,0x6512,0x6592,0x92,0xff91,0x6692,0x6792,0x3091,0x6992,0x6892,0x92,0xff91,0x5191,1,
-0x6992,0x6a92,0x4111,0x6b12,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x6d12,0x92,0xff91,0x6d12,1,1,
-0x92,0xff91,0x6d12,0x92,0xff91,0x6c92,0x6c92,0x92,0xff91,0x92,0xff91,0x6d92,0x92,0xff91,1,0,
-0x92,0xff91,1,0x1c11,0,0,0,0,0x48a,0x4bb,0x4f9,0x52a,0x55b,0x599,0x5ca,0x5fb,
-0x639,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,
-0xff91,0xd891,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x669,0x6ea,0x71b,0x759,0x92,0xff91,0xcf92,0xe412,0x92,0xff91,0x92,0xff91,
+0xc392,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x459,0x6191,0x6912,0x92,0xff91,0x92,0xff91,0x6712,0x92,
+0xff91,0x6692,0x6692,0x92,0xff91,1,0x2792,0x6512,0x6592,0x92,0xff91,0x6692,0x6792,0x3091,0x6992,0x6892,
+0x92,0xff91,0x5191,1,0x6992,0x6a92,0x4111,0x6b12,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x6d12,0x92,
+0xff91,0x6d12,1,1,0x92,0xff91,0x6d12,0x92,0xff91,0x6c92,0x6c92,0x92,0xff91,0x92,0xff91,0x6d92,
+0x92,0xff91,1,0,0x92,0xff91,1,0x1c11,0,0,0,0,0x48a,0x4bb,0x4f9,0x52a,
+0x55b,0x599,0x5ca,0x5fb,0x639,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,
+0xff91,0x92,0xff91,0x92,0xff91,0xd891,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x669,0x6ea,0x71b,0x759,0x92,0xff91,0xcf92,0xe412,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xbf12,1,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-1,1,1,1,1,1,0x78a,0x92,0xff91,0xae92,0x7aa,0x7c9,0x7c9,0x92,0xff91,0x9e92,
-0x2292,0x2392,0x92,0xff91,0x92,0xffb1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x7e9,0x809,0x829,0x9711,
-0x9911,1,0x9991,0x9991,1,0x9b11,1,0x9a91,0x849,1,1,1,0x9991,0x869,1,0x9891,
-1,0x889,0x8a9,1,0x97b1,0x9691,0x8a9,0x8c9,0x8e9,1,1,0x9691,1,0x909,0x9591,1,
-1,0x9511,1,1,1,1,1,1,1,0x929,1,1,0x9311,1,0x949,0x9311,
-1,1,1,0x969,0x9311,0xdd91,0x9391,0x9391,0xdc91,1,1,1,1,1,0x9291,1,
-0,1,1,1,1,1,1,1,1,0x989,0x9a9,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,5,5,0x25,5,
-5,5,5,5,5,4,4,4,0x14,4,0x14,4,5,5,4,4,
+0xbf12,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,1,1,1,1,1,1,0x78a,0x92,0xff91,0xae92,0x7aa,0x7c9,
+0x7c9,0x92,0xff91,0x9e92,0x2292,0x2392,0x92,0xff91,0x92,0xffb1,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x7e9,0x809,0x829,0x9711,0x9911,1,0x9991,0x9991,1,0x9b11,1,0x9a91,0x849,1,1,1,
+0x9991,0x869,1,0x9891,1,0x889,0x8a9,1,0x97b1,0x9691,0x8a9,0x8c9,0x8e9,1,1,0x9691,
+1,0x909,0x9591,1,1,0x9511,1,1,1,1,1,1,1,0x929,1,1,
+0x9311,1,0x949,0x9311,1,1,1,0x969,0x9311,0xdd91,0x9391,0x9391,0xdc91,1,1,1,
+1,1,0x9291,1,0,1,1,1,1,1,1,1,1,0x989,0x9a9,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+5,5,0x25,5,5,5,5,5,5,4,4,4,0x14,4,0x14,4,
+5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,
-5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,0x54,0x54,0x44,0x44,
-0x44,0x44,0x44,0x9cc,0x54,0x44,0x54,0x44,0x54,0x44,0x44,0x44,0x44,0x44,0x44,0x54,
-0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,
-0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x74,0x64,0x64,
-0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x54,0x44,
-0x44,0x9dd,0x44,0x64,0x64,0x64,0x44,0x44,0x44,0x64,0x64,4,0x44,0x44,0x44,0x64,
-0x64,0x64,0x64,0x44,0x64,0x64,0x64,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x92,0xff91,0x92,0xff91,
-4,4,0x92,0xff91,0,0,5,0x4111,0x4111,0x4111,0,0x3a12,0,0,0,0,
-4,4,0x1312,4,0x1292,0x1292,0x1292,0,0x2012,0,0x1f92,0x1f92,0xa29,0x1012,0xafa,0x1012,
-0x1012,0xb3a,0x1012,0x1012,0xb7a,0xbca,0xc1a,0x1012,0xc5a,0x1012,0x1012,0x1012,0xc9a,0xcda,0,0xd1a,
-0x1012,0x1012,0xd5a,0x1012,0x1012,0xd9a,0x1012,0x1012,0xed11,0xed91,0xed91,0xed91,0xdd9,0xf011,0xea9,0xf011,
-0xf011,0xee9,0xf011,0xf011,0xf29,0xf79,0xfc9,0xf011,0x1009,0xf011,0xf011,0xf011,0x1049,0x1089,0x10c9,0x10f9,
-0xf011,0xf011,0x1139,0xf011,0xf011,0x1179,0xf011,0xf011,0xe011,0xe091,0xe091,0x412,0x11b9,0x11e9,2,2,
-2,0x1239,0x1269,0xfc11,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x1299,0x12c9,0x391,0xc631,
-0x12fa,0x1349,0,0x92,0xff91,0xfc92,0x92,0xff91,1,0xbf12,0xbf12,0xbf12,0x2812,0x2812,0x2812,0x2812,
-0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x1012,0x1012,0x137a,0x1012,
-0x13ba,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x13fa,0x1012,0x1012,0x143a,0x147a,0x1012,
-0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x14ca,0x1012,0x1012,0x1012,0x1012,0x1012,0xf011,0xf011,0x1509,0xf011,
-0x1549,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x1589,0xf011,0xf011,0x15c9,0x1609,0xf011,
-0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x1659,0xf011,0xf011,0xf011,0xf011,0xf011,0xd811,0xd811,0xd811,0xd811,
-0xd811,0xd811,0xd831,0xd811,0xd831,0xd811,0xd811,0xd811,0xd811,0xd811,0xd811,0xd811,0x92,0xff91,0x169a,0x16d9,
+5,5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+0x54,0x54,0x44,0x44,0x44,0x44,0x44,0x9cc,0x54,0x44,0x54,0x44,0x54,0x44,0x44,0x44,
+0x44,0x44,0x44,0x54,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,
+0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,
+0x64,0x74,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x44,
+0x44,0x44,0x54,0x44,0x44,0x9dd,0x44,0x64,0x64,0x64,0x44,0x44,0x44,0x64,0x64,4,
+0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x44,0x64,0x64,0x64,0x44,0x64,0x64,0x64,0x64,
+0x64,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+0x92,0xff91,0x92,0xff91,4,4,0x92,0xff91,0,0,5,0x4111,0x4111,0x4111,0,0x3a12,
+0,0,0,0,4,4,0x1312,4,0x1292,0x1292,0x1292,0,0x2012,0,0x1f92,0x1f92,
+0xa29,0x1012,0xafa,0x1012,0x1012,0xb3a,0x1012,0x1012,0xb7a,0xbca,0xc1a,0x1012,0xc5a,0x1012,0x1012,0x1012,
+0xc9a,0xcda,0,0xd1a,0x1012,0x1012,0xd5a,0x1012,0x1012,0xd9a,0x1012,0x1012,0xed11,0xed91,0xed91,0xed91,
+0xdd9,0xf011,0xea9,0xf011,0xf011,0xee9,0xf011,0xf011,0xf29,0xf79,0xfc9,0xf011,0x1009,0xf011,0xf011,0xf011,
+0x1049,0x1089,0x10c9,0x10f9,0xf011,0xf011,0x1139,0xf011,0xf011,0x1179,0xf011,0xf011,0xe011,0xe091,0xe091,0x412,
+0x11b9,0x11e9,2,2,2,0x1239,0x1269,0xfc11,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0,0x44,
-0x44,0x44,0x44,0x44,4,4,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x1299,0x12c9,0x391,0xc631,0x12fa,0x1349,0,0x92,0xff91,0xfc92,0x92,0xff91,1,0xbf12,0xbf12,0xbf12,
+0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,0x2812,
+0x1012,0x1012,0x137a,0x1012,0x13ba,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x13fa,0x1012,
+0x1012,0x143a,0x147a,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x14ca,0x1012,0x1012,0x1012,0x1012,0x1012,
+0xf011,0xf011,0x1509,0xf011,0x1549,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x1589,0xf011,
+0xf011,0x15c9,0x1609,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0x1659,0xf011,0xf011,0xf011,0xf011,0xf011,
+0xd811,0xd811,0xd811,0xd811,0xd811,0xd811,0xd831,0xd811,0xd831,0xd811,0xd811,0xd811,0xd811,0xd811,0xd811,0xd811,
+0x92,0xff91,0x169a,0x16d9,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0,0x44,0x44,0x44,0x44,0x44,4,4,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x792,0x92,0xff91,0x92,
-0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xf891,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0,0x1812,0x1812,0x1812,
-0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
-0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0,0,4,0,0,0,0,0,4,
-1,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
+0x792,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xf891,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
+0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0,0,4,0,0,
+0,0,0,4,1,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
-0xe811,0xe811,0xe811,0x1719,1,0,0,0,0,0,0,0,0,0x64,0x44,0x44,
-0x44,0x44,0x64,0x44,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x64,
-0x64,0x64,0x64,0x64,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x44,0x64,0x64,0x64,0x64,
-0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0x64,0,0x64,0x64,0,
-0x44,0x64,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
+0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0x1719,1,0,0,0,0,0,0,0,
+0,0x64,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,
+0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x44,
+0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0x64,
+0,0x64,0x64,0,0x44,0x64,0,0x64,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
-4,4,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,
-0x44,0x44,0x44,0x44,0x64,0x64,0x64,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,0,0,0,0,0,0,0,4,0,0,0,
-0,0,0,0,0,0,0,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x44,
-0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x64,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,4,0,0x44,
-0x44,0x44,0x44,0x64,0x44,4,4,0x44,0x44,0,0x64,0x44,0x44,0x64,0,0,
+0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
+4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,
+0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x64,0x64,0,4,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,4,0,0x64,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x44,0x64,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x64,0x44,0x64,
-0x64,0x44,0x64,0x44,0x44,0x44,0x64,0x44,0x64,0x44,0x64,0x44,0x64,0x44,0x44,0,
+4,0,0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,0x64,0x64,
+0x64,0x64,0x64,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,
+0x44,4,0,0x44,0x44,0x44,0x44,0x64,0x44,4,4,0x44,0x44,0,0x64,0x44,
+0x44,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0x64,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x44,0x64,0x44,0x44,0x64,0x44,0x44,0x64,
+0x64,0x64,0x44,0x64,0x64,0x44,0x64,0x44,0x44,0x44,0x64,0x44,0x64,0x44,0x64,0x44,
+0x64,0x44,0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,
-4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x44,4,4,0,0,0,0,4,0,
-0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,4,0x44,
-0x44,0x44,0x44,0x44,4,0x44,0x44,0x44,4,0x44,0x44,0x44,0x44,0x44,0,0,
+0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,
+4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,0,0,0,0,
-0,0,0,0,4,0,0,0,0,0,0,0,4,4,0,0,
-0,0,0,0,0x44,0x64,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x44,4,0x64,
-0x44,0x44,0x64,0x44,0x44,0x64,0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,
-0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0,0,0,0,
-0,0,0,0,0,4,0x44,0x44,0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x64,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,4,4,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,0,0,0,4,0,
-0x64,0,0,0,0,4,4,4,4,4,4,4,4,0,0,0,
-0,0x64,0,0,0,0x44,0x64,0x44,0x44,4,4,4,0,0,0,0,
-0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,
-0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x44,4,4,0,0,
+0,0,4,0,0,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,
+0x44,0x44,4,0x44,0x44,0x44,0x44,0x44,4,0x44,0x44,0x44,4,0x44,0x44,0x44,
+0x44,0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
+4,4,0,0,0,0,0,0,0x44,0x64,0x64,0x64,0x44,0x44,0x44,0x44,
+0x44,0x44,4,0x64,0x44,0x44,0x64,0x44,0x44,0x64,0x44,0x44,0x44,0x64,0x64,0x64,
+0x64,0x64,0x64,0x44,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,
+0,0,0,0,0,0,0,0,0,4,0x44,0x44,0x44,0x44,0x44,0x64,
+0x64,0x64,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+4,4,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,0,
-0,0,0,0,0x64,0,0,0,0,4,4,4,4,0,0,0,
-0,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,4,0,0x64,0,0,0,0,4,4,4,4,4,4,4,
+4,0,0,0,0,0x64,0,0,0,0x44,0x64,0x44,0x44,4,4,4,
0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x44,0,0,4,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,0,0,4,4,0,0,0,0,4,
-4,0,0,4,4,0x64,0,0,0,4,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,
-0,4,0,0,0,0,0,0,0,0,0,0,0,4,4,4,
-4,4,0,4,4,0,0,0,0,0x64,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x64,0,0,0,0,4,4,4,
+4,0,0,0,0,0,0,0,0,0x64,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,4,4,4,4,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x44,0,0,4,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,0x64,0,0,4,0,4,4,4,
-4,0,0,0,0,0,0,0,0,0x64,0,0,0,0,0,0,
-0,4,4,0,0,0,0,0,0,0,0,0,0,0,4,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,
+0,0,0,4,4,0,0,4,4,0x64,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,0,0,0,0,4,0,
+4,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,
+0,4,4,4,4,4,0,4,4,0,0,0,0,0x64,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,
-0,0,0,0,0,0,0,0,0,0x64,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,
-4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x64,0,4,4,4,0,0,0,0,0,4,4,4,0,4,4,
-4,0x64,0,0,0,0,0,0,0,0x64,0x64,0,0,0,0,0,
-0,0,0,0,0,0,4,0,0,0,0,0,4,0x64,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,4,
+0,4,4,4,4,0,0,0,0,0,0,0,0,0x64,0,0,
+0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,
+0,0,4,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,
-4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0x64,0,0,0,0,0,0,0,4,4,4,0,4,0,
+4,0,0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,4,0,0,4,4,4,4,0x64,0x64,0x64,0,0,0,0,0,
-0,0,4,4,0x64,0x64,0x64,0x64,4,4,4,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,
-4,4,4,4,0x64,0x64,0x64,4,4,0,0,0,0,0,0,0,
-0,0,4,0,0x64,0x64,0x64,0x64,4,4,0,0,0,0,0,0,
+4,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,0,0,0,0x64,0x64,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,0,0x64,
-0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0x64,0x64,4,0x64,4,4,4,4,4,0x64,0x64,
-0x64,0x64,4,0,0x64,4,0x44,0x44,0x64,0,0x44,0x44,0,0,0,0,
-0,4,4,4,4,4,4,4,4,4,4,4,0,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,
-0,0,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x64,0,4,4,4,0,0,0,0,0,4,4,
+4,0,4,4,4,0x64,0,0,0,0,0,0,0,0x64,0x64,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
+4,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,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,4,4,4,4,0,4,4,4,4,4,0x64,0,0x64,0x64,0,
-0,4,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,4,4,0,0,
-0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,0,0,4,4,0,0,0,0,0,
-0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,4,0,0,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,
-0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,
-0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0,0x175a,0,0,0,0,0,0x175a,0,0,
-0x1779,0x17a9,0x17d9,0x1809,0x1839,0x1869,0x1899,0x18c9,0x18f9,0x1929,0x1959,0x1989,0x19b9,0x19e9,0x1a19,0x1a49,
-0x1a79,0x1aa9,0x1ad9,0x1b09,0x1b39,0x1b69,0x1b99,0x1bc9,0x1bf9,0x1c29,0x1c59,0x1c89,0x1cb9,0x1ce9,0x1d19,0x1d49,
-0x1d79,0x1da9,0x1dd9,0x1e09,0x1e39,0x1e69,0x1e99,0x1ec9,0x1ef9,0x1f29,0x1f59,0,4,0x1f89,0x1fb9,0x1fe9,
+0,0,0,0,0,0,0,0x64,0x64,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x64,0,0,0,0,0,0,0,4,4,
+4,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,4,4,4,4,0x64,0x64,0x64,0,
+0,0,0,0,0,0,4,4,0x64,0x64,0x64,0x64,4,4,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,0,0,0x44,0x44,0x44,
-0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
-0x203a,0x203a,0x203a,0x203a,0x203a,0x203a,0,0,0x2059,0x2089,0x20b9,0x20e9,0x2119,0x2149,0,0,
-0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
-0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
+0,4,0,0,4,4,4,4,0x64,0x64,0x64,4,4,0,0,0,
+0,0,0,0,0,0,4,0,0x64,0x64,0x64,0x64,4,4,4,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,4,4,0x64,0x60,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,4,4,0x60,0,0,0,
+0,0,0,0,0,0,0,0,0x64,0x64,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,4,0,4,4,4,4,4,4,4,0,0,
-0,0,0,0,0,0,4,0,0,4,4,4,4,4,4,4,
-4,4,0x64,4,0,0,0,4,0,0,0,0,0,0x44,0,0,
-0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,
+0,0x64,0,0x64,0,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x64,0x64,4,0x64,4,4,4,
+4,4,0x64,0x64,0x64,0x64,4,0,0x64,4,0x44,0x44,0x64,0,0x44,0x44,
+0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,
+0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,0,0,0,0,0,0,0,0,0,0x64,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,4,4,4,0,4,4,4,4,4,0x64,
+0,0x64,0x64,0,0,4,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,4,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,0x64,0,0,
+4,4,0,0,0,0,4,4,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,0,0,4,4,0,
+0,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,0,0,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,
+0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,
+0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0x175a,0,0x175a,0,0,0,0,
+0,0x175a,0,0,0x1779,0x17a9,0x17d9,0x1809,0x1839,0x1869,0x1899,0x18c9,0x18f9,0x1929,0x1959,0x1989,
+0x19b9,0x19e9,0x1a19,0x1a49,0x1a79,0x1aa9,0x1ad9,0x1b09,0x1b39,0x1b69,0x1b99,0x1bc9,0x1bf9,0x1c29,0x1c59,0x1c89,
+0x1cb9,0x1ce9,0x1d19,0x1d49,0x1d79,0x1da9,0x1dd9,0x1e09,0x1e39,0x1e69,0x1e99,0x1ec9,0x1ef9,0x1f29,0x1f59,0,
+5,0x1f89,0x1fb9,0x1fe9,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0x44,0x44,0x44,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
+0x201a,0x201a,0x201a,0x201a,0x203a,0x203a,0x203a,0x203a,0x203a,0x203a,0,0,0x2059,0x2089,0x20b9,0x20e9,
+0x2119,0x2149,0,0,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
+0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,0x201a,
+0x201a,0x201a,0x201a,0x201a,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,4,4,0x64,0x60,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,
+0x60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,0,4,4,4,4,4,
+4,4,0,0,0,0,0,0,0,0,4,0,0,4,4,4,
+4,4,4,4,4,4,0x64,4,0,0,0,4,0,0,0,0,
+0,0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,4,4,0,0,0,0,4,4,0,0,0,
-0,0,0,0,0,0,4,0,0,0,0,0,0,0x64,0x44,0x64,
+0,0,0,0,0,4,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,0,0,0,0,0x44,0x64,0,0,4,0,0,0,0,
+0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,0,0,0,0,4,
+4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,
+0,0x64,0x44,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x44,0x64,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,4,0,4,4,4,4,4,4,4,0,
+0x64,0,4,0,0,4,4,4,4,4,4,4,4,0,0,0,
+0,0,0,4,4,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0x64,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
+0x44,0x44,0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x64,4,0x64,
+0x64,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x44,0x44,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,4,0,4,4,4,4,4,4,4,0,0x64,0,4,0,
-0,4,4,4,4,4,4,4,4,0,0,0,0,0,0,4,
-4,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0x64,0,0,0,0,
-0,0,0,4,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,
-0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x64,4,0x64,0x64,0x44,0x44,0x64,
-0x64,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x44,0x44,0,0,0,0,0,
+0,0,0,0,0x64,0,4,4,4,4,4,0,4,0,0,0,
+0,0,4,0,0x60,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x64,0,4,4,4,4,4,0,4,0,0,0,0,0,4,0,
-0x60,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x44,
-0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,4,4,4,0,0,4,4,0x60,0x64,
-4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x64,0,4,4,0,0,0,4,0,4,
-4,4,0x60,0x60,0,0,0,0,0,0,0,0,0,0,0,0,
-4,4,4,4,4,4,4,4,0,0,4,0x64,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,4,4,4,4,4,0,0,0x2179,0x21a9,0x21d9,0x2209,
-0x2239,0x2289,0x22d9,0x2309,0x2339,0,0,0,0,0,0,0,0x236a,0x236a,0x236a,0x236a,
+0,0,0,0x44,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,4,4,4,0,0,
+4,4,0x60,0x64,4,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x64,0,4,4,0,0,
+0,4,0,4,4,4,0x60,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,4,4,4,4,4,4,4,4,0,0,4,0x64,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,4,4,4,0,0,
+0x2179,0x21a9,0x21d9,0x2209,0x2239,0x2289,0x22d9,0x2309,0x2339,0,0,0,0,0,0,0,
0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,
-0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0,0,0x236a,0x236a,0x236a,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0,
-0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x64,0x64,0x64,0x64,0x44,0,0x64,0x64,
-0x64,0x64,0x64,0x64,0x64,0,0,0,0,0x64,0,0,0,0,0,0,
-0x44,0,0,0,0x44,0x44,0,0,0,0,0,0,1,1,1,1,
+0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0x236a,0,0,0x236a,0x236a,0x236a,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x44,0x44,0x44,0,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0x64,0x64,0x64,0x64,
+0x44,0,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0,0,0,0x64,0,0,
+0,0,0,0,0x44,0,0,0,0x44,0x44,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x25,5,
-5,5,5,5,5,5,5,1,1,1,1,1,1,1,1,1,
-1,1,1,1,5,0x2389,1,1,1,0x23a9,1,1,5,5,5,5,
-0x25,5,5,5,0x25,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,0x23c9,1,1,1,1,1,
-1,1,0x21,1,1,1,1,5,5,5,5,5,0x44,0x44,0x44,0x44,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0x25,5,5,5,5,5,5,5,5,1,1,1,1,1,
+1,1,1,1,1,1,1,1,5,0x2389,1,1,1,0x23a9,1,1,
+5,5,5,5,0x25,5,5,5,0x25,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x23c9,1,
+1,1,1,1,1,1,0x21,1,1,1,1,5,5,5,5,5,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
-0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x44,0x64,0x64,0x44,0x64,0x44,0x44,0x64,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x64,0x64,0x44,0x44,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xffb1,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x23ea,0x2429,0x92,0xff91,
+0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x44,0x64,0x64,0x44,0x64,
+0x44,0x44,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x64,0x44,0x44,0x64,0x64,0x64,
+0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xffb1,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x2469,0x24e9,
-0x2569,0x25e9,0x2669,0x26e9,1,1,0x271a,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xffb1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x411,0x411,0x411,0x411,0x411,0x411,0x411,0x411,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,0x411,0x411,0,0,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0,0,0x411,0x411,0x411,0x411,0x411,0x411,0x411,0x411,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,0x411,0x411,0x411,0x411,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,0x411,0x411,0,0,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0,0,0x2769,0x411,0x27e9,0x411,0x2899,0x411,0x2949,0x411,
-0,0xfc12,0,0xfc12,0,0xfc12,0,0xfc12,0x411,0x411,0x411,0x411,0x411,0x411,0x411,0x411,
-0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x2511,0x2511,0x2b11,0x2b11,0x2b11,0x2b11,0x3211,0x3211,
-0x4011,0x4011,0x3811,0x3811,0x3f11,0x3f11,0,0,0x29f9,0x2a69,0x2ad9,0x2b49,0x2bb9,0x2c29,0x2c99,0x2d09,
-0x2d7b,0x2deb,0x2e5b,0x2ecb,0x2f3b,0x2fab,0x301b,0x308b,0x30f9,0x3169,0x31d9,0x3249,0x32b9,0x3329,0x3399,0x3409,
-0x347b,0x34eb,0x355b,0x35cb,0x363b,0x36ab,0x371b,0x378b,0x37f9,0x3869,0x38d9,0x3949,0x39b9,0x3a29,0x3a99,0x3b09,
-0x3b7b,0x3beb,0x3c5b,0x3ccb,0x3d3b,0x3dab,0x3e1b,0x3e8b,0x411,0x411,0x3ef9,0x3f79,0x3fe9,0,0x4069,0x40e9,
-0xfc12,0xfc12,0xdb12,0xdb12,0x419b,4,0x4209,4,4,4,0x4259,0x42d9,0x4349,0,0x43c9,0x4449,
-0xd512,0xd512,0xd512,0xd512,0x44fb,4,4,4,0x411,0x411,0x4569,0x4619,0,0,0x46e9,0x4769,
-0xfc12,0xfc12,0xce12,0xce12,0,4,4,4,0x411,0x411,0x4819,0x48c9,0x4999,0x391,0x4a19,0x4a99,
-0xfc12,0xfc12,0xc812,0xc812,0xfc92,4,4,4,0,0,0x4b49,0x4bc9,0x4c39,0,0x4cb9,0x4d39,
-0xc012,0xc012,0xc112,0xc112,0x4deb,4,4,0,0,0,0,0,0,0,0,0,
-0,0,0,4,4,4,4,4,0,0,0,0,0,0,0,0,
-4,4,0,0,0,0,0,0,4,0,0,4,0,0,4,4,
-4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,
-4,4,4,4,0,0x25,0,0,0,0,0,0,0,0,0,0,
-0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,0x64,0x64,0x64,0x44,
-0x44,4,4,4,4,0x44,4,4,4,0x64,0x64,0x44,0x64,0x44,0x64,0x64,
-0x64,0x64,0x64,0x64,0x44,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,2,0,0,0,0,2,0,0,1,2,
-2,2,1,1,2,2,2,1,0,2,0,0,0,2,2,2,
-2,2,0,0,0,0,0,0,2,0,0x4e5a,0,2,0,0x4e9a,0x4eda,
-2,2,0,1,2,2,0xe12,2,1,0,0,0,0,1,0,0,
-1,1,2,2,0,0,0,0,0,2,1,1,0x21,0x21,0,0,
-0,0,0xf211,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,
-0x812,0x812,0x812,0x812,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,
-0xf811,0xf811,0xf811,0xf811,0,0,0,0x92,0xff91,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,
-0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,
-0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
+0x23ea,0x2429,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x2469,0x24e9,0x2569,0x25e9,0x2669,0x26e9,1,1,0x271a,1,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xffb1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x411,0x411,0x411,0x411,
+0x411,0x411,0x411,0x411,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,
+0x411,0x411,0,0,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0,0,0x411,0x411,0x411,0x411,
+0x411,0x411,0x411,0x411,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,
+0x411,0x411,0x411,0x411,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x411,0x411,0x411,0x411,
+0x411,0x411,0,0,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0,0,0x2769,0x411,0x27e9,0x411,
+0x2899,0x411,0x2949,0x411,0,0xfc12,0,0xfc12,0,0xfc12,0,0xfc12,0x411,0x411,0x411,0x411,
+0x411,0x411,0x411,0x411,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0xfc12,0x2511,0x2511,0x2b11,0x2b11,
+0x2b11,0x2b11,0x3211,0x3211,0x4011,0x4011,0x3811,0x3811,0x3f11,0x3f11,0,0,0x29f9,0x2a69,0x2ad9,0x2b49,
+0x2bb9,0x2c29,0x2c99,0x2d09,0x2d7b,0x2deb,0x2e5b,0x2ecb,0x2f3b,0x2fab,0x301b,0x308b,0x30f9,0x3169,0x31d9,0x3249,
+0x32b9,0x3329,0x3399,0x3409,0x347b,0x34eb,0x355b,0x35cb,0x363b,0x36ab,0x371b,0x378b,0x37f9,0x3869,0x38d9,0x3949,
+0x39b9,0x3a29,0x3a99,0x3b09,0x3b7b,0x3beb,0x3c5b,0x3ccb,0x3d3b,0x3dab,0x3e1b,0x3e8b,0x411,0x411,0x3ef9,0x3f79,
+0x3fe9,0,0x4069,0x40e9,0xfc12,0xfc12,0xdb12,0xdb12,0x419b,4,0x4209,4,4,4,0x4259,0x42d9,
+0x4349,0,0x43c9,0x4449,0xd512,0xd512,0xd512,0xd512,0x44fb,4,4,4,0x411,0x411,0x4569,0x4619,
+0,0,0x46e9,0x4769,0xfc12,0xfc12,0xce12,0xce12,0,4,4,4,0x411,0x411,0x4819,0x48c9,
+0x4999,0x391,0x4a19,0x4a99,0xfc12,0xfc12,0xc812,0xc812,0xfc92,4,4,4,0,0,0x4b49,0x4bc9,
+0x4c39,0,0x4cb9,0x4d39,0xc012,0xc012,0xc112,0xc112,0x4deb,4,4,0,0,0,0,0,
+0,0,0,0,0,0,0,4,4,4,4,4,0,0,0,0,
+0,0,0,0,4,4,0,0,0,0,0,0,4,0,0,4,
+0,0,4,4,4,4,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,4,4,0,4,4,
+4,4,4,4,4,4,4,4,0,0x25,0,0,0,0,0,0,
+0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x44,0x44,0x64,0x64,0x44,0x44,0x44,0x44,
+0x64,0x64,0x64,0x44,0x44,4,4,4,4,0x44,4,4,4,0x64,0x64,0x44,
+0x64,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,2,
+0,0,1,2,2,2,1,1,2,2,2,1,0,2,0,0,
+0,2,2,2,2,2,0,0,0,0,0,0,2,0,0x4e5a,0,
+2,0,0x4e9a,0x4eda,2,2,0,1,2,2,0xe12,2,1,0,0,0,
+0,1,0,0,1,1,2,2,0,0,0,0,0,2,1,1,
+0x21,0x21,0,0,0,0,0xf211,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,
+0x812,0x812,0x812,0x812,0x812,0x812,0x812,0x812,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,
+0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0xf811,0,0,0,0x92,0xff91,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,
+0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xd12,0xf311,0xf311,0xf311,0xf311,
+0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0xf311,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
+0x1812,0x1812,0x1812,0x1812,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
-0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,0xe811,
-0x92,0xff91,0x4f1a,0x4f3a,0x4f5a,0x4f79,0x4f99,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x4fba,0x4fda,0x4ffa,
-0x501a,1,0x92,0xff91,1,0x92,0xff91,1,1,1,1,1,0x25,5,0x503a,0x503a,
-0x92,0xff91,0x92,0xff91,1,0,0,0,0,0,0,0x92,0xff91,0x92,0xff91,0x44,
-0x44,0x44,0x92,0xff91,0,0,0,0,0,0,0,0,0,0,0,0,
-0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,
+0xe811,0xe811,0xe811,0xe811,0x92,0xff91,0x4f1a,0x4f3a,0x4f5a,0x4f79,0x4f99,0x92,0xff91,0x92,0xff91,0x92,
+0xff91,0x4fba,0x4fda,0x4ffa,0x501a,1,0x92,0xff91,1,0x92,0xff91,1,1,1,1,1,
+0x25,5,0x503a,0x503a,0x92,0xff91,0x92,0xff91,1,0,0,0,0,0,0,0x92,
+0xff91,0x92,0xff91,0x44,0x44,0x44,0x92,0xff91,0,0,0,0,0,0,0,0,
+0,0,0,0,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,
0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,
-0x5059,0x5059,0,0x5059,0,0,0,0,0,0x5059,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+0x5059,0x5059,0x5059,0x5059,0x5059,0x5059,0,0x5059,0,0,0,0,0,0x5059,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x64,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
-0,0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,0x64,0x60,0x60,
-0,4,4,4,4,4,0,0,0,0,0,4,0,0,0,0,
+0x44,0x44,0x44,0x44,0,0,0,0,0,0,0,0,0,0,0x64,0x64,
+0x64,0x64,0x60,0x60,0,4,4,4,4,4,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,0x64,0x64,4,4,4,4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0x64,0x64,4,4,4,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,4,4,4,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x507a,0x50b9,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0,0x44,4,4,4,0,0x44,0x44,0x44,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0,4,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x507a,0x50b9,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0,0x44,4,4,4,0,
+0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,4,0x92,0xff91,0x92,0xff91,
0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,5,5,0x44,0x44,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x44,0x44,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,5,5,0x44,0x44,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,1,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,5,1,1,1,
-1,1,1,1,1,0x92,0xff91,0x92,0xff91,0x50fa,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,4,4,4,0x92,0xff91,0x511a,1,0,0x92,0xff91,0x92,0xff91,
-0x1811,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x513a,0x515a,
-0x517a,0x519a,0x513a,1,0x51ba,0x51da,0x51fa,0x521a,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
-0x92,0xff91,0x92,0xff91,0xe812,0x523a,0x525a,0x92,0xff91,0x92,0xff91,0,0,0,0,0,
-0x92,0xff91,0,1,0,1,0x92,0xff91,0x92,0xff91,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,
-4,0x92,0xff91,0,5,5,1,0,0,0,0,0,0,0,4,0,
-0,0,0x64,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,4,4,0,
-0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x64,4,0,0,0,0,0,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,1,1,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+5,1,1,1,1,1,1,1,1,0x92,0xff91,0x92,0xff91,0x50fa,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,4,4,4,0x92,0xff91,0x511a,1,0,
+0x92,0xff91,0x92,0xff91,0x1811,1,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x513a,0x515a,0x517a,0x519a,0x513a,1,0x51ba,0x51da,0x51fa,0x521a,0x92,0xff91,0x92,0xff91,
+0x92,0xff91,0x92,0xff91,0x92,0xff91,0x92,0xff91,0xe812,0x523a,0x525a,0x92,0xff91,0x92,0xff91,0,
+0,0,0,0,0x92,0xff91,0,1,0,1,0x92,0xff91,0x92,0xff91,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,5,5,0x92,0xff91,0,5,5,1,0,0,0,0,0,
+0,0,4,0,0,0,0x64,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,4,4,0,0,0,0,0,0x64,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x64,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,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,4,4,
+4,4,4,0x64,0x64,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,
+4,4,4,4,4,4,0,0x60,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,4,4,
+4,4,0,0,4,4,0,0,0x60,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,0,
+0,4,4,0,0,4,4,0,0,0,0,0,0,0,0,0,
+0,0,0,4,0,0,0,0,0,0,0,0,4,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0,0,0,0,0,
-0,0,0,4,0,0,0,0,0,0,4,4,4,4,4,0x64,
-0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,
-4,4,0,0x60,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0x64,0,0,4,4,4,4,0,0,
-4,4,0,0,0x60,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,4,4,4,4,4,4,0,0,4,4,0,
-0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,4,
-0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,
-0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x44,0,0x44,0x44,
-0x64,0,0,0x44,0x44,0,0,0,0,0,0x44,0x44,0,0x44,0,0,
+4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,4,
-4,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,0x5279,1,1,1,1,1,1,1,4,
-5,5,5,5,1,1,1,1,1,1,1,1,1,4,4,4,
-0,0,0,0,0x5299,0x52c9,0x52f9,0x5329,0x5359,0x5389,0x53b9,0x53e9,0x5419,0x5449,0x5479,0x54a9,
-0x54d9,0x5509,0x5539,0x5569,0x5b99,0x5bc9,0x5bf9,0x5c29,0x5c59,0x5c89,0x5cb9,0x5ce9,0x5d19,0x5d49,0x5d79,0x5da9,
-0x5dd9,0x5e09,0x5e39,0x5e69,0x5e99,0x5ec9,0x5ef9,0x5f29,0x5f59,0x5f89,0x5fb9,0x5fe9,0x6019,0x6049,0x6079,0x60a9,
-0x60d9,0x6109,0x6139,0x6169,0x5599,0x55c9,0x55f9,0x5629,0x5659,0x5689,0x56b9,0x56e9,0x5719,0x5749,0x5779,0x57a9,
-0x57d9,0x5809,0x5839,0x5869,0x5899,0x58c9,0x58f9,0x5929,0x5959,0x5989,0x59b9,0x59e9,0x5a19,0x5a49,0x5a79,0x5aa9,
-0x5ad9,0x5b09,0x5b39,0x5b69,0,0,0,0,0,4,0,0,4,0,0,0,
-0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x6199,0x6219,0x6299,0x6319,0x63c9,0x6479,0x6519,0,0,0,0,0,
-0,0,0,0,0,0,0,0x65b9,0x6639,0x66b9,0x6739,0x67b9,0,0,0,0,
-0,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,0,0,0,4,0,0,0,0,
-0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x64,
-0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,4,0,0,4,0,0,
-0,0,0,0,0,0,0,0,0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
+0x44,0,0x44,0x44,0x64,0,0,0x44,0x44,0,0,0,0,0,0x44,0x44,
+0,0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,
+0,0,0,4,4,0,0x64,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0x5279,1,1,1,1,
+1,1,1,4,5,5,5,5,1,1,1,1,1,1,1,1,
+1,5,4,4,0,0,0,0,0x5299,0x52c9,0x52f9,0x5329,0x5359,0x5389,0x53b9,0x53e9,
+0x5419,0x5449,0x5479,0x54a9,0x54d9,0x5509,0x5539,0x5569,0x5b99,0x5bc9,0x5bf9,0x5c29,0x5c59,0x5c89,0x5cb9,0x5ce9,
+0x5d19,0x5d49,0x5d79,0x5da9,0x5dd9,0x5e09,0x5e39,0x5e69,0x5e99,0x5ec9,0x5ef9,0x5f29,0x5f59,0x5f89,0x5fb9,0x5fe9,
+0x6019,0x6049,0x6079,0x60a9,0x60d9,0x6109,0x6139,0x6169,0x5599,0x55c9,0x55f9,0x5629,0x5659,0x5689,0x56b9,0x56e9,
+0x5719,0x5749,0x5779,0x57a9,0x57d9,0x5809,0x5839,0x5869,0x5899,0x58c9,0x58f9,0x5929,0x5959,0x5989,0x59b9,0x59e9,
+0x5a19,0x5a49,0x5a79,0x5aa9,0x5ad9,0x5b09,0x5b39,0x5b69,0,0,0,0,0,4,0,0,
+4,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x6199,0x6219,0x6299,0x6319,0x63c9,0x6479,0x6519,0,
+0,0,0,0,0,0,0,0,0,0,0,0x65b9,0x6639,0x66b9,0x6739,0x67b9,
+0,0,0,0,0,0,0x64,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,
+0x44,0x44,0x44,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x44,0x44,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,
+0,4,0,0,0,0,0,0,0,0,0,0,0,0x1012,0x1012,0x1012,
0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
-0x1012,0x1012,0x1012,0,0,0,4,0,4,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
+0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0,0,0,4,0,4,0xf011,0xf011,0xf011,
0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
-0xf011,0xf011,0xf011,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,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,4,4,4,
+0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,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,0,0,0,0,0,0x64,0,0,
-0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,4,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,
-0,0,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0x1412,0x1412,0x1412,0x1412,
+0,0x64,0,0,0x64,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,
+0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,
0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,
-0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0xec11,0xec11,0xec11,0xec11,
-0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,
-0xec11,0xec11,0xec11,0xec11,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,
-0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0,0,0,0,0xec11,0xec11,0xec11,0xec11,
0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,
0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,
-0x1392,0x1392,0x1392,0,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0,0x1392,0x1392,0,0xec91,
-0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0,0xec91,0xec91,0xec91,0xec91,0xec91,
-0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0,0xec91,0xec91,0xec91,0xec91,0xec91,
-0xec91,0xec91,0,0xec91,0xec91,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
-5,5,5,0,0,0,0,0,5,4,4,5,5,5,0,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,4,4,4,0,4,4,0,
-0,0,0,0,4,0x64,4,0x44,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x44,0x64,0x64,0,0,0,0,0x64,0,0,0,0,0,0x44,0x64,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,
+0,0,0,0,0,0,0,0,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,
+0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0x1412,0,0,0,0,
+0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,
+0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0xec11,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x1392,0x1392,0x1392,0x1392,
+0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0,
+0x1392,0x1392,0,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0,0xec91,
+0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0,0xec91,
+0xec91,0xec91,0xec91,0xec91,0xec91,0xec91,0,0xec91,0xec91,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,5,5,0,0,0,0,0,5,4,4,5,
+5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,4,4,4,
+0,4,4,0,0,0,0,0,4,0x64,4,0x44,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x44,0x64,0x64,0,0,0,0,0x64,0,0,0,0,
+0,0x44,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x2012,0x2012,0x2012,0x2012,
0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,
-0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,
+0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0x2012,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0xe011,0xe011,0xe011,0xe011,
0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,
-0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0,0,0,0,
+0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0xe011,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0x44,0x44,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,0x64,
-0x44,0x44,0x44,0x64,0x44,0x64,0x64,0x64,0x64,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0x44,0x64,0x44,0x64,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,
-4,4,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,4,
-4,0,0,0,0,0,0,0,0,0,0,0x64,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-4,4,4,0,0,0x64,0x64,0,0,4,0,0,0,0,4,0,
-0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,
+0,0,0,0,0,0,0x64,0x64,0x44,0x44,0x44,0x64,0x44,0x64,0x64,0x64,
+0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x44,0x64,0x44,0x64,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-4,4,4,4,0,4,4,4,4,4,4,0x64,0x64,0,0,0,
+4,4,4,4,4,4,4,4,4,4,0x64,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x64,0,0,4,4,0,0,0,0,0,0,0,
0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,
-4,4,4,0,0x60,0,0,0,0,0,0,0,0,4,0x64,4,
-4,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,4,4,0,0,4,0x60,0x64,4,
-0,0,0,0,0,0,4,0,0,0,0,4,4,4,4,4,
-4,0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0x60,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,
-0x44,0,0,0,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x64,4,4,0,0x64,0,0,0,0,0,
+0,0,0,0,0,0,0,4,4,4,4,0,0,0x64,0x64,0,
+0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x44,0x44,0x44,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,4,4,4,4,4,0,4,0,
-0,0,0,4,4,0,0x64,0x64,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,4,4,4,4,0,4,4,4,
+4,4,4,0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0x64,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,4,4,4,4,0,0,0,0,0,0,
-4,4,0,0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,
+0,0,4,4,4,4,4,4,4,4,4,0,0x60,0,0,0,
+0,0,0,0,0,4,0x64,4,4,0,0,4,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+4,4,0,0,4,0x60,0x64,4,0,0,0,0,0,0,4,0,
+0,0,0,4,4,4,4,4,4,0x64,0x64,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,0,
-0,4,0,0x64,0,0,0,0,0,0,0,0,0,0,0,4,
-0,4,0,0,4,4,4,4,4,4,0x60,0x64,0,0,0,0,
+4,0,0,0,0,0,0,0,0,0,0,0,0,0x60,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,4,4,4,0,0,4,4,
-4,4,0,4,4,4,4,0x64,0,0,0,0,0,0,0,0,
+0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0x44,0x44,0x44,0x44,
+0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,0x64,4,
+4,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x44,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-4,4,4,4,4,4,4,4,0,0x64,0x64,0,0,0,0,0,
-0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
-0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
-0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
-0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
+4,4,4,4,4,0,4,0,0,0,0,4,4,0,0x64,0x64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,4,4,0x60,0x64,0,
-0,0,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,
+4,4,0,0,0,0,0,0,4,4,0,0x64,0x64,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-4,4,4,4,0,0,4,4,0,0,0,0,0,4,4,4,
-4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-0x64,4,4,4,4,0,0,4,4,4,4,0,0,0,0,0,
-0,0,0,0x64,0,0,0,0,0,0,0,0,0,4,4,4,
-4,4,4,0,0,4,4,4,0,0,0,0,0,0,0,0,
-0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,0,
-4,0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,4,4,4,4,4,4,4,0,4,4,4,4,
-4,4,0,0x64,4,4,4,4,4,4,4,4,0,0,4,4,
-4,4,4,4,4,0,4,4,0,4,4,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,
-4,4,4,0,0,0,4,0,4,4,0,4,4,4,0x64,4,
-0x64,0x64,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,4,4,0,0,
-0,4,0,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
-4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x64,0x64,0x64,0x64,0x64,0,0,0,
+4,4,4,4,4,4,4,0,0,4,0,0x64,0,0,0,0,
+0,0,0,0,0,0,0,4,0,4,0,0,4,4,4,4,
+4,4,0x60,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,4,4,4,0,0,4,4,4,4,0,4,4,4,4,0x64,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,
-0,0,0,0,0,0,0,0,0x60,0x60,0,0,0,0,0,0,
+0,0x64,0x64,0,0,0,0,0,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
+0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,
+0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0x1012,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
+0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,
+0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0xf011,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,4,0x60,0x64,0,0,0,0,0x64,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,4,4,4,4,0,0,4,4,
+0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,4,0x64,4,4,4,4,0,0,4,
+4,4,4,0,0,0,0,0,0,0,0,0x64,0,0,0,0,
+0,0,0,0,0,4,4,4,4,4,4,0,0,4,4,4,
+0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,
+4,4,4,4,4,4,4,0,4,0x64,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
-0,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,
+4,4,4,0,4,4,4,4,4,4,0,0x64,4,4,4,4,
+4,4,4,4,0,0,4,4,4,4,4,4,4,0,4,4,
+0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,4,4,4,4,4,4,0,0,0,4,0,
+4,4,0,4,4,4,0x64,4,0x64,0x64,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,0,4,0x64,0,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,
+0,0,0,0,4,4,0,0,0,4,0,0x64,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+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,4,4,4,4,4,0,
+0,0,0,0,4,0x60,0x64,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0x60,0x60,0x64,0x64,0x64,0,0,
-0,0x60,0x60,0x60,0x60,0x60,0x60,4,4,4,4,4,4,4,4,0x64,
-0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0,0x44,0x44,0x44,0x44,0x44,0x64,0x64,
+0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,4,4,0,0,0,0,0,0,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x64,0x64,0x64,0x64,
+0x64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,
+4,0,0,0,0,0,0,0,0,0,0,0,0x60,0x60,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,4,0x64,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0x60,0x60,0x64,
+0x64,0x64,0,0,0,0x60,0x60,0x60,0x60,0x60,0x60,4,4,4,4,4,
+4,4,4,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0,0x44,0x44,0x44,
+0x44,0x44,0x64,0x64,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0x44,0x44,0x44,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0x44,0x44,0x44,0x44,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x44,0x44,
-0x44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,1,1,1,1,1,1,1,1,0x21,0x21,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
-1,1,1,1,1,0,0x21,0x21,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,
1,1,0x21,0x21,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,2,0,2,2,0,0,2,0,0,2,2,0,
-0,2,2,2,2,0,2,2,2,2,2,2,2,2,1,1,
-1,1,0,1,0,1,0x21,0x21,1,1,1,1,0,1,1,1,
-1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,1,1,1,1,2,2,0,2,
-2,2,2,0,0,2,2,2,2,2,2,2,2,0,2,2,
-2,2,2,2,2,0,1,1,1,1,1,1,1,1,0x21,0x21,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-2,2,0,2,2,2,2,0,2,2,2,2,2,0,2,0,
-0,0,2,2,2,2,2,2,2,0,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,1,1,1,1,1,1,1,0,0x21,0x21,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
+1,1,1,1,1,1,0x21,0x21,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,2,0,2,2,0,0,2,0,
+0,2,2,0,0,2,2,2,2,0,2,2,2,2,2,2,
+2,2,1,1,1,1,0,1,0,1,0x21,0x21,1,1,1,1,
+0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+2,2,0,2,2,2,2,0,0,2,2,2,2,2,2,2,
+2,0,2,2,2,2,2,2,2,0,1,1,1,1,1,1,
1,1,0x21,0x21,1,1,1,1,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,0,2,2,2,2,0,2,2,2,2,
+2,0,2,0,0,0,2,2,2,2,2,2,2,0,1,1,
+1,1,1,1,1,1,0x21,0x21,1,1,1,1,1,1,1,1,
1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,1,1,1,1,1,1,0,0,2,2,2,2,
+2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,0,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
-1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
+2,2,2,2,2,2,2,2,2,0,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,0,1,1,1,1,1,1,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,0,
-1,1,1,1,1,1,2,1,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
+1,1,1,0,1,1,1,1,1,1,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+1,1,1,0,1,1,1,1,1,1,2,1,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,0,0,0,0,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,0,0,0,0,0,0,0,0,4,0,0,
-0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
-4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0x44,0x44,0x44,0x44,
-0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,0,0x44,
-0x44,0x44,0x44,0x44,1,1,1,1,1,1,1,1,1,1,0,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x21,1,
-1,1,1,0,0x44,0x44,0,0x44,0x44,0,0x44,0x44,0x44,0x44,0x44,0,
+4,4,4,4,4,4,4,0,0,0,0,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,
+0,4,0,0,0,0,0,0,0,0,0,0,4,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0,
+0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
+0x44,0,0,0x44,0x44,0x44,0x44,0x44,1,1,1,1,1,1,1,1,
+1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,0x21,1,1,1,1,0,0,0,0,0,0,1,1,1,
+1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x44,0x44,0,0x44,0x44,0,0x44,0x44,
+0x44,0x44,0x44,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x25,5,5,5,5,5,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0x44,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+0x25,0x25,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0x44,0x44,0x44,0x44,0x44,0x44,0x44,4,4,4,4,4,
-4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
+0x64,0x64,0x64,0x44,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0,0,0,0,0,
0,0,0,0,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,
0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,0x1112,
@@ -965,17 +980,17 @@ static const UCaseProps ucase_props_singleton={
ucase_props_unfold,
{
ucase_props_trieIndex,
- ucase_props_trieIndex+3408,
+ ucase_props_trieIndex+3412,
NULL,
- 3408,
- 9500,
+ 3412,
+ 9736,
0x188,
- 0xdcc,
+ 0xdd0,
0x0,
0x0,
0xe0800,
- 0x3268,
- NULL, 0, FALSE, FALSE, 0, NULL
+ 0x3358,
+ NULL, 0, false, false, 0, NULL
},
{ 4,0,0,0 }
};
diff --git a/thirdparty/icu4c/common/ucasemap.cpp b/thirdparty/icu4c/common/ucasemap.cpp
index 95b55d56a0..fc0439db0f 100644
--- a/thirdparty/icu4c/common/ucasemap.cpp
+++ b/thirdparty/icu4c/common/ucasemap.cpp
@@ -157,7 +157,7 @@ appendResult(int32_t cpLength, int32_t result, const UChar *s,
ByteSinkUtil::appendCodePoint(cpLength, result, sink, edits);
}
}
- return TRUE;
+ return true;
}
// See unicode/utf8.h U8_APPEND_UNSAFE().
@@ -525,14 +525,14 @@ ucasemap_internalUTF8ToTitle(
csc.p=(void *)src;
csc.limit=srcLength;
int32_t prev=0;
- UBool isFirstIndex=TRUE;
+ UBool isFirstIndex=true;
/* titlecasing loop */
while(prev<srcLength) {
/* find next index where to titlecase */
int32_t index;
if(isFirstIndex) {
- isFirstIndex=FALSE;
+ isFirstIndex=false;
index=iter->first();
} else {
index=iter->next();
@@ -643,12 +643,12 @@ UBool isFollowedByCasedLetter(const uint8_t *s, int32_t i, int32_t length) {
if ((type & UCASE_IGNORABLE) != 0) {
// Case-ignorable, continue with the loop.
} else if (type != UCASE_NONE) {
- return TRUE; // Followed by cased letter.
+ return true; // Followed by cased letter.
} else {
- return FALSE; // Uncased and not case-ignorable.
+ return false; // Uncased and not case-ignorable.
}
}
- return FALSE; // Not followed by cased letter.
+ return false; // Not followed by cased letter.
}
// Keep this consistent with the UTF-16 version in ustrcase.cpp and the Java version in CaseMap.java.
@@ -707,7 +707,7 @@ void toUpper(uint32_t options,
nextState |= AFTER_VOWEL_WITH_ACCENT;
}
// Map according to Greek rules.
- UBool addTonos = FALSE;
+ UBool addTonos = false;
if (upper == 0x397 &&
(data & HAS_ACCENT) != 0 &&
numYpogegrammeni == 0 &&
@@ -718,7 +718,7 @@ void toUpper(uint32_t options,
if (i == nextIndex) {
upper = 0x389; // Preserve the precomposed form.
} else {
- addTonos = TRUE;
+ addTonos = true;
}
} else if ((data & HAS_DIALYTIKA) != 0) {
// Preserve a vowel with dialytika in precomposed form if it exists.
@@ -733,7 +733,7 @@ void toUpper(uint32_t options,
UBool change;
if (edits == nullptr && (options & U_OMIT_UNCHANGED_TEXT) == 0) {
- change = TRUE; // common, simple usage
+ change = true; // common, simple usage
} else {
// Find out first whether we are changing the text.
U_ASSERT(0x370 <= upper && upper <= 0x3ff); // 2-byte UTF-8, main Greek block
diff --git a/thirdparty/icu4c/common/uchar.cpp b/thirdparty/icu4c/common/uchar.cpp
index 61e9c3d900..7789a3b88a 100644
--- a/thirdparty/icu4c/common/uchar.cpp
+++ b/thirdparty/icu4c/common/uchar.cpp
@@ -126,7 +126,7 @@ u_isxdigit(UChar32 c) {
(c<=0x66 && c>=0x41 && (c<=0x46 || c>=0x61)) ||
(c>=0xff21 && c<=0xff46 && (c<=0xff26 || c>=0xff41))
) {
- return TRUE;
+ return true;
}
GET_PROPS(c, props);
@@ -249,7 +249,7 @@ U_CAPI UBool U_EXPORT2
u_isprint(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
- /* comparing ==0 returns FALSE for the categories mentioned */
+ /* comparing ==0 returns false for the categories mentioned */
return (UBool)((CAT_MASK(props)&U_GC_C_MASK)==0);
}
@@ -273,7 +273,7 @@ U_CAPI UBool U_EXPORT2
u_isgraph(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
- /* comparing ==0 returns FALSE for the categories mentioned */
+ /* comparing ==0 returns false for the categories mentioned */
return (UBool)((CAT_MASK(props)&
(U_GC_CC_MASK|U_GC_CF_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
==0);
@@ -291,7 +291,7 @@ u_isgraphPOSIX(UChar32 c) {
uint32_t props;
GET_PROPS(c, props);
/* \p{space}\p{gc=Control} == \p{gc=Z}\p{Control} */
- /* comparing ==0 returns FALSE for the categories mentioned */
+ /* comparing ==0 returns false for the categories mentioned */
return (UBool)((CAT_MASK(props)&
(U_GC_CC_MASK|U_GC_CS_MASK|U_GC_CN_MASK|U_GC_Z_MASK))
==0);
@@ -591,7 +591,7 @@ uscript_hasScript(UChar32 c, UScriptCode sc) {
uint32_t sc32=sc;
if(sc32>0x7fff) {
/* Guard against bogus input that would make us go past the Script_Extensions terminator. */
- return FALSE;
+ return false;
}
while(sc32>*scx) {
++scx;
@@ -654,7 +654,7 @@ _enumPropertyStartsRange(const void *context, UChar32 start, UChar32 end, uint32
sa->add(sa->set, start);
(void)end;
(void)value;
- return TRUE;
+ return true;
}
#define USET_ADD_CP_AND_NEXT(sa, cp) sa->add(sa->set, cp); sa->add(sa->set, cp+1)
diff --git a/thirdparty/icu4c/common/uchar_props_data.h b/thirdparty/icu4c/common/uchar_props_data.h
index c45b9da3fd..acbeadd249 100644
--- a/thirdparty/icu4c/common/uchar_props_data.h
+++ b/thirdparty/icu4c/common/uchar_props_data.h
@@ -9,146 +9,146 @@
#ifdef INCLUDED_FROM_UCHAR_C
-static const UVersionInfo dataVersion={0xe,0,0,0};
+static const UVersionInfo dataVersion={0xf,0,0,0};
-static const uint16_t propsTrie_index[22688]={
-0x48c,0x494,0x49c,0x4a4,0x4bc,0x4c4,0x4cc,0x4d4,0x4dc,0x4e4,0x4ea,0x4f2,0x4fa,0x502,0x50a,0x512,
-0x518,0x520,0x528,0x530,0x533,0x53b,0x543,0x54b,0x553,0x55b,0x557,0x55f,0x567,0x56f,0x574,0x57c,
-0x584,0x58c,0x590,0x598,0x5a0,0x5a8,0x5b0,0x5b8,0x5b4,0x5bc,0x5c1,0x5c9,0x5cf,0x5d7,0x5df,0x5e7,
-0x5ef,0x5f7,0x5ff,0x607,0x60c,0x614,0x617,0x61f,0x627,0x62f,0x635,0x63d,0x63c,0x644,0x64c,0x654,
-0x664,0x65c,0x66c,0x674,0x67a,0x5f7,0x68a,0x682,0x69a,0x69c,0x6a4,0x692,0x6b4,0x6ba,0x6c2,0x6ac,
-0x6d2,0x6d8,0x6e0,0x6ca,0x6f0,0x6f6,0x6fe,0x6e8,0x70e,0x714,0x71c,0x706,0x72c,0x734,0x73c,0x724,
-0x74c,0x752,0x75a,0x744,0x76a,0x770,0x778,0x762,0x788,0x78d,0x795,0x780,0x7a5,0x7ac,0x7b4,0x79d,
-0x638,0x7bc,0x7c4,0x4ac,0x7cc,0x7d3,0x7db,0x4ac,0x7e3,0x7eb,0x7f3,0x7f8,0x800,0x807,0x80f,0x4ac,
-0x5f7,0x817,0x81f,0x827,0x82f,0x584,0x83f,0x837,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x847,0x5f7,0x84f,0x853,0x85b,0x5f7,0x861,0x5f7,0x867,0x86f,0x877,0x584,0x584,0x87f,
-0x887,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x88c,0x894,0x5f7,0x5f7,0x89c,0x8a4,0x8ac,0x8b4,0x8bc,0x5f7,0x8c4,0x8cc,0x8d4,
-0x8e4,0x5f7,0x8ec,0x8ee,0x8f6,0x8dc,0x5f7,0x8f9,0x90d,0x901,0x909,0x915,0x5f7,0x91d,0x923,0x92b,
-0x933,0x5f7,0x943,0x94b,0x953,0x93b,0x963,0x4ac,0x96b,0x96e,0x976,0x95b,0x986,0x97e,0x5f7,0x98d,
-0x5f7,0x99c,0x995,0x9a4,0x9ac,0x9b0,0x9b8,0x9c0,0x52c,0x9c8,0x9cb,0x9d1,0x9d8,0x9cb,0x553,0x553,
-0x4dc,0x4dc,0x4dc,0x4dc,0x9e0,0x4dc,0x4dc,0x4dc,0x9f0,0x9f8,0xa00,0xa08,0xa10,0xa14,0xa1c,0x9e8,
-0xa34,0xa3c,0xa24,0xa2c,0xa44,0xa4c,0xa54,0xa5c,0xa74,0xa64,0xa6c,0xa7c,0xa84,0xa93,0xa98,0xa8b,
-0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa8,0xab0,0x92b,0xab3,0xabb,0xac2,0xac7,0xacf,
-0x92b,0xad6,0xad5,0xae6,0xae9,0x92b,0x92b,0xade,0x92b,0x92b,0x92b,0x92b,0x92b,0xaf8,0xb00,0xaf0,
-0x92b,0x92b,0x92b,0xb05,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0xb0b,0xb13,0x92b,0xb1b,0xb22,
-0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0xaa0,0xaa0,0xaa0,0xaa0,0xb2a,0xaa0,0xb31,0xb38,
-0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0xaa0,0x92b,0xb40,0xb47,0xb4b,0xb51,0x92b,0x92b,0x92b,
-0x584,0x58c,0x52c,0xb59,0x4dc,0x4dc,0x4dc,0xb61,0x52c,0xb69,0x5f7,0xb6f,0xb7f,0xb77,0xb77,0x553,
-0xb87,0xb8f,0xb97,0x4ac,0xb9f,0x92b,0x92b,0xba6,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0xbae,0xbb4,
-0xbc4,0xbbc,0x638,0x5f7,0xbcc,0x887,0x5f7,0xbd4,0xbdc,0xbe0,0x5f7,0x5f7,0xbe5,0x5f7,0x92b,0xbec,
-0xad0,0xbf4,0xbfa,0x92b,0xbf4,0xc02,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,
-0xc0a,0x5f7,0x5f7,0x5f7,0xc12,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0xc18,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc1d,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x92b,0x92b,
-0xc25,0x5f7,0xc28,0x5f7,0xc30,0xc36,0xc3e,0xc46,0xc4b,0x5f7,0x5f7,0xc4f,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc56,0x5f7,0xc5d,0xc63,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc6b,0x5f7,0x5f7,0x5f7,0xc73,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc75,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc7c,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0xc83,0x5f7,0x5f7,0x5f7,0xc8a,0xc92,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc97,0x5f7,0x5f7,0xc9f,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xca3,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xca6,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xca9,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0xcaf,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0xcb7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0xcbc,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xcc1,0x5f7,0x5f7,0x5f7,0xcc6,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0xcce,0xcd5,0xcd9,0x5f7,0x5f7,0x5f7,0xce0,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0xcee,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0xce6,0x92b,0xcf6,0x9a4,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0xcfb,0xd03,0x4dc,0xd13,0xd0b,0x5f7,0x5f7,0xd1b,0xd23,0xd33,0x4dc,0xd38,0xd40,0xd46,0xd4d,0xd2b,
-0xd55,0xd5d,0x5f7,0xd65,0xd75,0xd78,0xd6d,0xd80,0x64c,0xd88,0xd8f,0x8ed,0x69a,0xd9f,0xd97,0xda7,
-0x5f7,0xdaf,0xdb7,0xdbf,0x5f7,0xdc7,0xdcf,0xdd7,0xddf,0xde7,0xdeb,0xdf3,0x52c,0x52c,0x5f7,0xdfb,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xe03,0xe0f,0xe07,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,
-0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0x5f7,0x5f7,0x5f7,0xe27,0x5f7,0xce1,0xe2e,0xe33,
-0x5f7,0x5f7,0x5f7,0xe3b,0x5f7,0x5f7,0x8f8,0x4ac,0xe51,0xe41,0xe49,0x5f7,0x5f7,0xe59,0xe61,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xe66,0x92f,0x5f7,0xe6e,0x5f7,0xe74,0xe78,
-0xe80,0xe88,0xe8f,0xe97,0x5f7,0x5f7,0x5f7,0xe9d,0xeb5,0x49c,0xebd,0xec5,0xeca,0x90d,0xea5,0xead,
-0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,
-0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,0xe17,
-0x12b0,0x12b0,0x12f0,0x1330,0x1370,0x13a8,0x13e8,0x1428,0x1460,0x14a0,0x14cc,0x150c,0x154c,0x155c,0x159c,0x15d0,
-0x1610,0x1640,0x1680,0x16c0,0x16d0,0x1704,0x173c,0x177c,0x17bc,0x17fc,0x1830,0x185c,0x189c,0x18d4,0x18f0,0x1930,
-0xa80,0xac0,0xb00,0xb40,0xb80,0xbab,0xbeb,0xa40,0xc0d,0xa40,0xa40,0xa40,0xa40,0xc4d,0x1db,0x1db,
-0xc8d,0xccd,0xa40,0xa40,0xa40,0xcf6,0xd36,0xd56,0xa40,0xd7c,0xdbc,0xdfc,0xe3c,0xe7c,0xebc,0xefc,
-0xf3c,0xf73,0x1db,0x1db,0xf97,0xfcb,0x1db,0xff3,0x1db,0x1db,0x1db,0x1db,0x1020,0x1db,0x1db,0x1db,
-0x1db,0x1db,0x1db,0x1db,0x1034,0x1db,0x106c,0x10ac,0x1db,0x10b7,0x1db,0x1db,0x1db,0x10ed,0xa40,0x112d,
-0x1db,0x1db,0x116d,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+static const uint16_t propsTrie_index[23016]={
+0x495,0x49d,0x4a5,0x4ad,0x4c5,0x4cd,0x4d5,0x4dd,0x4e5,0x4ed,0x4f3,0x4fb,0x503,0x50b,0x513,0x51b,
+0x521,0x529,0x531,0x539,0x53c,0x544,0x54c,0x554,0x55c,0x564,0x560,0x568,0x570,0x578,0x57d,0x585,
+0x58d,0x595,0x599,0x5a1,0x5a9,0x5b1,0x5b9,0x5c1,0x5bd,0x5c5,0x5ca,0x5d2,0x5d8,0x5e0,0x5e8,0x5f0,
+0x5f8,0x600,0x608,0x610,0x615,0x61d,0x620,0x628,0x630,0x638,0x63e,0x646,0x645,0x64d,0x655,0x65d,
+0x66d,0x665,0x675,0x67d,0x683,0x600,0x693,0x68b,0x6a3,0x6a5,0x6ad,0x69b,0x6bd,0x6c3,0x6cb,0x6b5,
+0x6db,0x6e1,0x6e9,0x6d3,0x6f9,0x6ff,0x707,0x6f1,0x717,0x71d,0x725,0x70f,0x735,0x73d,0x745,0x72d,
+0x755,0x75b,0x763,0x74d,0x773,0x779,0x781,0x76b,0x791,0x796,0x79e,0x789,0x7ae,0x7b5,0x7bd,0x7a6,
+0x641,0x7c5,0x7cd,0x4b5,0x7d5,0x7dc,0x7e4,0x4b5,0x7ec,0x7f4,0x7fc,0x801,0x809,0x810,0x818,0x4b5,
+0x600,0x820,0x828,0x830,0x838,0x58d,0x848,0x840,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x850,0x600,0x858,0x85c,0x864,0x600,0x86a,0x600,0x870,0x878,0x880,0x58d,0x58d,0x888,
+0x890,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x895,0x89d,0x600,0x600,0x8a5,0x8ad,0x8b5,0x8bd,0x8c5,0x600,0x8cd,0x8d5,0x8dd,
+0x8ed,0x600,0x8f5,0x8f7,0x8ff,0x8e5,0x600,0x902,0x916,0x90a,0x912,0x91e,0x600,0x926,0x92c,0x934,
+0x93c,0x600,0x94c,0x954,0x95c,0x944,0x96c,0x4b5,0x974,0x977,0x97f,0x964,0x98f,0x987,0x600,0x996,
+0x600,0x9a5,0x99e,0x9ad,0x9b5,0x9b9,0x9c1,0x9c9,0x535,0x9d1,0x9d4,0x9da,0x9e1,0x9d4,0x55c,0x55c,
+0x4e5,0x4e5,0x4e5,0x4e5,0x9e9,0x4e5,0x4e5,0x4e5,0x9f9,0xa01,0xa09,0xa11,0xa19,0xa1d,0xa25,0x9f1,
+0xa3d,0xa45,0xa2d,0xa35,0xa4d,0xa55,0xa5d,0xa65,0xa7d,0xa6d,0xa75,0xa85,0xa8d,0xa9c,0xaa1,0xa94,
+0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xab1,0xab9,0x934,0xabc,0xac4,0xacb,0xad0,0xad8,
+0x934,0xadf,0xade,0xaef,0xaf2,0x934,0x934,0xae7,0x934,0x934,0x934,0x934,0x934,0xb01,0xb09,0xaf9,
+0x934,0x934,0x934,0xb0e,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0xb14,0xb1c,0x934,0xb24,0xb2b,
+0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0xaa9,0xaa9,0xaa9,0xaa9,0xb33,0xaa9,0xb3a,0xb41,
+0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0xaa9,0x934,0xb49,0xb50,0xb54,0xb5a,0x934,0x934,0x934,
+0x58d,0x595,0x535,0xb62,0x4e5,0x4e5,0x4e5,0xb6a,0x535,0xb72,0x600,0xb78,0xb88,0xb80,0xb80,0x55c,
+0xb90,0xb98,0xba0,0x4b5,0xba8,0x934,0x934,0xbaf,0x934,0x934,0x934,0x934,0x934,0x934,0xbb7,0xbbd,
+0xbcd,0xbc5,0x641,0x600,0xbd5,0x890,0x600,0xbdd,0xbe5,0xbe9,0x600,0x600,0xbee,0x600,0x934,0xbf5,
+0xad9,0xbfd,0xc03,0x934,0xbfd,0xc0b,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,
+0xc13,0x600,0x600,0x600,0xc1b,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0xc21,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc26,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x934,0x934,
+0xc2e,0x600,0xc31,0x600,0xc39,0xc3f,0xc47,0xc4f,0xc54,0x600,0x600,0xc58,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc5f,0x600,0xc66,0xc6c,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc74,0x600,0x600,0x600,0xc7c,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0xc7e,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc85,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0xc8c,0x600,0x600,0x600,0xc93,0xc9b,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xca0,0x600,0x600,0xca8,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcac,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcaf,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xcb2,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0xcb8,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0xcc0,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0xcc5,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0xcca,0x600,0x600,0x600,0xccf,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0xcd7,0xcde,0xce2,0x600,0x600,0x600,0xce9,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0xcf7,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0xcef,0x934,0xcff,0x9ad,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0xd04,0xd0c,0x4e5,0xd1c,0xd14,0x600,0x600,0xd24,0xd2c,0xd3c,0x4e5,0xd41,0xd49,0xd4f,0xd56,0xd34,
+0xd5e,0xd66,0x600,0xd6e,0xd7e,0xd81,0xd76,0xd89,0x655,0xd91,0xd98,0x8f6,0x6a3,0xda8,0xda0,0xdb0,
+0x600,0xdb8,0xdc0,0xdc8,0x600,0xdd0,0xdd8,0xde0,0xde8,0xdf0,0xdf4,0xdfc,0x535,0x535,0x600,0xe04,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe0c,0xe18,0xe10,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,
+0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0x600,0x600,0x600,0xe30,0x600,0xcea,0xe37,0xe3c,
+0x600,0x600,0x600,0xe44,0x600,0x600,0x901,0x4b5,0xe5a,0xe4a,0xe52,0x600,0x600,0xe62,0xe6a,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe6f,0x938,0x600,0xe77,0x600,0xe7d,0xe81,
+0xe89,0xe91,0xe98,0xea0,0x600,0x600,0x600,0xea6,0xebe,0x4a5,0xec6,0xece,0xed3,0x916,0xeae,0xeb6,
+0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,
+0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,0xe20,
+0x12d4,0x12d4,0x1314,0x1354,0x1394,0x13cc,0x140c,0x144c,0x1484,0x14c4,0x14f0,0x1530,0x1570,0x1580,0x15c0,0x15f4,
+0x1634,0x1664,0x16a4,0x16e4,0x16f4,0x1728,0x1760,0x17a0,0x17e0,0x1820,0x1854,0x1880,0x18c0,0x18f8,0x1914,0x1954,
+0xa80,0xac0,0xb00,0xb40,0xb80,0xbab,0xbeb,0xa40,0xc0e,0xa40,0xa40,0xa40,0xa40,0xc4e,0x1db,0x1db,
+0xc8e,0xcce,0xa40,0xa40,0xa40,0xcf7,0xd37,0xd57,0xa40,0xd7d,0xdbd,0xdfd,0xe3d,0xe7d,0xebd,0xefd,
+0xf3d,0xf74,0x1db,0x1db,0xf98,0xfcc,0x1db,0xff4,0x1db,0x1db,0x1db,0x1db,0x1021,0x1db,0x1db,0x1db,
+0x1db,0x1db,0x1db,0x1db,0x1035,0x1db,0x106d,0x10ad,0x1db,0x10b8,0x1db,0x1db,0x1db,0x10ee,0xa40,0x112e,
+0x1db,0x1db,0x116e,0x1db,0x1191,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
@@ -170,1033 +170,1044 @@ static const uint16_t propsTrie_index[22688]={
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
-0x11ad,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
+0x11d1,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,
-0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x11ed,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x1211,
0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,
-0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x11ed,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0xed2,0xed9,0xee1,0x4ac,0x5f7,0x5f7,0x5f7,0xee9,0xef9,0xef1,0xf10,0xf01,0xf08,0xf18,0xf1c,0xf20,
-0x4ac,0x4ac,0x4ac,0x4ac,0x8ed,0x5f7,0xf28,0xf30,0x5f7,0xf38,0xf40,0xf44,0xf4c,0x5f7,0xf54,0x4ac,
-0x584,0x58e,0xf5c,0x5f7,0xf60,0xf68,0xf78,0xf70,0x5f7,0xf80,0x5f7,0xf87,0xf97,0xf8f,0x4ac,0x4ac,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xb7f,0x8f9,0xf9f,0xfaf,0xfa7,0x4ac,0x4ac,
-0xfbf,0xfb7,0xfc2,0xfca,0x90d,0xfd2,0x4ac,0xfda,0xfe2,0xfea,0x4ac,0x4ac,0x5f7,0xffa,0x1002,0xff2,
-0x1012,0x1019,0x100a,0x1021,0x1029,0x4ac,0x1039,0x1031,0x5f7,0x103c,0x1044,0x104c,0x1054,0x105c,0x4ac,0x4ac,
-0x5f7,0x5f7,0x1064,0x4ac,0x584,0x106c,0x52c,0x1074,0x5f7,0x107c,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x1084,0x5f7,0x108c,0x4ac,0x4ac,0x1094,0x109c,0x10a3,0xfd6,0x10ab,0xfd6,0x10b3,0xb7f,
-0x10c3,0x62d,0x10cb,0x10bb,0x986,0x10d3,0x10db,0x10e1,0x10f9,0x10e9,0x10f1,0x10fd,0x986,0x110d,0x1105,0x1115,
-0x1125,0x111d,0x4ac,0x4ac,0x112c,0x1134,0x64f,0x113c,0x114c,0x1152,0x115a,0x1144,0x4ac,0x4ac,0x4ac,0x4ac,
-0x5f7,0x1162,0x116a,0x1172,0x5f7,0x117a,0x1182,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x118a,0x1192,0x4ac,
-0x5f7,0x119a,0x11a2,0x11aa,0x5f7,0x11ba,0x11b2,0x4ac,0x867,0x11c2,0x11ca,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x5f7,0x11d2,0x4ac,0x4ac,0x4ac,0x584,0x52c,0x11da,0x11ea,0x11f0,0x11e2,0x4ac,0x4ac,0x1200,0x1204,0x11f8,
-0x121c,0x120c,0x1214,0x5f7,0x122a,0x1224,0x5f7,0x8ee,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x1240,0x1245,0x1232,0x123a,0x1255,0x124d,0x4ac,0x4ac,0x1264,0x1268,0x125c,0x1278,0x1270,0x11b2,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x127c,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x1283,0x1293,0x128b,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x8f8,0x4ac,0x4ac,0x4ac,
-0x12a3,0x12ab,0x12b3,0x129b,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x12bb,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0xfd6,0x5f7,0x5f7,0x12c3,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x12cb,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x11ca,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x8ee,0x90d,
-0xd9b,0x5f7,0x90d,0x12d3,0x12d8,0x5f7,0x12e8,0x12f0,0x12f8,0x12e0,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x584,
-0x52c,0x1300,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x1308,0x130d,0x1313,0x4ac,0x4ac,0x131b,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x1323,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x8f9,0x4ac,0x1064,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x1329,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x1331,
-0x1335,0x133c,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xe07,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x5f7,0x1342,0x1347,0x134f,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x553,0x135f,0x1366,0x92b,0x92b,0x92b,0x1357,0x4ac,0x92b,0x92b,0x92b,0x92b,
-0x92b,0x92b,0x92b,0xbae,0x92b,0x136d,0x92b,0x1374,0x137c,0x1382,0x92b,0xad5,0x92b,0x92b,0x138a,0x4ac,
-0x4ac,0x4ac,0x4ac,0x1392,0x92b,0x92b,0xad2,0x139a,0x4ac,0x4ac,0x4ac,0x4ac,0x13aa,0x13b1,0x13b6,0x13bc,
-0x13c4,0x13cc,0x13d4,0x13ae,0x13dc,0x13e4,0x13ec,0x13f1,0x13c3,0x13aa,0x13b1,0x13ad,0x13bc,0x13f9,0x13ab,0x13fc,
-0x13ae,0x1404,0x140c,0x1414,0x141b,0x1407,0x140f,0x1417,0x141e,0x140a,0x1426,0x13a2,0x92b,0x92b,0x92b,0x92b,
-0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x553,0x1436,0x553,0x143d,
-0x1444,0x142e,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x1453,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x144b,0x145b,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x146b,0x1463,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0xfd6,0x1473,0x5f7,0x147b,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x1483,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x148b,0x4ac,0x584,0x149b,0x1493,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x14a3,
-0x14b3,0x14ab,0x4ac,0x4ac,0x14c3,0x14bb,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x14d3,0x14db,0x14e3,0x14eb,
-0x14f3,0x14fb,0x4ac,0x14cb,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x92b,0x1503,0x92b,0x92b,
-0xba6,0x136b,0x150b,0xbae,0x1513,0x92b,0x92b,0x92b,0x92b,0xbb0,0x4ac,0x151b,0x1523,0x1527,0x152f,0x1537,
-0x4ac,0x4ac,0x4ac,0x4ac,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x153f,0x92b,0x92b,0x92b,0x92b,
-0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,
-0x92b,0x92b,0x1547,0x154f,0x92b,0x92b,0x92b,0xba6,0x92b,0x92b,0x1557,0x155f,0x1503,0x92b,0x1567,0x92b,
-0x156f,0x1574,0x4ac,0x4ac,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0x92b,0xba6,0x157c,
-0x1588,0x158d,0x1595,0x1584,0x92b,0x92b,0x92b,0x92b,0x159d,0x92b,0xad5,0x11ae,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x15a5,0x5f7,0x5f7,0x15ac,
-0x5f7,0x5f7,0x5f7,0x15b4,0x5f7,0x15bc,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xc87,0x5f7,0x5f7,0x15c4,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x15cc,0x15d4,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0xcc6,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x15db,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x15e2,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x15e9,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x4ac,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x8ee,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xf60,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x1090,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x15f1,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x5f7,
-0x5f7,0x15f9,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0xf60,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,
-0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x15ff,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x160f,0x1607,0x1607,
-0x1607,0x4ac,0x4ac,0x4ac,0x4ac,0x553,0x553,0x553,0x553,0x553,0x553,0x553,0x1617,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,
-0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0x4ac,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
-0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0x161f,0x48b,0x48b,0x48b,
-0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
+0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x700,0x1211,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0xedb,0xee2,0xeea,0x4b5,0x600,0x600,0x600,0xef2,0xf02,0xefa,0xf19,0xf0a,0xf11,0xf21,0xf25,0xf29,
+0x4b5,0x4b5,0x4b5,0x4b5,0x8f6,0x600,0xf31,0xf39,0x600,0xf41,0xf49,0xf4d,0xf55,0x600,0xf5d,0x4b5,
+0x58d,0x597,0xf65,0x600,0xf69,0xf71,0xf81,0xf79,0x600,0xf89,0x600,0xf90,0xfa0,0xf98,0x4b5,0x4b5,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xb88,0x902,0xfa8,0xfb8,0xfb0,0x4b5,0x4b5,
+0xfc8,0xfc0,0xfcb,0xfd3,0x916,0xfdb,0x4b5,0xfe3,0xfeb,0xff3,0x4b5,0x4b5,0x600,0x1003,0x100b,0xffb,
+0x101b,0x1022,0x1013,0x102a,0x1032,0x4b5,0x1042,0x103a,0x600,0x1045,0x104d,0x1055,0x105d,0x1065,0x4b5,0x4b5,
+0x600,0x600,0x106d,0x4b5,0x58d,0x1075,0x535,0x107d,0x600,0x1085,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x108d,0x600,0x1095,0x4b5,0x109a,0x10a2,0x10aa,0x10b1,0xfdf,0x10b9,0xfdf,0x10c1,0xb88,
+0x10d1,0x636,0x10d9,0x10c9,0x98f,0x10e1,0x10e9,0x10ef,0x1107,0x10f7,0x10ff,0x110b,0x98f,0x111b,0x1113,0x1123,
+0x113b,0x112b,0x1133,0x4b5,0x1142,0x114a,0x658,0x1152,0x1162,0x1168,0x1170,0x115a,0x4b5,0x4b5,0x4b5,0x4b5,
+0x600,0x1178,0x1180,0x1099,0x600,0x1188,0x1190,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x1198,0x11a0,0x4b5,
+0x600,0x11a8,0x11b0,0x11b8,0x600,0x11c8,0x11c0,0x4b5,0x870,0x11d0,0x11d8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x600,0x11e0,0x4b5,0x4b5,0x4b5,0x58d,0x535,0x11e8,0x11f8,0x11fe,0x11f0,0x4b5,0x4b5,0x120e,0x1212,0x1206,
+0x122a,0x121a,0x1222,0x600,0x1238,0x1232,0x600,0x8f7,0x1248,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x1256,0x125b,0x1240,0x1250,0x126b,0x1263,0x4b5,0x4b5,0x127a,0x127e,0x1272,0x128e,0x1286,0x11c0,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1292,0x12a2,0x12a7,0x129a,0x4b5,0x4b5,0x12af,0x12bf,0x12b7,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x901,0x4b5,0x4b5,0x4b5,
+0x12cf,0x12d7,0x12df,0x12c7,0x600,0x600,0x600,0x600,0x600,0x600,0x12e7,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0xfdf,0x600,0x600,0x12ef,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x12f7,0x12ff,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x11d8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x8f7,
+0x916,0xda4,0x600,0x916,0x1307,0x130c,0x600,0x131c,0x1324,0x132c,0x1314,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x58d,0x535,0x1334,0x4b5,0x4b5,0x4b5,0x600,0x600,0x133c,0x1341,0x1347,0x4b5,0x4b5,0x134f,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1357,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x902,0x4b5,0x106d,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x135d,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x1365,0x136a,0x1371,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xe10,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,0x600,0x1377,0x137c,0x1384,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x1394,0x139b,0x934,0x934,0x934,0x138c,0x4b5,0x934,0x934,0x934,
+0x934,0x934,0x934,0x934,0xbb7,0x934,0x13a2,0x934,0x13a9,0x13b1,0x13b7,0x934,0xade,0x934,0x934,0x13bf,
+0x4b5,0x4b5,0x4b5,0x13c7,0x13c7,0x934,0x934,0xadb,0x13cf,0x4b5,0x4b5,0x4b5,0x4b5,0x13df,0x13e6,0x13eb,
+0x13f1,0x13f9,0x1401,0x1409,0x13e3,0x1411,0x1419,0x1421,0x1426,0x13f8,0x13df,0x13e6,0x13e2,0x13f1,0x142e,0x13e0,
+0x1431,0x13e3,0x1439,0x1441,0x1449,0x1450,0x143c,0x1444,0x144c,0x1453,0x143f,0x145b,0x13d7,0x934,0x934,0x934,
+0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x55c,0x146b,0x55c,
+0x1472,0x1479,0x1463,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1488,0x1490,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1480,0x1498,0x9d4,
+0x14a8,0x14a0,0x4b5,0x4b5,0x4b5,0x600,0x14b8,0x14b0,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0xfdf,0x14c0,0x600,0x14c8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0xfdf,0x14d0,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x14d8,0x600,0x600,0x600,
+0x600,0x600,0x600,0x14e0,0x4b5,0x58d,0x14f0,0x14e8,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x14f8,0x1508,0x1500,0x4b5,0x4b5,0x1518,0x1510,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x1528,0x1530,0x1538,
+0x1540,0x1548,0x1550,0x4b5,0x1520,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x1558,0x934,
+0x934,0xbaf,0x13a0,0x1560,0xbb7,0x1568,0x934,0x934,0x934,0x934,0xbb9,0x4b5,0x1570,0x1578,0x157c,0x1584,
+0x158c,0x4b5,0x4b5,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x1594,0x934,0x934,0x934,
+0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,
+0x934,0x934,0x934,0x157d,0x159c,0x934,0x934,0x934,0x15a4,0x934,0x934,0x15ab,0x15b3,0x1558,0x934,0x15bb,
+0x934,0x15c3,0x15c8,0x4b5,0x4b5,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0x934,0xbaf,
+0x15d0,0x15d9,0x15dd,0x15e5,0x15d5,0x934,0x934,0x934,0x934,0x15ed,0x934,0xade,0x11bc,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x15f5,0x600,0x600,
+0x15fc,0x600,0x600,0x600,0x1604,0x600,0x160c,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xc90,0x600,0x600,
+0x1614,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x161c,0x1624,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0xccf,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x162b,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1632,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x1639,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x4b5,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x901,0x600,0x600,0x600,0x600,0x600,0x600,0xf69,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1641,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1649,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,
+0x600,0x600,0x1651,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0xf69,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x67d,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x1314,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x1661,0x1659,0x1659,0x1659,0x4b5,0x4b5,0x4b5,0x4b5,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c,0x55c,
+0x1669,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,0x4b5,
+0x4b5,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0x1671,0x494,0x494,0x494,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
-0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x18,0x18,0x18,0x17,
-0x17,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,0x14,0x17,0x15,0x1a,0x16,
-0x1a,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,0x14,0x18,0x15,0x18,0xf,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0xf,0xf,0xf,0xf,0xc,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,
+0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,
+0x18,0x18,0x18,0x17,0x17,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x14,
+0x17,0x15,0x1a,0x16,0x1a,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0x14,
+0x18,0x15,0x18,0xf,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
-0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,
-0xc,0x17,0x19,0x19,0x19,0x19,0x1b,0x17,0x1a,0x1b,5,0x1c,0x18,0x10,0x1b,0x1a,
-0x1b,0x18,0x34b,0x38b,0x1a,2,0x17,0x17,0x1a,0x30b,5,0x1d,0x34cb,0x344b,0x3ccb,0x17,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,0x18,1,1,1,1,1,1,1,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,0x18,2,2,2,2,2,2,2,2,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,1,
-2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+0xf,0xf,0xf,0xf,0xc,0x17,0x19,0x19,0x19,0x19,0x1b,0x17,0x1a,0x1b,5,0x1c,
+0x18,0x10,0x1b,0x1a,0x1b,0x18,0x34b,0x38b,0x1a,2,0x17,0x17,0x1a,0x30b,5,0x1d,
+0x34cb,0x344b,0x3ccb,0x17,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,0x18,1,1,1,1,
+1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,0x18,2,2,2,2,
+2,2,2,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,1,2,1,2,1,2,2,2,1,1,2,1,2,1,1,
-2,1,1,1,2,2,1,1,1,1,2,1,1,2,1,1,
-1,2,2,2,1,1,2,1,1,2,1,2,1,2,1,1,
-2,1,2,2,1,2,1,1,2,1,1,1,2,1,2,1,
-1,2,2,5,1,2,2,2,5,5,5,5,1,3,2,1,
-3,2,1,3,2,1,2,1,2,1,2,1,2,1,2,1,
+1,2,1,2,1,2,1,2,1,2,1,2,2,1,2,1,
2,1,2,1,2,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,2,1,3,2,1,2,1,1,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,1,2,1,2,1,2,2,2,1,1,2,
+1,2,1,1,2,1,1,1,2,2,1,1,1,1,2,1,
+1,2,1,1,1,2,2,2,1,1,2,1,1,2,1,2,
+1,2,1,1,2,1,2,2,1,2,1,1,2,1,1,1,
+2,1,2,1,1,2,2,5,1,2,2,2,5,5,5,5,
+1,3,2,1,3,2,1,3,2,1,2,1,2,1,2,1,
+2,1,2,1,2,1,2,1,2,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,2,1,3,2,
+1,2,1,1,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,2,2,2,2,2,2,1,1,2,1,1,2,
-2,1,2,1,1,1,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,2,2,2,2,2,2,1,1,
+2,1,1,2,2,1,2,1,1,1,1,2,1,2,1,2,
+1,2,1,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,5,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,4,0x1a,0x1a,
-0x1a,0x1a,4,4,4,4,4,4,4,4,4,4,4,4,0x1a,0x1a,
-0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,
-4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,0x1a,4,0x1a,0x1a,0x1a,0x1a,0x1a,
-0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,6,6,6,6,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,4,
+4,4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
+4,4,4,4,4,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,0x1a,4,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,1,2,1,2,
-4,0x1a,1,2,0,0,4,2,2,2,0x17,1,0,0,0,0,
-0x1a,0x1a,1,0x17,1,1,1,0,1,0,1,1,2,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,
-1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,
-2,2,1,1,1,2,2,2,1,2,1,2,1,2,1,2,
+1,2,1,2,4,0x1a,1,2,0,0,4,2,2,2,0x17,1,
+0,0,0,0,0x1a,0x1a,1,0x17,1,1,1,0,1,0,1,1,
+2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,0,1,1,1,1,1,1,1,1,1,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,1,2,2,1,1,1,2,2,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-2,2,2,2,1,2,0x18,1,2,1,1,2,2,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,2,1,2,2,2,2,2,1,2,0x18,1,2,1,1,2,
+2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,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,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+2,2,2,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,0x1b,6,6,6,6,6,7,7,1,2,1,2,1,2,
+1,2,1,2,1,2,0x1b,6,6,6,6,6,7,7,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,2,
+1,2,1,2,1,1,2,1,2,1,2,1,2,1,2,1,
+2,1,2,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,0,0,4,0x17,0x17,
-0x17,0x17,0x17,0x17,2,2,2,2,2,2,2,2,2,2,2,2,
+1,2,1,2,0,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+0,4,0x17,0x17,0x17,0x17,0x17,0x17,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,0x17,0x13,0,0,0x1b,0x1b,0x19,0,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+2,2,2,2,2,2,2,2,2,0x17,0x13,0,0,0x1b,0x1b,0x19,
+0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,0x13,6,0x17,6,6,0x17,
-6,6,0x17,6,0,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,0x17,
-0x17,0,0,0,0,0,0,0,0,0,0,0,0x10,0x10,0x10,0x10,
-0x10,0x10,0x18,0x18,0x18,0x17,0x17,0x19,0x17,0x17,0x1b,0x1b,6,6,6,6,
-6,6,6,6,6,6,6,0x17,0x10,0x17,0x17,0x17,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,
-5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,5,5,6,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,0x13,6,
+0x17,6,6,0x17,6,6,0x17,6,0,0,0,0,0,0,0,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,5,
+5,5,5,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,
+0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x18,0x18,0x17,0x17,0x19,0x17,0x17,0x1b,0x1b,
+6,6,6,6,6,6,6,6,6,6,6,0x17,0x10,0x17,0x17,0x17,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0x17,5,6,6,6,6,6,6,6,0x10,0x1b,6,6,6,6,6,
-6,4,4,6,6,0x1b,6,6,6,6,5,5,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,0x1b,0x1b,5,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0x10,5,6,5,5,
+4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,5,5,
+6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,
-0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,
-6,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,5,
+5,5,5,5,0x17,5,6,6,6,6,6,6,6,0x10,0x1b,6,
+6,6,6,6,6,4,4,6,6,0x1b,6,6,6,6,5,5,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,0x1b,0x1b,5,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0x10,
+5,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,
-6,6,6,6,4,4,0x1b,0x17,0x17,0x17,4,0,0,6,0x19,0x19,
-6,6,6,6,4,6,6,6,4,6,6,6,6,6,0,0,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,0,0,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,6,6,6,6,4,6,6,6,6,6,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,6,6,6,0,0,0x17,0,
-5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,
+6,6,6,6,6,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0x1a,5,5,5,5,5,5,0,0x10,0x10,0,0,0,0,0,0,
-6,6,6,6,6,6,6,6,6,6,0x10,6,6,6,6,6,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,
+6,6,6,6,6,6,6,6,4,4,0x1b,0x17,0x17,0x17,4,0,
+0,6,0x19,0x19,6,6,6,6,4,6,6,6,4,6,6,6,
+6,6,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,6,6,6,6,4,6,
+6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,
+0,0,0x17,0,5,5,5,5,5,5,5,5,5,5,5,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x1a,5,5,5,5,5,5,0,0x10,0x10,0,0,
+0,0,0,0,6,6,6,6,6,6,6,6,6,6,0x10,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,
-5,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,5,5,6,6,0x17,0x17,0x49,0x89,
-0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,4,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,6,6,6,8,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,6,8,6,5,8,8,
-8,6,6,6,6,6,6,6,6,8,8,8,8,6,8,8,
-5,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,
-5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-5,5,0x19,0x19,0x37cb,0x35cb,0x3fcb,0x34cb,0x3ccb,0x94b,0x1b,0x19,5,0x17,6,0,
-5,6,8,8,0,5,5,5,5,5,5,5,5,0,0,5,
-5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,5,5,5,5,5,5,5,0,5,0,0,0,5,5,
-5,5,0,0,6,5,8,8,8,6,6,6,6,0,0,8,
-8,0,0,8,8,6,5,0,0,0,0,0,0,0,0,8,
-0,0,0,0,5,5,0,5,0,0,0,0,0,0,0x49,0x89,
-0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,6,6,5,5,5,6,0x17,0,
-0,0,0,0,0,0,0,0,0,6,6,8,0,5,5,5,
-5,5,5,0,0,0,0,5,5,0,0,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
-5,0,5,5,0,5,5,0,5,5,0,0,6,0,8,8,
-8,6,6,0,0,0,0,6,6,0,0,6,6,6,0,0,
-0,6,0,0,0,0,0,0,0,5,5,5,5,0,5,0,
-5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-0x17,0x19,0,0,0,0,0,0,0,5,6,6,6,6,6,6,
-0,6,6,8,0,5,5,5,5,5,5,5,5,5,0,5,
-5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,5,5,5,5,5,5,5,0,5,5,0,5,5,5,
-5,5,0,0,6,5,8,8,8,6,6,6,6,6,0,6,
-6,8,0,8,8,6,0,0,5,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,5,5,6,6,0,0,0x49,0x89,
-0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x1b,5,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,
+6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,
+5,5,5,5,5,4,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,5,5,6,6,
+0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,4,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,8,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,8,
+6,5,8,8,8,6,6,6,6,6,6,6,6,8,8,8,
+8,6,8,8,5,6,6,6,6,6,6,6,5,5,5,5,
+5,5,5,5,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,5,5,0x19,0x19,0x37cb,0x35cb,0x3fcb,0x34cb,0x3ccb,0x94b,0x1b,0x19,
+5,0x17,6,0,5,6,8,8,0,5,5,5,5,5,5,5,
+5,0,0,5,5,0,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,5,5,5,0,5,0,
+0,0,5,5,5,5,0,0,6,5,8,8,8,6,6,6,
+6,0,0,8,8,0,0,8,8,6,5,0,0,0,0,0,
+0,0,0,8,0,0,0,0,5,5,0,5,0,0,0,0,
+0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,6,6,5,5,
+5,6,0x17,0,0,0,0,0,0,0,0,0,0,6,6,8,
+0,5,5,5,5,5,5,0,0,0,0,5,5,0,0,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,0,5,5,0,5,5,0,5,5,0,0,
+6,0,8,8,8,6,6,0,0,0,0,6,6,0,0,6,
+6,6,0,0,0,6,0,0,0,0,0,0,0,5,5,5,
+5,0,5,0,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x17,0x19,0,0,0,0,0,0,0,5,6,6,
+6,6,6,6,0,6,6,8,0,5,5,5,5,5,5,5,
+5,5,0,5,5,5,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,5,5,5,0,5,5,
+0,5,5,5,5,5,0,0,6,5,8,8,8,6,6,6,
+6,6,0,6,6,8,0,8,8,6,0,0,5,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,5,6,6,
+0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x1b,5,0x34cb,0x344b,
+0x3ccb,0x37cb,0x35cb,0x3fcb,0,0,0,0,0,0,0,0,0,6,8,8,
+0,5,5,5,5,5,5,5,5,0,0,5,5,0,0,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,
+6,5,8,6,8,6,6,6,6,0,0,8,8,0,0,8,
+8,6,0,0,0,0,0,0,0,6,6,8,0,0,0,0,
+5,5,0,5,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x7cb,0x1e4b,0x784b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x1b,0,
+0,0,0,0,0,0,6,5,0,5,5,5,5,5,5,0,
+0,0,5,5,5,0,5,5,5,5,0,0,0,5,5,0,
+5,0,5,5,0,0,0,5,5,0,0,0,5,5,5,0,
+0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0,0,8,8,6,8,8,0,0,0,8,8,8,0,8,8,
+8,6,0,0,5,0,0,0,0,0,0,8,0,0,0,0,
+0,0,0,0,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0,0x17,0x54b,0x58b,0x5cb,0x60b,
+0x58b,0x5cb,0x60b,0x1b,6,8,8,8,6,5,5,5,5,5,5,5,
+5,0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,6,5,6,6,6,8,8,8,
+8,0,6,6,6,0,6,6,6,6,0,0,0,0,0,0,
+0,6,6,0,5,5,5,0,0,5,0,0,5,5,6,6,
+0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,5,5,8,
+0,0,0,0,0,0,0,0,0,0,0,0,5,6,8,8,
+0x17,5,5,5,5,5,5,5,5,0,5,5,5,0,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
+5,5,5,5,5,5,5,5,0,5,5,5,5,5,0,0,
+6,5,8,6,8,8,8,8,8,0,6,8,8,0,8,8,
+6,6,0,0,0,0,0,0,0,8,8,0,0,0,0,0,
+0,5,5,0,5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x7cb,0x1e4b,0x784b,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,5,5,
+5,5,5,5,6,6,8,8,5,5,5,5,5,5,5,5,
+5,0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,6,6,5,8,8,8,6,6,6,6,0,8,8,
+8,0,8,8,8,6,5,0x1b,0,0,0,0,5,5,5,8,
+0xcc0b,0xca0b,0xcb4b,0xc90b,0x364b,0xc94b,0x350b,5,0,0,0,0,0,0,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,8,8,0x17,0,0,0,
0,0,0,0,0,0,0,0,0,6,8,8,0,5,5,5,
-5,5,5,5,5,0,0,5,5,0,0,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
-5,0,5,5,0,5,5,5,5,5,0,0,6,5,8,6,
-8,6,6,6,6,0,0,8,8,0,0,8,8,6,0,0,
-0,0,0,0,0,6,6,8,0,0,0,0,5,5,0,5,
-0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-0x7cb,0x1e4b,0x784b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x19,0x1b,0,0,0,0,0,
-0,0,6,5,0,5,5,5,5,5,5,0,0,0,5,5,
-5,0,5,5,5,5,0,0,0,5,5,0,5,0,5,5,
-0,0,0,5,5,0,0,0,5,5,5,0,0,0,5,5,
-5,5,5,5,5,5,5,5,5,5,0,0,0,0,8,8,
-6,8,8,0,0,0,8,8,8,0,8,8,8,6,0,0,
-5,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,
-5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-0,0,0,0,0,0,0,0x17,0x54b,0x58b,0x5cb,0x60b,0x58b,0x5cb,0x60b,0x1b,
-6,8,8,8,6,5,5,5,5,5,5,5,5,0,5,5,
-5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,6,5,6,6,6,8,8,8,8,0,6,6,
-6,0,6,6,6,6,0,0,0,0,0,0,0,6,6,0,
-5,5,5,0,0,5,0,0,5,5,6,6,0,0,0x49,0x89,
-0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,5,5,0,0,0,0,0,
-0,0,0,0,0,0,0,0,5,6,8,8,0x17,5,5,5,
-5,5,5,5,5,0,5,5,5,0,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
-5,5,5,5,0,5,5,5,5,5,0,0,6,5,8,6,
-8,8,8,8,8,0,6,8,8,0,8,8,6,6,0,0,
-0,0,0,0,0,8,8,0,0,0,0,0,0,5,5,0,
-5,5,6,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-0x7cb,0x1e4b,0x784b,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,5,5,5,5,5,5,
-6,6,8,8,5,5,5,5,5,5,5,5,5,0,5,5,
-5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,
-6,5,8,8,8,6,6,6,6,0,8,8,8,0,8,8,
-8,6,5,0x1b,0,0,0,0,5,5,5,8,0xcc0b,0xca0b,0xcb4b,0xc90b,
-0x364b,0xc94b,0x350b,5,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
-0x1c9,0x209,0x249,0x289,0,0,8,8,0x17,0,0,0,0,0,0,0,
-0,0,0,0,0,6,8,8,0,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,0,0,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,5,5,5,5,5,5,5,5,5,0,5,0,0,
-5,5,5,5,5,5,5,0,0,0,6,0,0,0,0,8,
-8,8,6,6,6,0,6,0,8,8,8,8,8,8,8,8,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,6,5,5,6,6,6,6,6,6,6,0,0,0,0,0x19,
-5,5,5,5,5,5,4,6,6,6,6,6,6,6,6,0x17,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0,0,0,0,
-0,5,5,0,5,0,5,5,5,5,5,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0,5,0,5,5,5,5,5,5,5,5,5,5,6,5,5,
-6,6,6,6,6,6,6,6,6,5,0,0,5,5,5,5,
-5,0,4,0,6,6,6,6,6,6,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,5,5,5,5,5,0x1b,0x1b,0x1b,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,
-0x17,0x1b,0x1b,0x1b,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0x344b,0x3c4b,0x444b,0x4c4b,0x544b,0x5c4b,0x644b,0x6c4b,0x744b,0x2c4b,
-0x1b,6,0x1b,6,0x1b,6,0x14,0x15,0x14,0x15,8,8,5,5,5,5,
-5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,
-0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,8,
-6,6,6,6,6,0x17,6,6,5,5,5,5,5,6,6,6,
-6,6,6,6,6,6,6,6,0,6,6,6,6,6,6,6,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
+0,5,0,0,5,5,5,5,5,5,5,0,0,0,6,0,
+0,0,0,8,8,8,6,6,6,0,6,0,8,8,8,8,
+8,8,8,8,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,6,5,5,6,6,6,6,6,6,6,0,
+0,0,0,0x19,5,5,5,5,5,5,4,6,6,6,6,6,
+6,6,6,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,
+0,0,0,0,0,5,5,0,5,0,5,5,5,5,5,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0,5,0,5,5,5,5,5,5,5,5,5,
+5,6,5,5,6,6,6,6,6,6,6,6,6,5,0,0,
+5,5,5,5,5,0,4,0,6,6,6,6,6,6,6,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,5,5,5,5,
+5,0x1b,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x1b,0x17,0x1b,0x1b,0x1b,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x344b,0x3c4b,0x444b,0x4c4b,0x544b,0x5c4b,
+0x644b,0x6c4b,0x744b,0x2c4b,0x1b,6,0x1b,6,0x1b,6,0x14,0x15,0x14,0x15,8,8,
+5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,8,6,6,6,6,6,0x17,6,6,5,5,5,5,
+5,6,6,6,6,6,6,6,6,6,6,6,0,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,6,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x17,0x17,0x17,0x17,
-0x17,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,8,8,6,6,6,6,8,6,6,
-6,6,6,6,8,6,6,8,8,6,6,5,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,
-5,5,8,8,6,6,5,5,5,5,6,6,6,5,8,8,
-8,5,5,8,8,8,8,8,8,8,5,5,5,6,6,6,
-6,5,5,5,5,5,5,5,5,5,5,5,5,5,6,8,
-8,6,6,8,8,8,8,8,8,6,5,8,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,8,8,8,6,0x1b,0x1b,2,2,2,2,
+6,6,6,6,6,6,6,6,6,6,6,6,6,0,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,
+0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,8,8,6,6,6,
+6,8,6,6,6,6,6,6,8,6,6,8,8,6,6,5,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,
+5,5,5,5,5,5,8,8,6,6,5,5,5,5,6,6,
+6,5,8,8,8,5,5,8,8,8,8,8,8,8,5,5,
+5,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,
+5,5,6,8,8,6,6,8,8,8,8,8,8,6,5,8,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,8,8,8,6,0x1b,0x1b,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,0x17,4,2,2,2,1,1,1,1,
-1,1,0,1,0,0,0,0,0,1,0,0,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,
-5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
-5,5,5,0,5,0,5,5,5,5,0,0,5,5,5,5,
-5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
-5,5,0,0,5,5,5,5,5,5,5,0,5,0,5,5,
-5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,0,5,5,5,5,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0,0,6,6,6,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,
-0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x788b,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,0,0,2,2,2,2,2,2,0,0,0x13,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x1b,0x17,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0xc,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0x14,0x15,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x98a,0x9ca,
-0xa0a,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,6,6,6,8,0,0,0,0,0,0,0,0,0,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,6,6,8,0x17,0x17,0,0,0,0,0,0,0,0,0,
+2,2,2,2,2,2,2,2,2,2,2,0x17,4,2,2,2,
+1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+5,5,5,5,5,5,5,5,5,0,5,5,5,5,0,0,
+5,5,5,5,5,5,5,0,5,0,5,5,5,5,0,0,
+5,5,5,5,5,5,5,5,5,0,5,5,5,5,0,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,6,6,0,0,0,0,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,
-5,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,
+5,0,5,5,5,5,0,0,5,5,5,5,5,5,5,0,
+5,0,5,5,5,5,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,5,5,5,5,0,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,6,6,8,6,6,6,6,6,6,6,8,8,
-8,8,8,8,8,8,6,8,8,6,6,6,6,6,6,6,
-6,6,6,6,0x17,0x17,0x17,4,0x17,0x17,0x17,0x19,5,6,0,0,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,6,5,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,0,0,6,6,6,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,
+0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x788b,0,0,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17,0x17,0x17,0x17,6,6,6,0x10,6,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-5,5,5,4,5,5,5,5,5,5,5,5,5,5,5,5,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,0,0,2,2,2,2,2,2,0,0,
+0x13,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0x1b,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0xc,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x14,
+0x15,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0x17,
+0x17,0x17,0x98a,0x9ca,0xa0a,5,5,5,5,5,5,5,5,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,6,6,6,8,0,0,0,0,0,0,
+0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,6,6,8,0x17,0x17,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,6,6,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,5,5,5,0,6,6,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,6,6,8,6,6,6,6,6,
+6,6,8,8,8,8,8,8,8,8,6,8,8,6,6,6,
+6,6,6,6,6,6,6,6,0x17,0x17,0x17,4,0x17,0x17,0x17,0x19,
+5,6,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
+0,0,0,0,0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,6,5,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17,0x17,0x17,0x17,6,
+6,6,0x10,6,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
+0,0,0,0,5,5,5,4,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,0,0,0,0,0,0,5,5,5,5,5,6,6,5,
+5,5,5,5,5,0,0,0,0,0,0,0,5,5,5,5,
+5,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+0,0,0,0,0,0,0,0,6,6,6,8,8,8,8,6,
+6,8,8,8,0,0,0,0,8,8,6,8,8,8,8,8,
+8,6,6,6,0,0,0,0,0x1b,0,0,0,0x17,0x17,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,5,5,5,5,5,0,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,
-0,0,0,0,6,6,6,8,8,8,8,6,6,8,8,8,
-0,0,0,0,8,8,6,8,8,8,8,8,8,6,6,6,
-0,0,0,0,0x1b,0,0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,
-0x1c9,0x209,0x249,0x289,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,5,5,5,5,5,0,0,0,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0x30b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x30b,0,0,0,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,6,6,8,8,6,0,0,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,4,0x17,0x17,0x17,0x17,0x17,0x17,0,0,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,7,6,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,8,6,8,6,6,6,6,6,6,6,0,6,8,6,8,
-8,6,6,6,6,6,6,6,6,8,8,8,8,8,8,6,
-6,6,6,6,6,6,6,6,6,0,0,6,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,0x17,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,
-8,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,6,8,6,6,
-6,6,6,8,6,8,8,8,8,8,6,8,8,5,5,5,
-5,5,5,5,5,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,5,8,6,6,6,6,8,8,
-6,6,8,6,6,6,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,5,5,5,5,5,5,6,6,8,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,6,8,6,6,8,8,
-8,6,8,6,6,6,8,8,0,0,0,0,0,0,0,0,
-0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
-0,5,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,
-5,5,5,5,8,8,8,8,8,8,8,8,6,6,6,6,
-6,6,6,6,8,8,6,6,0,0,0,0x17,0x17,0x17,0x17,0x17,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,4,4,4,4,4,4,0x17,0x17,
-2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,
-6,6,6,0x17,6,6,6,6,6,6,6,6,6,6,6,6,
-6,8,6,6,6,6,6,6,6,5,5,5,5,6,5,5,
-5,5,5,5,6,5,5,8,6,6,5,0,0,0,0,0,
-2,2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,
+5,5,5,5,5,5,5,6,6,8,8,6,0,0,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,4,0x17,0x17,0x17,0x17,0x17,0x17,0,0,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,6,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,8,6,8,6,6,6,6,6,6,6,0,
+6,8,6,8,8,6,6,6,6,6,6,6,6,8,8,8,
+8,8,8,6,6,6,6,6,6,6,6,6,6,0,0,6,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0x17,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,6,6,
+6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,6,6,6,8,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,8,6,6,6,6,6,8,6,8,8,8,8,8,6,8,
+8,5,5,5,5,5,5,5,5,0,0,0,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,0x17,0x17,5,8,6,6,
+6,6,8,8,6,6,8,6,6,6,5,5,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,5,6,6,8,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,8,
+6,6,8,8,8,6,8,6,6,6,8,8,0,0,0,0,
+0,0,0,0,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,5,5,5,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,5,5,5,5,5,5,8,8,8,8,8,8,8,8,
+6,6,6,6,6,6,6,6,8,8,6,6,0,0,0,0x17,
+0x17,0x17,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,
+4,4,0x17,0x17,2,2,2,2,2,2,2,2,2,0,0,0,
+0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+0,1,1,1,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,
+0,0,0,0,6,6,6,0x17,6,6,6,6,6,6,6,6,
+6,6,6,6,6,8,6,6,6,6,6,6,6,5,5,5,
+5,6,5,5,5,5,5,5,6,5,5,8,6,6,5,0,
+0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,
-2,2,2,2,2,2,2,2,2,2,2,2,4,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,2,2,2,2,2,2,2,2,1,2,
-2,2,2,2,2,2,2,2,1,1,1,1,1,0x1a,0x1a,0x1a,
-0,0,2,2,2,0,2,2,1,1,1,1,3,0x1a,0x1a,0,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,0,0,1,1,1,1,1,1,0,0,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,0,0,1,1,1,1,1,1,0,0,
-2,2,2,2,2,2,2,2,0,1,0,1,0,1,0,1,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
-2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,
-2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,
-2,2,2,2,2,0,2,2,1,1,1,1,3,0x1a,2,0x1a,
-0x1a,0x1a,2,2,2,0,2,2,1,1,1,1,3,0x1a,0x1a,0x1a,
-2,2,2,2,0,0,2,2,1,1,1,1,0,0x1a,0x1a,0x1a,
-0x16,0x17,0x17,0x17,0x18,0x14,0x15,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0x17,0x18,0x17,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xc,
-0x10,0x10,0x10,0x10,0x10,0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
-0x2cb,4,0,0,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,0x18,0x14,0x15,4,
-0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x10,0x10,0x10,0x10,0x10,
-0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x1c,0x1d,0x14,0x1c,0x1c,0x1d,0x14,0x1c,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xd,0xe,0x10,0x10,0x10,0x10,0x10,0xc,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1c,0x1d,0x17,0x17,0x17,0x17,0x16,
-0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,0x18,0x14,0x15,0,
-4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,
-0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,
+4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,
+4,4,4,4,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,2,1,2,2,2,2,2,2,2,
+2,2,1,2,2,2,2,2,2,2,2,2,1,1,1,1,
+1,0x1a,0x1a,0x1a,0,0,2,2,2,0,2,2,1,1,1,1,
+3,0x1a,0x1a,0,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,0,0,1,1,1,1,
+1,1,0,0,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,0,0,1,1,1,1,
+1,1,0,0,2,2,2,2,2,2,2,2,0,1,0,1,
+0,1,0,1,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,0,0,2,2,2,2,2,2,2,2,3,3,3,3,
+3,3,3,3,2,2,2,2,2,2,2,2,3,3,3,3,
+3,3,3,3,2,2,2,2,2,0,2,2,1,1,1,1,
+3,0x1a,2,0x1a,0x1a,0x1a,2,2,2,0,2,2,1,1,1,1,
+3,0x1a,0x1a,0x1a,2,2,2,2,0,0,2,2,1,1,1,1,
+0,0x1a,0x1a,0x1a,0x16,0x17,0x17,0x17,0x18,0x14,0x15,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0x18,0x17,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0xc,0x10,0x10,0x10,0x10,0x10,0,0x10,0x10,0x10,0x10,0x10,0x10,
+0x10,0x10,0x10,0x10,0x2cb,4,0,0,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,
+0x18,0x14,0x15,4,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0xc,0x10,
+0x10,0x10,0x10,0x10,0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x1c,0x1d,0x14,0x1c,
+0x1c,0x1d,0x14,0x1c,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0xd,0xe,0x10,0x10,
+0x10,0x10,0x10,0xc,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1c,0x1d,0x17,
+0x17,0x17,0x17,0x16,0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x18,0x18,
+0x18,0x14,0x15,0,4,4,4,4,4,4,4,4,4,4,4,4,
+4,0,0,0,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,
0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19,
-0x19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,
-7,6,7,7,7,6,6,6,6,6,6,6,6,6,6,6,
-6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x1b,0x1b,0x1b,0x1b,1,0x1b,1,0x1b,1,0x1b,1,1,1,1,0x1b,2,
-1,1,1,1,2,5,5,5,5,2,0x1b,0x1b,2,2,1,1,
-0x18,0x18,0x18,0x18,0x18,1,2,2,2,2,0x1b,0x18,0x1b,0x1b,2,0x1b,
-0x358b,0x360b,0x364b,0x348b,0x388b,0x350b,0x390b,0x3d0b,0x410b,0x354b,0x454b,0x35cb,0x3dcb,0x45cb,0x4dcb,0x58b,
-0x1b,0x1b,1,0x1b,0x1b,0x1b,0x1b,1,0x1b,0x1b,2,1,1,1,2,2,
-1,1,1,2,0x1b,1,0x1b,0x1b,0x18,1,1,1,1,1,0x1b,0x1b,
-0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x7ca,0x80a,0x84a,0x11ca,0x1e4a,0x980a,0x784a,
-0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x7ca,0x80a,0x84a,0x11ca,0x1e4a,0x980a,0x784a,
-0x784a,0x984a,0x788a,1,2,0x6ca,0x11ca,0x988a,0x78ca,0x54b,0x1b,0x1b,0,0,0,0,
-0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,
+0x19,0x19,0x19,0x19,0x19,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
+6,7,7,7,7,6,7,7,7,6,6,6,6,6,6,6,
+6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,1,0x1b,1,0x1b,1,0x1b,1,1,
+1,1,0x1b,2,1,1,1,1,2,5,5,5,5,2,0x1b,0x1b,
+2,2,1,1,0x18,0x18,0x18,0x18,0x18,1,2,2,2,2,0x1b,0x18,
+0x1b,0x1b,2,0x1b,0x358b,0x360b,0x364b,0x348b,0x388b,0x350b,0x390b,0x3d0b,0x410b,0x354b,0x454b,0x35cb,
+0x3dcb,0x45cb,0x4dcb,0x58b,0x1b,0x1b,1,0x1b,0x1b,0x1b,0x1b,1,0x1b,0x1b,2,1,
+1,1,2,2,1,1,1,2,0x1b,1,0x1b,0x1b,0x18,1,1,1,
+1,1,0x1b,0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x7ca,0x80a,0x84a,
+0x11ca,0x1e4a,0x980a,0x784a,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x7ca,0x80a,0x84a,
+0x11ca,0x1e4a,0x980a,0x784a,0x784a,0x984a,0x788a,1,2,0x6ca,0x11ca,0x988a,0x78ca,0x54b,0x1b,0x1b,
+0,0,0,0,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x18,
-0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,
-0x1b,0x1b,0x18,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x1b,0x1b,0x18,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x18,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x1b,0x1b,0x1b,0x1b,
+0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,
+0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x2cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0xa4b,0x30b,0x34b,0x38b,
-0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,
-0x50b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0xa4b,0x30b,0x34b,0x38b,0x3cb,
+0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x2cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,
+0xa4b,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x2cb,0x30b,0x34b,0x38b,0x3cb,
0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0xa4b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,
+0x98b,0x9cb,0xa0b,0xa4b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
-0x14,0x15,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x30b,0x34b,0x38b,0x3cb,
-0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,
-0x18,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,
-0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,0x14,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
+0x14,0x15,0x14,0x15,0x14,0x15,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,
+0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,
+0x48b,0x4cb,0x50b,0x7cb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,
0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,
-0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x14,0x15,
+0x15,0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x14,0x15,0x18,0x18,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x14,0x15,0x14,0x15,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-0x18,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x14,0x15,0x18,0x18,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,2,1,1,1,2,2,1,
+2,1,2,1,2,1,1,1,1,2,1,2,2,1,2,2,
+2,2,2,2,4,4,1,1,1,2,1,2,2,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,1,2,1,2,6,6,6,1,2,0,0,0,0,
+0,0x17,0x17,0x17,0x17,0x344b,0x17,0x17,2,2,2,2,2,2,0,2,
+0,0,0,0,0,2,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,4,
+0x17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
+0x17,0x17,0x1c,0x1d,0x1c,0x1d,0x17,0x17,0x17,0x1c,0x1d,0x17,0x1c,0x1d,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x17,0x17,0x13,0x17,0x1c,0x1d,0x17,0x17,
+0x1c,0x1d,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x17,0x17,4,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x13,0x17,0x17,0x17,0x17,
+0x13,0x17,0x14,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x1b,0x1b,0x17,0x17,0x17,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0,0,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,1,2,1,1,1,2,2,1,2,1,2,1,
-2,1,1,1,1,2,1,2,2,1,2,2,2,2,2,2,
-4,4,1,1,1,2,1,2,2,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,1,
-2,1,2,6,6,6,1,2,0,0,0,0,0,0x17,0x17,0x17,
-0x17,0x344b,0x17,0x17,2,2,2,2,2,2,0,2,0,0,0,0,
-0,2,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,0,0,0,0,0,0,0,4,0x17,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,6,5,5,5,5,
-5,5,5,0,5,5,5,5,5,5,5,0,5,5,5,5,
-5,5,5,0,5,5,5,5,5,5,5,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,0,0,0,0,0,0,0,0,0x17,0x17,0x1c,0x1d,
-0x1c,0x1d,0x17,0x17,0x17,0x1c,0x1d,0x17,0x1c,0x1d,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x13,0x17,0x17,0x13,0x17,0x1c,0x1d,0x17,0x17,0x1c,0x1d,0x14,0x15,
-0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x17,0x17,4,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x13,0x13,0x17,0x17,0x17,0x17,0x13,0x17,0x14,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x1b,0x1b,0x17,0x17,
-0x17,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0,0,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
-0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
-0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,6,6,6,6,8,8,
-0x13,4,4,4,4,4,0x1b,0x1b,0x7ca,0xa4a,0xcca,4,5,0x17,0x1b,0x1b,
-0xc,0x17,0x17,0x17,0x1b,4,5,0x54a,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
-0x14,0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x13,0x14,0x15,0x15,
+0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0,0,0,0x1b,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,6,6,
+6,6,8,8,0x13,4,4,4,4,4,0x1b,0x1b,0x7ca,0xa4a,0xcca,4,
+5,0x17,0x1b,0x1b,0xc,0x17,0x17,0x17,0x1b,4,5,0x54a,0x14,0x15,0x14,0x15,
+0x14,0x15,0x14,0x15,0x14,0x15,0x1b,0x1b,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,
+0x13,0x14,0x15,0x15,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0,0,6,6,0x1a,
+0x1a,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x17,
+4,4,4,5,0,0,0,0,0,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0,0,6,6,0x1a,0x1a,4,4,5,
+5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1b,0xa8b,0xacb,0xb0b,
+0xb4b,0xb8b,0xbcb,0xc0b,0xc4b,0xc8b,0xccb,0xd0b,0xd4b,0xd8b,0xdcb,0xe0b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xe4b,0xe8b,0xecb,
+0xf0b,0xf4b,0xf8b,0xfcb,0x100b,0x104b,0x108b,0x10cb,0x110b,0x114b,0x118b,0x11cb,5,5,5,5,
+5,0x685,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0x17,4,4,4,5,
-0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x685,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,0x705,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x585,5,5,0x705,5,5,5,0x7885,
+5,0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1b,0xa8b,0xacb,0xb0b,0xb4b,0xb8b,0xbcb,0xc0b,
-0xc4b,0xc8b,0xccb,0xd0b,0xd4b,0xd8b,0xdcb,0xe0b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0xe4b,0xe8b,0xecb,0xf0b,0xf4b,0xf8b,0xfcb,
-0x100b,0x104b,0x108b,0x10cb,0x110b,0x114b,0x118b,0x11cb,5,5,5,5,5,0x685,5,5,
+5,0x785,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x5c5,5,5,5,5,5,5,5,0x685,5,0x645,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0x7985,0x7c5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x685,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,0x7845,5,5,5,5,
+5,5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x685,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0x705,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,0x585,5,5,0x705,5,5,5,0x7885,5,0x605,5,5,
+0x1e45,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x7985,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x7a85,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x785,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,
-5,5,5,5,0x685,5,0x645,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0x5c5,5,0x745,5,0x6c5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0x7985,0x7c5,5,5,5,5,5,5,5,
+5,0x7c5,5,0x7845,0xa45,0xcc5,5,5,5,5,5,5,0xf45,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0x7845,5,5,5,5,5,5,5,5,
-0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0x685,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x1e45,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x7985,5,5,5,
+5,0x605,0x605,0x605,0x605,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x7a85,5,5,5,5,5,
+5,5,5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x585,5,5,5,5,5,5,5,0x585,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,0x5c5,5,0x745,5,0x6c5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5,0x7845,
-0xa45,0xcc5,5,5,5,5,5,5,0xf45,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x605,0x605,0x605,
-0x605,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x645,
+5,5,5,5,5,5,5,5,5,5,0x585,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0x585,5,5,5,5,5,5,5,0x585,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x785,0xa45,5,5,5,5,
+5,5,5,5,5,5,5,5,0x585,0x5c5,0x605,5,0x5c5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0x585,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x745,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0x785,0xa45,5,5,5,5,5,5,5,5,
-5,5,5,5,0x585,0x5c5,0x605,5,0x5c5,5,5,5,5,5,5,5,
+5,5,0x705,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x785,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x7c5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0x745,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x705,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1e45,5,
+5,5,5,5,5,5,0x645,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x785,5,5,5,5,5,
+0x7885,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0x5c5,5,5,5,5,0x5c5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x5c5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x7845,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x1e45,5,5,5,5,5,
-5,5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x7885,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x6c5,5,
+5,5,5,5,0x1e45,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0x5c5,5,5,5,5,0x5c5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0x5c5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0x7845,5,5,5,5,5,5,
+0x6c5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x545,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0x6c5,5,5,5,5,5,
-0x1e45,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x6c5,5,5,5,
+5,4,5,5,5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,4,0x17,0x17,0x17,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0x545,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,
-5,5,5,5,5,5,5,5,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
-0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,4,0x17,0x17,0x17,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,2,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,2,1,2,1,2,4,4,6,6,1,2,1,2,
-1,2,1,2,1,2,1,2,1,2,5,6,7,7,7,0x17,
-6,6,6,6,6,6,6,6,6,6,0x17,4,5,5,5,5,
-5,5,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x54a,6,6,0x17,0x17,
-0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0x1a,0x1a,0x1a,0x1a,
+1,2,1,2,1,2,1,2,1,2,1,2,4,4,6,6,
+1,2,1,2,1,2,1,2,1,2,1,2,1,2,5,6,
+7,7,7,0x17,6,6,6,6,6,6,6,6,6,6,0x17,4,
+5,5,5,5,5,5,0x58a,0x5ca,0x60a,0x64a,0x68a,0x6ca,0x70a,0x74a,0x78a,0x54a,
+6,6,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,
0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
-0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,
-4,1,2,5,4,4,2,5,5,5,5,5,0x1a,0x1a,1,2,
-1,2,1,2,1,2,1,2,1,2,1,2,2,2,1,2,
-1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
-4,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,
-1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,2,1,2,5,
-1,2,1,2,2,2,1,2,1,2,1,2,1,2,1,2,
-1,2,1,1,1,1,1,2,1,1,1,1,1,2,1,2,
-1,2,1,2,1,2,1,2,1,1,1,1,2,1,2,0,
-0,0,0,0,1,2,0,2,0,2,1,2,1,2,0,0,
-0,0,0,0,5,5,6,5,5,5,6,5,5,5,5,6,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,8,8,6,6,8,0x1b,0x1b,0x1b,0x1b,
-6,0,0,0,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,0x1b,0x19,0x1b,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x17,0,0,0,0,
-0,0,0,0,8,8,8,8,6,6,0,0,0,0,0,0,
-0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
-0,0,0,0,8,8,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,8,8,8,8,8,8,8,8,8,8,8,8,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,5,5,5,5,5,5,0x17,0x17,0x17,5,0x17,5,5,6,
-5,5,5,5,5,5,6,6,6,6,6,6,6,6,0x17,0x17,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,6,6,6,6,6,6,6,6,6,6,6,8,8,
-0,0,0,0,0,0,0,0,0,0,0,0x17,8,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,
-8,8,6,6,6,6,8,8,6,6,8,8,5,5,5,5,
-5,6,4,5,5,5,5,5,5,5,5,5,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,0,5,5,5,5,
-5,5,5,5,5,6,6,6,6,6,6,8,8,6,6,8,
-8,6,6,0,0,0,0,0,0,0,0,0,5,5,5,6,
-5,5,5,5,5,5,5,5,6,8,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0x17,0x17,0x17,0x17,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,
-5,5,5,0x1b,0x1b,0x1b,5,8,6,8,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,6,5,6,6,
-6,5,5,6,6,5,5,5,5,5,6,6,5,6,5,0,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,4,4,4,4,4,4,4,4,4,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,5,5,4,0x17,0x17,5,5,5,5,
-5,5,5,5,5,5,5,8,6,6,8,8,0x17,0x17,5,4,
-4,8,6,0,0,0,0,0,0,0,0,0,0,5,5,5,
-5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,5,
-5,5,5,0,0,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,0,5,5,5,5,5,5,5,0,2,2,2,2,
+0,0,4,4,4,1,2,5,4,4,2,5,5,5,5,5,
+0x1a,0x1a,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+2,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,
+1,2,1,2,4,2,2,2,2,2,2,2,2,1,2,1,
+2,1,1,2,1,2,1,2,1,2,1,2,4,0x1a,0x1a,1,
+2,1,2,5,1,2,1,2,2,2,1,2,1,2,1,2,
+1,2,1,2,1,2,1,1,1,1,1,2,1,1,1,1,
+1,2,1,2,1,2,1,2,1,2,1,2,1,1,1,1,
+2,1,2,0,0,0,0,0,1,2,0,2,0,2,1,2,
+1,2,0,0,0,0,0,0,5,5,6,5,5,5,6,5,
+5,5,5,6,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,8,8,6,6,8,
+0x1b,0x1b,0x1b,0x1b,6,0,0,0,0x34cb,0x344b,0x3ccb,0x37cb,0x35cb,0x3fcb,0x1b,0x1b,
+0x19,0x1b,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0x17,0x17,
+0,0,0,0,0,0,0,0,8,8,8,8,6,6,0,0,
+0,0,0,0,0,0,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,0,0,0,8,8,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,8,8,8,8,8,8,8,8,
+8,8,8,8,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,5,5,5,5,5,5,0x17,0x17,0x17,5,
+0x17,5,5,6,5,5,5,5,5,5,6,6,6,6,6,6,
+6,6,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,
+6,6,8,8,0,0,0,0,0,0,0,0,0,0,0,0x17,
+8,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,4,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,6,8,8,6,6,6,6,8,8,6,6,8,8,
+5,5,5,5,5,6,4,5,5,5,5,5,5,5,5,5,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,5,5,5,5,0,
+5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,8,
+8,6,6,8,8,6,6,0,0,0,0,0,0,0,0,0,
+5,5,5,6,5,5,5,5,5,5,5,5,6,8,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0x17,0x17,0x17,0x17,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+4,5,5,5,5,5,5,0x1b,0x1b,0x1b,5,8,6,8,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,5,6,6,6,5,5,6,6,5,5,5,5,5,6,6,
+5,6,5,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,5,4,0x17,0x17,
+5,5,5,5,5,5,5,5,5,5,5,8,6,6,8,8,
+0x17,0x17,5,4,4,8,6,0,0,0,0,0,0,0,0,0,
+0,5,5,5,5,5,5,0,0,5,5,5,5,5,5,0,
+0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,0x1a,4,4,4,4,2,2,2,2,
-2,2,2,2,2,4,0x1a,0x1a,0,0,0,0,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,8,
-8,6,8,8,6,8,8,0x17,8,6,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5,
-0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+2,2,2,2,2,2,2,2,2,2,2,0x1a,4,4,4,4,
+2,2,2,2,2,2,2,2,2,4,0x1a,0x1a,0,0,0,0,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+5,5,5,8,8,6,8,8,6,8,8,0x17,8,6,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
+5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,
-5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0x12,0x12,0x12,0x12,
0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
-0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x11,0x11,0x11,
+0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
-0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,5,5,5,5,
-5,5,5,5,5,5,5,0x605,5,5,5,5,5,5,5,0x7c5,
-5,5,5,5,0x5c5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0x6c5,5,0x6c5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0x7c5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x18,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,
-5,0,5,0,5,5,0,5,5,0,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,2,2,2,2,2,2,2,0,0,0,0,0,
-0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,
-0,5,6,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
-0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0x15,0x14,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0x1b,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,5,0x19,0x1b,0x1b,0x1b,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x14,0x15,0x17,0,0,0,0,0,0,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-0x17,0x13,0x13,0x16,0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,0x15,0x14,
-0x15,0x17,0x17,0x14,0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x17,0x17,0x17,0,
-0x17,0x17,0x17,0x17,0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x17,0x18,0x13,
-0x18,0x18,0x18,0,0x17,0x19,0x17,0x17,0,0,0,0,5,5,5,5,
-5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
+5,5,5,5,5,5,5,5,5,5,5,0x605,5,5,5,5,
+5,5,5,0x7c5,5,5,5,5,0x5c5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x6c5,5,0x6c5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,0,0x10,0,0,5,5,5,5,5,5,0,0,5,5,
-5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,
-5,0,0,0,0x19,0x19,0x18,0x1a,0x1b,0x19,0x19,0,0x1b,0x18,0x18,0x18,
-0x18,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0x10,0x10,0x10,
-0x1b,0x1b,0,0,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17,0x14,0x15,0x17,0x18,
-0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,
-0x18,0x18,0x18,0x17,0x1a,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0x14,
-0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5,5,5,5,5,
-5,5,5,5,4,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0x7c5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,4,4,5,5,5,5,5,5,5,5,
-5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
-5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
-0,0,0,0,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,
-0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x17,0x17,0x17,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,
-0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,
-0x900b,0x980b,0xa00b,0xa80b,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xcca,0x11ca,0x11ca,0x11ca,0x11ca,0x1e4a,0x880a,
-0x980a,0x980a,0x980a,0x980a,0x980a,0x784a,0x984a,0x68a,0x11ca,0x344b,0x344b,0x388b,0x3ccb,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x54b,0x34cb,0x1b,0x1b,0x1b,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
-0x34ca,0x344a,0x58a,0x68a,0x11ca,0x980a,0x984a,0x988a,0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x984a,0x68a,
-0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x788a,0x988a,0x7ca,0x58a,0x58a,0x58a,0x5ca,0x5ca,0x5ca,0x5ca,0x68a,
-0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0,0,
+5,0x18,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,5,5,5,5,0,5,0,5,5,0,5,5,0,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-6,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,
-0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0,0,0,0,
-0x58b,0x68b,0x7cb,0x11cb,0,0,0,0,0,0,0,0,0,5,5,5,
+5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,0,
+0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,
+0,0,0,0,0,5,6,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,
+0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0x1bca,5,5,5,5,5,5,5,5,0xb80a,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,0x15,0x14,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
+0,0,0,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+0x19,0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x14,0x15,0x17,0,0,
+0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,0x17,0x13,0x13,0x16,0x16,0x14,0x15,0x14,0x15,0x14,0x15,0x14,
+0x15,0x14,0x15,0x14,0x15,0x17,0x17,0x14,0x15,0x17,0x17,0x17,0x17,0x16,0x16,0x16,
+0x17,0x17,0x17,0,0x17,0x17,0x17,0x17,0x13,0x14,0x15,0x14,0x15,0x14,0x15,0x17,
+0x17,0x17,0x18,0x13,0x18,0x18,0x18,0,0x17,0x19,0x17,0x17,0,0,0,0,
+5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0x10,0,0,5,5,5,5,5,5,
+0,0,5,5,5,5,5,5,0,0,5,5,5,5,5,5,
+0,0,5,5,5,0,0,0,0x19,0x19,0x18,0x1a,0x1b,0x19,0x19,0,
+0x1b,0x18,0x18,0x18,0x18,0x1b,0x1b,0,0,0,0,0,0,0,0,0,
+0,0x10,0x10,0x10,0x1b,0x1b,0,0,0,0x17,0x17,0x17,0x19,0x17,0x17,0x17,
+0x14,0x15,0x17,0x18,0x17,0x13,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0x17,0x17,0x18,0x18,0x18,0x17,0x1a,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,0x14,0x18,0x15,0x18,0x14,0x15,0x17,0x14,0x15,0x17,0x17,5,5,
+5,5,5,5,5,5,5,5,4,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,6,6,6,6,6,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,4,4,5,5,5,5,
+5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0x17,
-5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,
-0x17,0x58a,0x5ca,0x7ca,0xa4a,0x1e4a,0,0,0,0,0,0,0,0,0,0,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+5,5,5,0,5,5,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0,0,0,0,0,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,
+0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0,0,0,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x17,0x17,0x17,0,0,0,0,0x58b,
+0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,
+0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xcca,0x11ca,0x11ca,
+0x11ca,0x11ca,0x1e4a,0x880a,0x980a,0x980a,0x980a,0x980a,0x980a,0x784a,0x984a,0x68a,0x11ca,0x344b,0x344b,0x388b,
+0x3ccb,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x54b,0x34cb,
+0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0,0,0,0x34ca,0x344a,0x58a,0x68a,0x11ca,0x980a,0x984a,0x988a,0x68a,0x7ca,0x11ca,0x1e4a,
+0x980a,0x784a,0x984a,0x68a,0x7ca,0x11ca,0x1e4a,0x980a,0x784a,0x788a,0x988a,0x7ca,0x58a,0x58a,0x58a,0x5ca,
+0x5ca,0x5ca,0x5ca,0x68a,0x1b,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,6,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,6,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,
+0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,
+0,0,0,0,0x58b,0x68b,0x7cb,0x11cb,0,0,0,0,0,0,0,0,
+0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0x1bca,5,5,5,5,5,5,5,5,0xb80a,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+5,5,0,0x17,5,5,5,5,0,0,0,0,5,5,5,5,
+5,5,5,5,0x17,0x58a,0x5ca,0x7ca,0xa4a,0x1e4a,0,0,0,0,0,0,
+0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
+0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,0,0,0,0,2,2,2,2,2,2,2,2,
+0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,0,0,0,0,2,2,2,2,
+2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0x17,
+1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
+2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,0,2,2,2,2,2,2,2,0,2,2,0,0,0,
+1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
+1,1,1,0,1,1,0,2,2,2,2,2,2,2,2,2,
5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+4,0,4,4,4,4,4,4,4,4,4,0,0,0,0,0,
+4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0,0,0,0,0,0,0,0,0,0,0,0x17,1,1,1,1,
-1,1,1,1,1,1,1,0,1,1,1,1,2,2,0,2,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,
-2,2,2,2,2,2,0,2,2,0,0,0,1,1,1,1,
-1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,
-1,1,0,2,2,2,2,2,2,2,2,2,5,5,5,5,
-5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,
-4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,4,
-4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,
-4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,5,5,0,0,0,5,0,0,5,5,5,5,5,
-5,5,0,0,5,0,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0x17,
-0x58b,0x5cb,0x60b,0x7cb,0xa4b,0x1e4b,0x784b,0x788b,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x1b,
-0x1b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0,0,0,0,0,0,0,0x58b,
-0x5cb,0x60b,0x64b,0x64b,0x68b,0x7cb,0xa4b,0x1e4b,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,5,5,0,0,
-0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,0x58b,0x7cb,
-0xa4b,0x1e4b,0x5cb,0x60b,0,0,0,0x17,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,0,0,0,0x17,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,
-0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x88cb,0x90cb,0x98cb,0xa0cb,0xa8cb,0xb0cb,0xb8cb,0x36cb,0x354b,
-0x34cb,0x348b,0x46cb,0x344b,0x4ecb,0x388b,0x3ccb,0x454b,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0,0,0,0,0x5ecb,0x344b,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,
-0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0,0,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,
-0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0x30b,0x34b,0x38b,0x3cb,0x7cb,0xa4b,0x1e4b,0x784b,
-0x344b,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0,0,0,0,0,0,0,5,6,6,6,0,6,6,0,
-0,0,0,0,6,6,6,6,5,5,5,5,0,5,5,5,
-0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,0,0,6,6,6,0,
-0,0,0,6,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,5,5,0,0,0,5,0,0,5,
+5,5,5,5,5,5,0,0,5,0,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,0,0x17,0x58b,0x5cb,0x60b,0x7cb,0xa4b,0x1e4b,0x784b,0x788b,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0x58b,0x11cb,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,0x1b,0x1b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0,0,0,0,
+0,0,0,0x58b,0x5cb,0x60b,0x64b,0x64b,0x68b,0x7cb,0xa4b,0x1e4b,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,5,0,0,0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0x58b,0x7cb,0xa4b,5,5,5,5,5,6,6,0,0,0,0,0x58b,
-0x68b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,0x1b,5,5,5,
+5,5,0x58b,0x7cb,0xa4b,0x1e4b,0x5cb,0x60b,0,0,0,0x17,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+5,5,5,5,5,5,0,0,0,0,0,0x17,0xa04b,0xa84b,0xb04b,0xb84b,
+0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x88cb,0x90cb,0x98cb,0xa0cb,0xa8cb,
+0xb0cb,0xb8cb,0x36cb,0x354b,0x34cb,0x348b,0x46cb,0x344b,0x4ecb,0x388b,0x3ccb,0x454b,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b,
+5,5,5,5,0,0,0,0,0x5ecb,0x344b,5,5,0x58b,0x5cb,0x60b,0x64b,
+0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0,0,0x1e4b,0x800b,
+0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0x30b,0x34b,0x38b,0x3cb,
+0x7cb,0xa4b,0x1e4b,0x784b,0x344b,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,5,6,6,6,
+0,6,6,0,0,0,0,0,6,6,6,6,5,5,5,5,
+0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
+6,6,6,0,0,0,0,6,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0x784b,
+5,5,5,5,5,0x58b,0x11cb,0x17,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,0,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0,0,0,
-0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,
+5,5,5,5,5,0x58b,0x7cb,0xa4b,5,5,5,5,5,6,6,0,
+0,0,0,0x58b,0x68b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+0x1b,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0,0,0,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b,
+0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,
+0x7cb,0xa4b,0x1e4b,0x784b,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,0,0,0,0,0,0x17,0x17,0x17,
+0x17,0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,
+0x64b,0x7cb,0xa4b,0x1e4b,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,
+0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,0,0,0,0,0,0,0,0x58b,0x68b,
+0x7cb,0x11cb,0x1e4b,0x784b,5,5,5,5,6,6,6,6,0,0,0,0,
+0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
+0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,
+0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x344b,
+0x34cb,0x348b,0x388b,0,5,5,5,5,5,5,5,5,5,5,0,6,
+6,0x13,0,0,5,5,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
-2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,0,0,0,0,0,0,0,0x58b,0x68b,0x7cb,0x11cb,0x1e4b,0x784b,
-5,5,5,5,6,6,6,6,0,0,0,0,0,0,0,0,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,
-0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x344b,0x34cb,0x348b,0x388b,0,
-5,5,5,5,5,5,5,5,5,5,0,6,6,0x13,0,0,
-5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,6,6,6,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0x58b,0x5cb,0x60b,
-0x64b,0x68b,0x7cb,0xa4b,0xccb,0x1e4b,0x344b,5,0,0,0,0,0,0,0,0,
+5,5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x68b,0x7cb,0xa4b,0xccb,0x1e4b,0x344b,5,
+0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,
+6,6,6,6,6,0x58b,0x7cb,0xa4b,0x1e4b,0x17,0x17,0x17,0x17,0x17,0,0,
+0,0,0,0,5,5,6,6,6,6,0x17,0x17,0x17,0x17,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,6,5,5,6,6,5,0,0,0,0,0,0,
+0,0,0,6,8,6,8,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,6,6,6,6,6,6,6,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0,0,0,0,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,
+0xa4b,0xccb,0xf4b,0x11cb,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,8,8,8,6,6,6,6,8,8,6,6,0x17,
+0x17,0x10,0x17,0x17,0x17,0x17,6,0,0,0,0,0,0,0,0,0,
+0,0x10,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5,
+5,5,5,6,6,6,6,6,8,6,6,6,6,6,6,6,
+6,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,
+5,8,8,5,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,6,6,6,6,6,6,6,6,6,6,6,0x58b,0x7cb,0xa4b,
-0x1e4b,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,5,5,6,6,
-6,6,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,
+0x17,0x17,5,0,0,0,0,0,0,0,0,0,8,5,5,5,
+5,0x17,0x17,0x17,0x17,6,6,6,6,0x17,8,6,0x49,0x89,0xc9,0x109,
+0x149,0x189,0x1c9,0x209,0x249,0x289,5,0x17,5,0x17,0x17,0x17,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8,
+8,8,6,6,6,6,6,6,6,6,6,8,0,0x58b,0x5cb,0x60b,
+0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,
+0x784b,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,8,8,8,6,6,6,8,8,
+6,8,6,6,0x17,0x17,0x17,0x17,0x17,0x17,6,5,5,6,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
-5,0x58b,0x5cb,0x60b,0x64b,0x7cb,0xa4b,0x1e4b,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x144b,0x16cb,0x194b,0x1bcb,
-0x1e4b,0x784b,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,6,5,5,6,
-6,5,0,0,0,0,0,0,0,0,0,6,8,6,8,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,
-6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0x30b,0x34b,
-0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,6,
-6,6,6,8,8,6,6,0x17,0x17,0x10,0x17,0x17,0x17,0x17,6,0,
-0,0,0,0,0,0,0,0,0,0x10,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,
-0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,
-0,0,0,0,5,5,5,5,5,5,5,6,6,6,6,6,
-8,6,6,6,6,6,6,6,6,0,0x49,0x89,0xc9,0x109,0x149,0x189,
-0x1c9,0x209,0x249,0x289,0x17,0x17,0x17,0x17,5,8,8,5,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,6,6,6,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,6,0x17,0x17,5,0,0,0,0,0,
-0,0,0,0,8,5,5,5,5,0x17,0x17,0x17,0x17,6,6,6,
-6,0x17,8,6,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,5,0x17,
-5,0x17,0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,8,8,8,6,6,6,6,6,6,
-6,6,6,8,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,
-0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0x784b,0,0,0,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-8,8,8,6,6,6,8,8,6,8,6,6,0x17,0x17,0x17,0x17,
-0x17,0x17,6,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0,5,0,5,5,5,5,0,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,
-5,5,5,5,5,5,5,5,5,0x17,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,0,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
+5,0x17,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,6,
+6,6,6,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,0,0,0,5,5,8,8,0,0,6,6,
+6,6,6,6,6,0,0,0,6,6,6,6,6,0,0,0,
+0,0,0,0,0,0,0,0,6,6,8,8,0,5,5,5,
+5,5,5,5,5,0,0,5,5,0,0,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
+5,0,5,5,0,5,5,5,5,5,0,6,6,5,8,8,
+6,8,8,8,8,0,0,8,8,0,0,8,8,8,0,0,
+5,0,0,0,0,0,0,8,0,0,0,0,0,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,8,8,8,6,6,6,6,6,6,6,6,
+8,8,6,6,6,8,6,5,5,5,5,0x17,0x17,0x17,0x17,0x17,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x17,0x17,0,0x17,6,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-8,8,8,6,6,6,6,6,6,6,6,0,0,0,0,0,
+8,8,8,6,6,6,6,6,6,8,6,8,8,8,8,6,
+6,8,6,6,5,5,0x17,5,0,0,0,0,0,0,0,0,
0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-5,5,8,8,0,0,6,6,6,6,6,6,6,0,0,0,
-6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,
-6,6,8,8,0,5,5,5,5,5,5,5,5,0,0,5,
-5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,0,5,5,5,5,5,5,5,0,5,5,0,5,5,5,
-5,5,0,6,6,5,8,8,6,8,8,8,8,0,0,8,
-8,0,0,8,8,8,0,0,5,0,0,0,0,0,0,8,
-0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,
-6,6,6,6,6,6,6,6,8,8,6,6,6,8,6,5,
-5,5,5,0x17,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0x17,0x17,0,0x17,6,5,5,5,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,8,
+8,8,6,6,6,6,0,0,8,8,8,8,6,6,8,6,
+6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,5,5,5,5,6,6,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+8,8,8,6,6,6,6,6,6,6,6,8,8,6,8,6,
+6,0x17,0x17,0x17,5,0,0,0,0,0,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,6,8,6,8,8,
+6,6,6,6,6,6,8,6,5,0x17,0,0,0,0,0,0,
+8,8,6,6,6,6,8,6,6,6,6,6,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0x17,0x17,0x17,0x1b,
+5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,8,8,8,6,
+6,6,6,6,6,6,6,6,8,6,6,0x17,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,
+0x16cb,0x194b,0x1bcb,0,0,0,0,0,0,0,0,0,0,0,0,5,
+8,5,8,6,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+5,5,5,5,5,5,5,0,0,5,0,0,5,5,5,5,
+5,5,5,5,0,5,5,0,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,8,8,8,8,8,8,0,8,
+8,0,0,6,6,8,6,5,6,5,0x17,5,8,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,6,
-6,8,6,8,8,8,8,6,6,8,6,6,5,5,0x17,5,
-0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,8,8,8,6,6,6,6,0,0,
-8,8,8,8,6,6,8,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-5,5,5,5,6,6,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,6,
-6,6,6,8,8,6,8,6,6,0x17,0x17,0x17,5,0,0,0,
-0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0,0,0,0,0,0,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,8,8,8,6,6,6,6,
+0,0,6,6,8,8,8,8,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,
+6,8,5,6,6,6,6,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,6,
+0,0,0,0,0,0,0,0,5,6,6,6,6,6,6,8,
+8,6,6,6,5,5,5,5,5,6,6,6,6,6,6,6,
+6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,0x17,0x17,0x17,0,0,0,0,0,
0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,6,8,6,8,8,6,6,6,6,6,6,8,6,
-5,0x17,0,0,0,0,0,0,8,8,6,6,6,6,8,6,
-6,6,6,6,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0x7cb,0xa4b,0x17,0x17,0x17,0x1b,5,5,5,5,5,5,5,0,
+5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,
+6,6,6,6,6,6,6,8,6,6,0x17,0x17,0x17,5,0x17,0x17,
+5,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,8,8,8,6,6,6,6,6,6,6,6,6,
-8,6,6,0x17,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0,0,0,0,0,
-0,0,0,0,0,0,0,5,8,5,8,6,0x17,0x17,0x17,0,
+0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0,0,0,
+0x17,0x17,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,8,6,6,6,6,
+6,6,6,0,6,6,6,6,6,6,8,6,6,6,6,6,
+6,6,6,6,0,8,6,6,6,6,6,6,6,8,6,6,
+8,6,6,0,0,0,0,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,5,6,
0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
0x249,0x289,0,0,0,0,0,0,5,5,5,5,5,5,5,0,
-0,5,0,0,5,5,5,5,5,5,5,5,0,5,5,0,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-8,8,8,8,8,8,0,8,8,0,0,6,6,8,6,5,
-6,5,0x17,5,8,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,8,8,8,6,6,6,6,0,0,6,6,8,8,8,8,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,6,6,6,6,6,6,8,5,6,6,6,6,0x17,
-0x17,0x17,0x17,0x17,0x17,0x17,0x17,6,0,0,0,0,0,0,0,0,
-5,6,6,6,6,6,6,8,8,6,6,6,5,5,5,5,
-5,6,6,6,6,6,6,6,6,6,6,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-0x17,0x17,0x17,0,0,0,0,0,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,8,
-6,6,0x17,0x17,0x17,5,0x17,0x17,5,0x17,0x17,0x17,0x17,0x17,0,0,
-0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
-0x249,0x289,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,
-0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,0,0,0,0x17,0x17,5,5,5,5,5,5,
+5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,0,
+0,0,6,0,6,6,0,6,5,5,5,5,5,5,5,5,
+5,5,8,8,8,8,8,0,6,6,0,8,8,6,8,6,
+5,0,0,0,0,0,0,0,5,5,5,5,5,5,0,5,
+5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,6,6,8,8,0x17,
+0x17,0,0,0,0,0,0,0,6,8,6,0x17,0x17,0x17,0x17,0x17,
+0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0,0,0,0,0,0,6,6,5,8,5,5,5,5,
5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,8,6,6,6,6,6,6,6,0,6,6,6,6,
-6,6,8,6,6,6,6,6,6,6,6,6,0,8,6,6,
-6,6,6,6,6,8,6,6,8,6,6,0,0,0,0,0,
-0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,0,0,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,5,6,0,0,0,0,0,0,0,0,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
-5,5,5,5,5,5,5,0,5,5,0,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,6,6,6,6,6,6,0,0,0,6,0,6,6,0,6,
-5,5,5,5,5,5,5,5,5,5,8,8,8,8,8,0,
-6,6,0,8,8,6,8,6,5,0,0,0,0,0,0,0,
-5,5,5,5,5,5,0,5,5,0,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,6,6,8,8,0x17,0x17,0,0,0,0,0,0,0,
+8,8,6,6,6,6,6,0,0,0,8,8,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0x19,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
@@ -1215,8 +1226,10 @@ static const uint16_t propsTrie_index[22688]={
0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,0x17,0x17,0,
0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,0x10,0x10,0x10,0x10,
-0x10,0x10,0x10,0x10,0x10,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
+5,5,5,5,5,5,5,5,5,5,5,5,0x10,0x10,0x10,0x10,
+0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,5,5,5,
+5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,
6,6,6,6,6,0x17,0,0,0,0,0,0,0,0,0,0,
@@ -1241,145 +1254,153 @@ static const uint16_t propsTrie_index[22688]={
5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,4,4,4,4,0,4,4,4,4,4,4,4,
0,4,4,0,5,5,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,5,5,5,0,0,5,0,0,
+0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,0,0,0,0,0,5,5,5,5,
+5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,0,0,0x1b,6,6,0x17,
+0x10,0x10,0x10,0x10,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,
-0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,
-5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,0,0,0,0,0,5,5,5,5,5,5,5,5,
-5,5,5,5,5,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,0,0,0x1b,6,6,0x17,0x10,0x10,0x10,0x10,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,0,0,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,
-0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,0x1b,8,8,8,
-8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,6,6,6,6,
-6,6,6,0x1b,0x1b,6,6,6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,8,8,6,6,6,0x1b,0x1b,
+0x1b,8,8,8,8,8,8,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,6,
+6,6,6,6,6,6,6,0x1b,0x1b,6,6,6,6,6,6,6,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,0x1b,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0x54b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,
-0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,0,0,0,0,
-0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,
-0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x58b,0x5cb,0x60b,0x64b,0x68b,0x58b,
-0x68b,0,0,0,0,0,0,0,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,
-0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89,
-0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,2,2,2,2,2,2,2,0,2,2,
-2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,6,
+6,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0x54b,0x58b,0x5cb,0x60b,
+0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x80b,0x84b,0x88b,0x8cb,0x90b,0x94b,0x98b,0x9cb,0xa0b,
+0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,0x64b,
+0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x58b,0x5cb,
+0x60b,0x64b,0x68b,0x58b,0x68b,0,0,0,0,0,0,0,0x249,0x289,0x49,0x89,
+0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,
+0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,1,0,1,1,
-0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,
-1,1,1,1,1,1,2,2,2,2,0,2,0,2,2,2,
-2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,
+1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
+2,0,2,2,2,2,2,2,2,2,2,2,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-2,2,2,2,1,1,0,1,1,1,1,0,0,1,1,1,
-1,1,1,1,1,0,1,1,1,1,1,1,1,0,2,2,
+1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,1,1,0,1,1,1,1,0,
-1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,
+1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,
+1,0,1,1,1,1,1,1,1,1,2,2,2,2,0,2,
+0,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,1,1,0,1,1,1,1,0,
+0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,
1,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,1,1,0,1,
+1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,1,
+1,1,1,1,1,0,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,2,2,2,2,2,2,0,0,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-2,2,2,2,2,2,0,0,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,0x18,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,0x18,2,2,2,2,
-2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,1,1,1,0x18,2,2,2,2,
+1,1,1,1,1,0x18,2,2,2,2,2,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0x18,
+2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0x18,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,0x18,2,2,2,2,2,2,1,1,1,1,1,1,1,1,
-1,1,1,1,1,1,1,1,2,2,2,0x18,2,2,2,2,
-2,2,1,2,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,
-0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0x1b,
-0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,
-6,6,6,0,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,0,0,6,6,6,6,6,2,2,2,2,
-2,2,2,2,2,2,5,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,0,6,6,0,6,
-6,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,5,0x1b,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,0,0,0,6,6,6,6,
-6,6,6,4,4,4,4,4,4,4,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,6,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
-5,5,5,5,5,5,5,5,6,6,6,6,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0x19,5,5,5,5,
-5,5,5,0,5,5,5,5,0,5,5,0,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,
-5,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,6,6,6,6,
-6,6,6,0,0,0,0,0,0,0,0,0,2,2,2,2,
-6,6,6,6,6,6,6,4,0,0,0,0,0x49,0x89,0xc9,0x109,
-0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,1,1,2,2,
+2,2,2,2,2,0x18,2,2,2,2,2,2,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,0x18,
+2,2,2,2,2,2,1,2,0,0,0x49,0x89,0xc9,0x109,0x149,0x189,
+0x1c9,0x209,0x249,0x289,0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,0x1b,0x1b,0x1b,0x1b,6,6,6,6,6,6,6,6,6,
+6,6,6,6,6,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,6,0x1b,0x1b,0x17,0x17,0x17,0x17,0x17,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+6,6,6,6,6,6,6,0,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,6,0,0,6,6,6,6,6,
+2,2,2,2,2,2,2,2,2,2,5,2,2,2,2,2,
+2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
+0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+6,6,0,6,6,0,6,6,6,6,6,0,0,0,0,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,5,0x1b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,
+6,6,6,6,6,6,6,4,4,4,4,4,4,4,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0x19,
+5,5,5,5,5,5,5,5,5,5,5,4,6,6,6,6,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0,0,
+5,5,5,5,5,5,5,0,5,5,5,5,0,5,5,0,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,
+5,5,5,5,5,0,0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,
+6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0,
+2,2,2,2,6,6,6,6,6,6,6,4,0,0,0,0,
+0x49,0x89,0xc9,0x109,0x149,0x189,0x1c9,0x209,0x249,0x289,0,0,0,0,0x17,0x17,
+1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
-2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0,0x58b,0x5cb,0x60b,
-0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x78cb,0x794b,0x814b,0x58b,
-0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x1b,0x34cb,0x344b,0x3ccb,0x19,0x58b,0x5cb,0x788b,
-0x78cb,0,0,0,0,0,0,0,0,0,0,0,0x16cb,0x194b,0x1bcb,0x1e4b,
-0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0x984b,0xa04b,0xa84b,0xb04b,
-0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,0x984b,0xa04b,0xa84b,0xb04b,
-0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x1b,0x5cb,0x60b,0x64b,0x68b,0x6cb,
-0x70b,0x74b,0x78b,0x7cb,0x900b,0xa00b,0x804b,0x788b,0x344b,0x354b,0,0,0,0x58b,0x5cb,0x60b,
-0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,0x16cb,0x194b,0x1bcb,0x1e4b,
-0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x18,0x18,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,
-0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,0,
-5,0,0,5,0,5,5,5,5,5,5,5,5,5,5,0,
-5,5,5,5,0,5,0,5,0,0,0,0,0,0,5,0,
-0,0,0,5,0,5,0,5,0,5,5,5,0,5,5,0,
-5,0,0,5,0,5,0,5,0,5,0,5,0,5,5,0,
-5,0,0,5,5,5,5,0,5,5,5,5,5,5,5,0,
-5,5,5,5,0,5,5,5,5,0,5,0,5,5,5,5,
-5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,0,0,0,0,5,5,5,
-0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,5,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x2cb,0x2cb,0x30b,0x34b,
-0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x54b,0x54b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,
+0x78cb,0x794b,0x814b,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x1b,0x34cb,0x344b,0x3ccb,
+0x19,0x58b,0x5cb,0x788b,0x78cb,0,0,0,0,0,0,0,0,0,0,0,
+0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,
+0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x78cb,0x80cb,
+0x984b,0xa04b,0xa84b,0xb04b,0xb84b,0x788b,0x808b,0x888b,0x908b,0x988b,0xa08b,0xa88b,0xb08b,0xb88b,0x1b,0x5cb,
+0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0x900b,0xa00b,0x804b,0x788b,0x344b,0x354b,0,0,
+0,0x58b,0x5cb,0x60b,0x64b,0x68b,0x6cb,0x70b,0x74b,0x78b,0x7cb,0xa4b,0xccb,0xf4b,0x11cb,0x144b,
+0x16cb,0x194b,0x1bcb,0x1e4b,0x800b,0x880b,0x900b,0x980b,0xa00b,0xa80b,0xb00b,0xb80b,0x784b,0x804b,0x884b,0x904b,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x18,0x18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+0,5,5,0,5,0,0,5,0,5,5,5,5,5,5,5,
+5,5,5,0,5,5,5,5,0,5,0,5,0,0,0,0,
+0,0,5,0,0,0,0,5,0,5,0,5,0,5,5,5,
+0,5,5,0,5,0,0,5,0,5,0,5,0,5,0,5,
+0,5,5,0,5,0,0,5,5,5,5,0,5,5,5,5,
+5,5,5,0,5,5,5,5,0,5,5,5,5,0,5,0,
+5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
+0,5,5,5,0,5,5,5,5,5,0,5,5,5,5,5,
+5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
-0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0x1b,0x1b,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x2cb,0x2cb,0x30b,0x34b,0x38b,0x3cb,0x40b,0x44b,0x48b,0x4cb,0x50b,0x54b,0x54b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,
0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x1a,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x1a,0x1a,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0x1b,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0x1b,0x1b,0x1b,0x1b,
@@ -1388,13 +1409,12 @@ static const uint16_t propsTrie_index[22688]={
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
0x1b,0x1b,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,0,0,0,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,
+0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,
-0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,
-0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,
+0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0,0,0,0,0,
+0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0,0,0,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
0x1b,0x1b,0x1b,0x1b,5,0x705,5,5,5,5,5,5,5,5,5,5,
@@ -1416,176 +1436,177 @@ static const uint16_t propsTrie_index[22688]={
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,0x605,5,5,5,5,5,5,5,5,5,5,5,5,
5,0x645,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,0x785,5,5,5,5,5,5,5,5,5,5,5,
-5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x10,0x10,0x10,0x10,
+5,5,5,5,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
-0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0,0x10,0,0,
+0x10,0x10,0x10,0x10,0,0x10,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,
-6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,
-0,0,0,0,0,0,0,0,0,0,0,0,0x11,0x11,0x11,0x11,
+0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,
+6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
-0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0,0,0,0,0,0
+0x11,0x11,0,0,0,0,0,0
};
static const UTrie2 propsTrie={
propsTrie_index,
- propsTrie_index+4656,
+ propsTrie_index+4692,
NULL,
- 4656,
- 18032,
+ 4692,
+ 18324,
0xa40,
- 0x12b0,
+ 0x12d4,
0x0,
0x0,
0x110000,
- 0x589c,
- NULL, 0, FALSE, FALSE, 0, NULL
+ 0x59e4,
+ NULL, 0, false, false, 0, NULL
};
-static const uint16_t propsVectorsTrie_index[32060]={
-0x511,0x519,0x521,0x529,0x541,0x549,0x551,0x559,0x561,0x569,0x571,0x579,0x581,0x589,0x591,0x599,
-0x5a0,0x5a8,0x5b0,0x5b8,0x5bb,0x5c3,0x5cb,0x5d3,0x5db,0x5e3,0x5eb,0x5f3,0x5fb,0x603,0x60b,0x613,
-0x61b,0x623,0x62a,0x632,0x63a,0x642,0x64a,0x652,0x65a,0x662,0x667,0x66f,0x676,0x67e,0x686,0x68e,
-0x696,0x69e,0x6a6,0x6ae,0x6b5,0x6bd,0x6c5,0x6cd,0x6d5,0x6dd,0x6e5,0x6ed,0x6f5,0x6fd,0x705,0x70d,
-0x1aba,0xd5a,0xe2e,0x1162,0x1299,0x1c7b,0x1e12,0x1c73,0x1367,0x1377,0x135f,0x136f,0x7da,0x7e0,0x7e8,0x7f0,
-0x7f8,0x7fe,0x806,0x80e,0x816,0x81c,0x824,0x82c,0x834,0x83a,0x842,0x84a,0x852,0x85a,0x862,0x869,
-0x871,0x877,0x87f,0x887,0x88f,0x895,0x89d,0x8a5,0x8ad,0x137f,0x8b5,0x8bd,0x8c5,0x8cc,0x8d4,0x8dc,
-0x8e4,0x8e8,0x8f0,0x8f7,0x8ff,0x907,0x90f,0x917,0x169a,0x16a2,0x91f,0x927,0x92f,0x937,0x93f,0x946,
-0x1700,0x16f0,0x16f8,0x19f5,0x19fd,0x138f,0x94e,0x1387,0x15e3,0x15e3,0x15e5,0x13a3,0x13a4,0x1397,0x1399,0x139b,
-0x1708,0x170a,0x956,0x170a,0x95e,0x963,0x96b,0x170f,0x971,0x170a,0x977,0x97f,0xc3a,0x1717,0x1717,0x987,
-0x1727,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,0x1728,
-0x1728,0x1728,0x1728,0x171f,0x98f,0x1730,0x1730,0x997,0xb62,0xb6a,0xb72,0xb7a,0x1740,0x1738,0x99f,0x9a7,
-0x9af,0x174a,0x1752,0x9b7,0x1748,0x9bf,0x1ac2,0xd62,0xb82,0xb8a,0xb92,0xb97,0x195b,0xc61,0xc68,0x18b7,
-0xc12,0x1aca,0xd6a,0xd72,0xd7a,0xd82,0xf38,0xf3c,0x19bb,0x19c0,0xca0,0xca8,0x1a31,0x1a39,0x1b93,0xe36,
-0x1a41,0xcee,0xcf6,0x1a49,0x10e2,0x118a,0xf10,0xd8a,0x18d7,0x18bf,0x18cf,0x18c7,0x1973,0x196b,0x1927,0x19b3,
-0x13ac,0x13ac,0x13ac,0x13ac,0x13af,0x13ac,0x13ac,0x13b7,0x9c7,0x13bf,0x9cb,0x9d3,0x13bf,0x9db,0x9e3,0x9eb,
-0x13cf,0x13c7,0x13d7,0x9f3,0x9fb,0x13df,0xa03,0xa0b,0x13e7,0x13ef,0x13f7,0x13ff,0xa13,0x1407,0x140e,0x1416,
-0x141e,0x1426,0x142e,0x1436,0x143e,0x1445,0x144d,0x1455,0x145d,0x1465,0x1468,0x146a,0x175a,0x184d,0x1853,0x19a3,
-0x1472,0xa1b,0xa23,0x1598,0x159d,0x15a0,0x15a6,0x147a,0x15ae,0x15ae,0x148a,0x1482,0x1492,0x149a,0x14a2,0x14aa,
-0x14b2,0x14ba,0x14c2,0x14ca,0x185b,0x18af,0x1a05,0x1b5b,0x14da,0x14e0,0x14e8,0x14f0,0x14d2,0x14f8,0x1863,0x186a,
-0x1762,0x1762,0x1762,0x1762,0x1762,0x1762,0x1762,0x1762,0x1872,0x1872,0x1872,0x1872,0x187a,0x1881,0x1883,0x188a,
-0x1892,0x1896,0x1896,0x1899,0x1896,0x1896,0x189f,0x1896,0x18df,0x19ab,0x1a0d,0xb9f,0xba5,0x1cbf,0x1cc7,0x1d9d,
-0x194b,0x193f,0x1943,0x19c8,0x192f,0x192f,0x192f,0xc22,0x1937,0xc42,0x198b,0xc90,0xc2a,0xc32,0xc32,0x1a51,
-0x197b,0x1a15,0xc78,0xc80,0xa2b,0x176a,0x176a,0xa33,0x1772,0x1772,0x1772,0x1772,0x1772,0x1772,0xa3b,0x715,
-0x15cb,0x15ed,0xa43,0x15f5,0xa4b,0x15fd,0x1605,0x160d,0xa53,0xa58,0x1615,0x161c,0xa5d,0x177a,0x199b,0xc1a,
-0xa65,0x1677,0x167e,0x1624,0x1686,0x168a,0x162c,0x1630,0x1649,0x1649,0x164b,0x1638,0x1640,0x1640,0x1641,0x1692,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,
-0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1782,0x1785,0x18e7,0x18e7,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,
-0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x1653,0x165a,0x1ab2,0x1e7e,
-0x178d,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,
-0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,0x1793,
-0x1793,0x1793,0x1793,0x1793,0xa6d,0x179b,0xa75,0x1ad2,0x1a5d,0x1a5d,0x1a5d,0x1a5d,0x1a5d,0x1a5d,0x1a5d,0x1a5d,
-0x1a59,0xcfe,0x1a6d,0x1a65,0x1a6f,0x1ada,0x1ada,0xd92,0x1953,0x19d0,0x1a25,0x1a29,0x1a1d,0x1b8b,0xcb0,0xcb7,
-0x1983,0xc88,0x19d8,0xcbf,0x1a77,0x1a7a,0xd06,0x1ae2,0x1a8a,0x1a82,0xd0e,0xd9a,0x1aea,0x1aee,0xda2,0xfec,
-0x1a92,0xd16,0xd1e,0x1af6,0x1b06,0x1afe,0xdaa,0xee0,0xe3e,0xe46,0x1d0d,0xf9c,0x1dba,0x1dba,0x1b0e,0xdb2,
-0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,
-0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,
-0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
-0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,
-0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,
-0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,
-0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,
-0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,
-0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,
-0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
-0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,
-0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,
-0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,
-0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,
-0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,
-0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,
-0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
-0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,
-0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,
-0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,
-0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,
-0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0x16e8,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,0xa7d,0xdba,0xdbd,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,
-0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,0x16ba,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,
-0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x15b6,0x1662,0x1662,0x1662,0x1662,0x1662,0x1662,0x1662,0x1662,
-0x1667,0x166f,0x18a7,0x132c,0x1993,0x1993,0x1330,0x1337,0xa85,0xa8d,0xa95,0x1518,0x151f,0x1527,0xa9d,0x152f,
-0x156d,0x156d,0x1500,0x1508,0x1537,0x1564,0x1565,0x1575,0x153f,0x1544,0x154c,0x1554,0xaa5,0x155c,0xaad,0x1510,
-0xc98,0x157d,0xab5,0xabd,0x1585,0x158b,0x1590,0xac5,0xad5,0x15d3,0x15db,0x15be,0x15c3,0xadd,0xae5,0xacd,
-0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,
-0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16aa,0x16b2,0x16b2,0x16b2,0x16b2,
-0x14c4,0x14c4,0x1504,0x1544,0x1584,0x15c4,0x1604,0x1644,0x1680,0x16c0,0x16ec,0x172c,0x176c,0x17ac,0x17ec,0x182c,
-0x186c,0x18a8,0x18e8,0x1928,0x1968,0x199c,0x19d8,0x1a18,0x1a58,0x1a98,0x1ad4,0x1b14,0x1b54,0x1b94,0x1bd4,0x1c14,
-0xe59,0xa80,0xac0,0xb00,0xb40,0xb6b,0xed9,0xa40,0xefb,0xa40,0xa40,0xa40,0xa40,0xbab,0x1381,0x1381,
-0xf3b,0xfbb,0xa40,0xa40,0xa40,0xbeb,0xf7b,0xc2b,0xa40,0xc51,0xc91,0xcd1,0xd11,0xd51,0xe99,0xdc9,
-0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,0x12c1,
-0x12c1,0x12c1,0x12c1,0x12c1,0xffb,0x1301,0x1136,0x1176,0x1341,0x1181,0x13c1,0x13c1,0x13c1,0x103b,0x105b,0x109b,
-0x1401,0x1401,0x10db,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,
-0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x105b,0x10f6,
+static const uint16_t propsVectorsTrie_index[32692]={
+0x539,0x541,0x549,0x551,0x569,0x571,0x579,0x581,0x589,0x591,0x599,0x5a1,0x5a9,0x5b1,0x5b9,0x5c1,
+0x5c8,0x5d0,0x5d8,0x5e0,0x5e3,0x5eb,0x5f3,0x5fb,0x603,0x60b,0x613,0x61b,0x623,0x62b,0x633,0x63b,
+0x643,0x64b,0x652,0x65a,0x662,0x66a,0x672,0x67a,0x682,0x68a,0x68f,0x697,0x69e,0x6a6,0x6ae,0x6b6,
+0x6be,0x6c6,0x6ce,0x6d6,0x6dd,0x6e5,0x6ed,0x6f5,0x6fd,0x705,0x70d,0x715,0x71d,0x725,0x72d,0x735,
+0x1b39,0xd8a,0xe56,0x118d,0x12cc,0x1d01,0x1ea0,0x1cf9,0x13e6,0x13f6,0x13de,0x13ee,0x80a,0x810,0x818,0x820,
+0x828,0x82e,0x836,0x83e,0x846,0x84c,0x854,0x85c,0x864,0x86a,0x872,0x87a,0x882,0x88a,0x892,0x899,
+0x8a1,0x8a7,0x8af,0x8b7,0x8bf,0x8c5,0x8cd,0x8d5,0x8dd,0x13fe,0x8e5,0x8ed,0x8f5,0x8fc,0x904,0x90c,
+0x914,0x918,0x920,0x927,0x92f,0x937,0x93f,0x947,0x1719,0x1721,0x94f,0x957,0x95f,0x967,0x96f,0x976,
+0x177f,0x176f,0x1777,0x1a74,0x1a7c,0x140e,0x97e,0x1406,0x1662,0x1662,0x1664,0x1422,0x1423,0x1416,0x1418,0x141a,
+0x1787,0x1789,0x986,0x1789,0x98e,0x993,0x99b,0x178e,0x9a1,0x1789,0x9a7,0x9af,0xc6a,0x1796,0x1796,0x9b7,
+0x17a6,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,0x17a7,
+0x17a7,0x17a7,0x17a7,0x179e,0x9bf,0x17af,0x17af,0x9c7,0xb92,0xb9a,0xba2,0xbaa,0x17bf,0x17b7,0x9cf,0x9d7,
+0x9df,0x17c9,0x17d1,0x9e7,0x17c7,0x9ef,0x1b41,0xd92,0xbb2,0xbba,0xbc2,0xbc7,0x19da,0xc91,0xc98,0x1936,
+0xc42,0x1b49,0xd9a,0xda2,0xdaa,0xdb2,0xf60,0xf64,0x1a3a,0x1a3f,0xcd0,0xcd8,0x1ab0,0x1ab8,0x1c19,0xe5e,
+0x1ac0,0xd1e,0xd26,0x1ac8,0x1105,0x11b5,0xf38,0xdba,0x1956,0x193e,0x194e,0x1946,0x19f2,0x19ea,0x19a6,0x1a32,
+0x142b,0x142b,0x142b,0x142b,0x142e,0x142b,0x142b,0x1436,0x9f7,0x143e,0x9fb,0xa03,0x143e,0xa0b,0xa13,0xa1b,
+0x144e,0x1446,0x1456,0xa23,0xa2b,0x145e,0xa33,0xa3b,0x1466,0x146e,0x1476,0x147e,0xa43,0x1486,0x148d,0x1495,
+0x149d,0x14a5,0x14ad,0x14b5,0x14bd,0x14c4,0x14cc,0x14d4,0x14dc,0x14e4,0x14e7,0x14e9,0x17d9,0x18cc,0x18d2,0x1a22,
+0x14f1,0xa4b,0xa53,0x1617,0x161c,0x161f,0x1625,0x14f9,0x162d,0x162d,0x1509,0x1501,0x1511,0x1519,0x1521,0x1529,
+0x1531,0x1539,0x1541,0x1549,0x18da,0x192e,0x1a84,0x1be1,0x1559,0x155f,0x1567,0x156f,0x1551,0x1577,0x18e2,0x18e9,
+0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x17e1,0x18f1,0x18f1,0x18f1,0x18f1,0x18f9,0x1900,0x1902,0x1909,
+0x1911,0x1915,0x1915,0x1918,0x1915,0x1915,0x191e,0x1915,0x195e,0x1a2a,0x1a8c,0xbcf,0xbd5,0x1d45,0x1d4d,0x1e2b,
+0x19ca,0x19be,0x19c2,0x1a47,0x19ae,0x19ae,0x19ae,0xc52,0x19b6,0xc72,0x1a0a,0xcc0,0xc5a,0xc62,0xc62,0x1ad0,
+0x19fa,0x1a94,0xca8,0xcb0,0xa5b,0x17e9,0x17e9,0xa63,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0xa6b,0x73d,
+0x164a,0x166c,0xa73,0x1674,0xa7b,0x167c,0x1684,0x168c,0xa83,0xa88,0x1694,0x169b,0xa8d,0x17f9,0x1a1a,0xc4a,
+0xa95,0x16f6,0x16fd,0x16a3,0x1705,0x1709,0x16ab,0x16af,0x16c8,0x16c8,0x16ca,0x16b7,0x16bf,0x16bf,0x16c0,0x1711,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,
+0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1801,0x1804,0x1966,0x1966,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
+0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d9,0x1b31,0x1f0c,
+0x180c,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
+0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
+0x1812,0x1812,0x1812,0x1812,0xa9d,0x181a,0xaa5,0x1b51,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,
+0x1ad8,0xd2e,0x1aec,0x1ae4,0x1aee,0x1b59,0x1b59,0xdc2,0x19d2,0x1a4f,0x1aa4,0x1aa8,0x1a9c,0x1c11,0xce0,0xce7,
+0x1a02,0xcb8,0x1a57,0xcef,0x1af6,0x1af9,0xd36,0x1b61,0x1b09,0x1b01,0xd3e,0xdca,0x1b69,0x1b6d,0xdd2,0x100f,
+0x1b11,0xd46,0xd4e,0x1b75,0x1b85,0x1b7d,0xdda,0xf08,0xe66,0xe6e,0x1d9b,0xfbf,0x1e48,0x1e48,0x1b8d,0xde2,
+0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,
+0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,
+0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,
+0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,
+0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,
+0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,
+0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,
+0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,
+0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,
+0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,
+0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,
+0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,
+0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,
+0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,
+0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,
+0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,
+0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,
+0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,
+0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0xaad,0xdea,0xded,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,
+0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,0x1739,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,
+0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,0x16e1,
+0x16e6,0x16ee,0x1926,0x13a3,0x1a12,0x1a12,0x13a7,0x13ae,0xab5,0xabd,0xac5,0x1597,0x159e,0x15a6,0xacd,0x15ae,
+0x15ec,0x15ec,0x157f,0x1587,0x15b6,0x15e3,0x15e4,0x15f4,0x15be,0x15c3,0x15cb,0x15d3,0xad5,0x15db,0xadd,0x158f,
+0xcc8,0x15fc,0xae5,0xaed,0x1604,0x160a,0x160f,0xaf5,0xb05,0x1652,0x165a,0x163d,0x1642,0xb0d,0xb15,0xafd,
+0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,
+0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1729,0x1731,0x1731,0x1731,0x1731,
+0x1564,0x1564,0x15a4,0x15e4,0x1624,0x1664,0x16a4,0x16e4,0x1720,0x1760,0x178c,0x17cc,0x180c,0x184c,0x188c,0x18cc,
+0x190c,0x1948,0x1988,0x19c8,0x1a08,0x1a3c,0x1a78,0x1ab8,0x1af8,0x1b38,0x1b74,0x1bb4,0x1bf4,0x1c34,0x1c74,0x1cb4,
+0xe59,0xa80,0xac0,0xb00,0xb40,0xb6b,0xf99,0xa40,0xed9,0xa40,0xa40,0xa40,0xa40,0xbab,0x13e2,0x13e2,
+0xf19,0xfd9,0xa40,0xa40,0xa40,0xbeb,0xf59,0xc2b,0xa40,0xc51,0xc91,0xcd1,0xd11,0xd51,0xe99,0xdc9,
+0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,0x1322,
+0x1322,0x1322,0x1322,0x1322,0x1019,0x1362,0x1157,0x1197,0x13a2,0x11a2,0x1422,0x1422,0x1422,0x1059,0x1079,0x10b9,
+0x1462,0x1462,0x11e2,0x14a2,0x10f9,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,
+0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1079,0x1117,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
@@ -1608,1868 +1629,1908 @@ static const uint16_t propsVectorsTrie_index[32060]={
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89,
0xe09,0xe19,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,
0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xa40,0xd89,
-0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,
-0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x1241,0x11c1,
-0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,
-0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1281,0x1201,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0xbf7,0xbfa,0xdc5,0x1d5d,0xff4,0x71d,0x531,0x108e,0xcc7,0xd46,0x531,0x531,0x1c8b,0xee8,0xef0,0x1da5,
-0xc4a,0xc51,0xc59,0x1b16,0x1d3d,0x531,0x1d1d,0xfc4,0x1b1e,0xdcd,0xdd5,0xddd,0x101c,0x725,0x531,0x531,
-0x1b26,0x1b26,0x72d,0x531,0x1dd2,0x10a6,0x1dca,0x10ae,0x1ebe,0x11a0,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0xde5,0x1f16,0x1291,0x531,0x531,0x1ede,0x11c8,0x11cf,0x11d6,0x12cd,0x12d1,0x1248,0x11de,
-0x1b9b,0x1b9d,0xe4e,0xe55,0x1b2e,0x1b36,0xded,0xf08,0x1c83,0xed0,0xed8,0xfbc,0x1ca3,0x1ca7,0x1caf,0x103c,
-0xf87,0xf8c,0x735,0x531,0x1096,0x109e,0x1d05,0xf94,0xf69,0xf6f,0xf77,0xf7f,0x531,0x531,0x531,0x531,
-0x1e42,0x1e3a,0x1110,0x1118,0x1d85,0x1d7d,0x1064,0x531,0x531,0x531,0x531,0x531,0x1d6d,0x1024,0x102c,0x1034,
-0x1d35,0x1d2d,0xfd4,0x1108,0x1cb7,0xf18,0x73d,0x531,0x1074,0x107c,0x745,0x531,0x531,0x531,0x531,0x531,
-0x1eb6,0x1182,0x74d,0x531,0x531,0x1d95,0x1d8d,0x106c,0x1250,0x1256,0x125e,0x531,0x531,0x11e6,0x11ea,0x11f2,
-0x1e76,0x1e6e,0x116a,0x1e66,0x1e5e,0x115a,0x1d65,0x1014,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x10c6,0x10cb,0x10d3,0x10da,0x10fa,0x1100,0x531,0x531,0x113e,0x1142,0x114a,0x1192,0x1198,0x755,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x11b0,0x531,0x531,0x531,0x531,0x531,0x759,0x1efe,0x1238,
-0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,
-0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e0,0x19e5,0xccf,0xcd6,0xcd6,0xcd6,
-0x19ed,0x19ed,0x19ed,0xcde,0x1dc2,0x1dc2,0x1dc2,0x1dc2,0x1dc2,0x1dc2,0x761,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x765,0x1f2e,0x1f2e,0x12a1,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,
-0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0x1ba5,0xe5d,0xfdc,0xfe4,0x1f36,
-0x12d9,0x12e1,0xf20,0x1d55,0x1d4d,0x1004,0x100c,0x76d,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1ed6,0x1ece,0x11c0,
-0x531,0x531,0x531,0x1c9b,0x1c9b,0xef8,0x1c93,0xf00,0x531,0x531,0x10f2,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x771,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1ced,0x1ced,0x1ced,0xf44,0xf49,
-0x779,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1f46,0x1301,0x1308,0x1f3e,0x1f3e,0x1f3e,0x781,
-0x531,0x17c0,0x17c0,0x17c0,0x17c0,0x17c0,0x17c0,0x17c0,0xafb,0x17d0,0xb03,0x17d1,0x17c8,0x17d9,0x17df,0x17e7,
-0xb0b,0x190f,0x190f,0x789,0x531,0x531,0x531,0x531,0x11b8,0x18ff,0x18ff,0xc02,0xce6,0x531,0x531,0x531,
-0x531,0x1818,0x181f,0xb13,0x1822,0xb1b,0xb23,0xb2b,0x181c,0xb33,0xb3b,0xb43,0x1821,0x1829,0x1818,0x181f,
-0x181b,0x1822,0x182a,0x1819,0x1820,0x181c,0xb4a,0x17ef,0x17f7,0x17fe,0x1805,0x17f2,0x17fa,0x1801,0x1808,0xb52,
-0x1810,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,0x1dea,
-0x1dea,0x1dda,0x1ddd,0x1dda,0x1de4,0x10b6,0x791,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x12bd,0x12c5,0x12c5,0x12c5,0x12c5,0x12c5,0x12c5,
-0x12c5,0x10ea,0x799,0x531,0x531,0x531,0x531,0x531,0x531,0x1ef6,0x11fa,0x7a1,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x7a5,0x12e9,0x1f06,0x1240,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x12a9,0x1d25,0x1d25,0x1d25,0x1d25,0x1d25,0x1d25,0xfcc,0x531,0x1e32,0x1e2a,0x10be,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x7ad,0x1ec6,0x11a8,0x531,0x531,0x1202,0x1203,0x7b5,0x531,0x531,0x531,0x531,
-0x531,0xe95,0xe9d,0xea5,0xead,0xeb5,0xebd,0xec4,0xec8,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x7b9,0x1044,0x1d75,0x104a,0x1d75,0x1052,0x1057,0x105c,
-0x105c,0x1dfa,0x1e1a,0x1e22,0x1e8e,0x1e02,0x1ee6,0x1e0a,0x1e96,0x1eee,0x1eee,0x1172,0x117a,0x121a,0x1220,0x1228,
-0x1230,0x1f0e,0x1f0e,0x1f0e,0x1f0e,0x1274,0x1f0e,0x127a,0x127e,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,
-0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,
-0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c1,0x7c2,0xb5a,0x1832,0x1832,0x1832,0x7ca,0x7ca,0x7ca,
-0x7ca,0x1907,0x1907,0x1907,0x1907,0x1907,0x1907,0x1907,0x7d2,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,
-0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,
-0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,
-0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,
-0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0x7ca,0xbad,0xbb4,0xbbc,0xbc4,0x18ef,0x18ef,0x18ef,
-0xbcc,0xbd4,0xbd7,0x191f,0x1917,0xc0a,0xd26,0xd2a,0xd2e,0x531,0x531,0x531,0x531,0xd36,0x1a9a,0xd3e,
-0xf30,0x17a3,0xaed,0xaf3,0xffc,0xbdf,0x1963,0xc70,0x531,0x17b8,0x17ab,0x17b0,0x18f7,0xbe7,0xbef,0x1120,
-0x1126,0x1cf5,0xf51,0x1ce5,0xf28,0x12f1,0x12f9,0x531,0x531,0x1d15,0x1d15,0x1d15,0x1d15,0x1d15,0x1d15,0x1d15,
-0x1d15,0x1d15,0xfa4,0xfac,0xfb4,0x12b1,0x12b5,0x531,0x531,0x1aa2,0xd4e,0x1aaa,0x1aaa,0xd52,0xe65,0xe6d,
-0xe75,0x1b6b,0x1b53,0x1b73,0x1b7b,0x1b63,0xdfd,0xe01,0xe08,0xe10,0xe14,0xe1c,0xe24,0xe26,0xe26,0xe26,
-0xe26,0x1bdc,0x1be4,0x1bdc,0x1bea,0x1bf2,0x1bbd,0x1bfa,0x1c02,0x1bdc,0x1c0a,0x1c12,0x1c19,0x1c21,0x1bc5,0x1bdc,
-0x1c26,0x1bcd,0x1bd4,0x1c2e,0x1c34,0x1cd6,0x1cdd,0x1ccf,0x1c3b,0x1c43,0x1c4b,0x1c53,0x1d45,0x1c5b,0x1c63,0xe7d,
-0xe85,0x1bad,0x1bad,0x1bad,0xe8d,0x1cfd,0x1cfd,0xf59,0xf61,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,
-0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b40,0x1b3e,0x1b48,0x1b3e,0x1b3e,
-0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b4b,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0x1b3e,0xdf5,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,
-0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1dad,0x1db2,0x1dad,0x1dad,0x1dad,0x1084,0x1086,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x112e,0x1bb5,0x1e86,0x1e86,0x1e86,0x1e86,
-0x1e86,0x1e86,0x1e86,0x1ea6,0x1136,0x120b,0x1212,0x1eae,0x1eae,0x1eae,0x1eae,0x1eae,0x1eae,0x1eae,0x1eae,0x1eae,
-0x1eae,0x1eae,0x1152,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,
-0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,0x1e52,
-0x1e52,0x1e52,0x1e56,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,0x1f26,
-0x1f26,0x1266,0x126c,0x1286,0x1289,0x1289,0x1289,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,
-0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x531,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183d,0x1310,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1318,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1845,0x1845,0x1845,0x1845,0x1845,
-0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x1845,0x133f,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x131c,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1324,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,0x1310,
-0x1310,0x1310,0x1310,0x1310,0x1310,0x131c,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1347,
-0x1c6b,0x1c6b,0x1c6b,0x1c6b,0x1c6b,0x1c6b,0x134f,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1357,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16c2,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16ca,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,0x16d2,
-0x16d2,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,0x16da,
-0x16da,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,0x183a,
-0x183a,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,0x1b83,
-0x1b83,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,0x1df2,
-0x1df2,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,0x1e4a,
-0x1e4a,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,0x1e9e,
-0x1e9e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,0x1f1e,
-0x1f1e,0x510,0x510,0x510,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d6,0x2df,0x2d9,
-0x2d9,0x2dc,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,
-0x2d3,0x2d3,0x2d3,0x2d3,0x7cb,0x7c5,0x7aa,0x78f,0x79b,0x798,0x78f,0x7a7,0x795,0x7a1,0x78f,0x7bc,
-0x7b3,0x7a4,0x7c8,0x79e,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x7b0,0x7ad,
-0x7b6,0x7b6,0x7b6,0x7c5,0x78f,0x7d7,0x7d7,0x7d7,0x7d7,0x7d7,0x7d7,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,
-0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x7d1,0x795,
-0x79b,0x7a1,0x7c2,0x789,0x7bf,0x7d4,0x7d4,0x7d4,0x7d4,0x7d4,0x7d4,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,
-0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x7ce,0x795,
-0x7b9,0x792,0x7b6,0x2d3,0,0,0,0,0,0,0,0,0,0,0,0,
+0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,
+0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x12a2,0x1222,
+0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,
+0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x12e2,0x1262,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0xc27,0xc2a,0xdf5,0x1deb,0x1017,0x745,0x559,0x10b1,0xcf7,0xd76,0x559,0x559,0x1d11,0xf10,0xf18,0x1e33,
+0xc7a,0xc81,0xc89,0x1b95,0x1dcb,0x559,0x1dab,0xfe7,0x1b9d,0xdfd,0xe05,0xe0d,0x103f,0x74d,0x559,0x559,
+0x1ba5,0x1ba5,0x755,0x559,0x1e60,0x10c9,0x1e58,0x10d1,0x1f4c,0x11cb,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0xe15,0x1fa4,0x12c4,0x1346,0x1347,0x1f6c,0x11f3,0x11fa,0x1201,0x1303,0x1307,0x127b,0x1211,
+0x1c21,0x1c23,0xe76,0xe7d,0x1bad,0x1bb5,0xe1d,0xf30,0x1d09,0xef8,0xf00,0xfdf,0x1d29,0x1d2d,0x1d35,0x105f,
+0xfaf,0x1d8b,0x75d,0x559,0x10b9,0x10c1,0x1d93,0xfb7,0xf91,0xf97,0xf9f,0xfa7,0x559,0x559,0x559,0x559,
+0x1ed0,0x1ec8,0x113b,0x1143,0x1e13,0x1e0b,0x1087,0x559,0x559,0x559,0x559,0x559,0x1dfb,0x1047,0x104f,0x1057,
+0x1dc3,0x1dbb,0xff7,0x1133,0x1d3d,0xf40,0x765,0x559,0x1097,0x109f,0x76d,0x559,0x559,0x559,0x559,0x559,
+0x1f44,0x11ad,0x775,0x559,0x559,0x1e23,0x1e1b,0x108f,0x1283,0x1289,0x1291,0x559,0x559,0x1219,0x121d,0x1225,
+0x1f04,0x1efc,0x1195,0x1ef4,0x1eec,0x1185,0x1df3,0x1037,0x1357,0x135a,0x135a,0x559,0x559,0x559,0x559,0x559,
+0x10e9,0x10ee,0x10f6,0x10fd,0x1125,0x112b,0x559,0x559,0x1169,0x116d,0x1175,0x11bd,0x11c3,0x77d,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x11db,0x136a,0x136f,0x1377,0x559,0x559,0x781,0x1f8c,0x126b,
+0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,
+0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a5f,0x1a64,0xcff,0xd06,0xd06,0xd06,
+0x1a6c,0x1a6c,0x1a6c,0xd0e,0x1e50,0x1e50,0x1e50,0x1e50,0x1e50,0x1e50,0x789,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x78d,0x1fbc,0x1fbc,0x12d4,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,
+0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0x1c2b,0xe85,0xfff,0x1007,0x1fc4,
+0x130f,0x1317,0xf48,0x1de3,0x1ddb,0x1027,0x102f,0x795,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1f64,0x1f5c,0x11eb,
+0x559,0x559,0x559,0x1d21,0x1d21,0xf20,0x1d19,0xf28,0x559,0x559,0x111d,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x799,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1d73,0x1d73,0x1d73,0xf6c,0xf71,
+0x7a1,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1fd4,0x1337,0x133e,0x1fcc,0x1fcc,0x1fcc,0x7a9,
+0x559,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0xb2b,0x184f,0xb33,0x1850,0x1847,0x1858,0x185e,0x1866,
+0xb3b,0x198e,0x198e,0x7b1,0x559,0x559,0x559,0x1362,0x11e3,0x197e,0x197e,0xc32,0xd16,0x559,0x559,0x559,
+0x559,0x1897,0x189e,0xb43,0x18a1,0xb4b,0xb53,0xb5b,0x189b,0xb63,0xb6b,0xb73,0x18a0,0x18a8,0x1897,0x189e,
+0x189a,0x18a1,0x18a9,0x1898,0x189f,0x189b,0xb7a,0x186e,0x1876,0x187d,0x1884,0x1871,0x1879,0x1880,0x1887,0xb82,
+0x188f,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,0x1e78,
+0x1e78,0x1e68,0x1e6b,0x1e68,0x1e72,0x10d9,0x7b9,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x12f0,0x12f8,0x12fb,0x12fb,0x12fb,0x12fb,0x12fb,
+0x12fb,0x110d,0x1115,0x1fdc,0x134f,0x7c1,0x559,0x559,0x559,0x1f84,0x122d,0x7c9,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x7cd,0x131f,0x1f94,0x1273,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x7d5,0x137f,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x12dc,0x1db3,0x1db3,0x1db3,0x1db3,0x1db3,0x1db3,0xfef,0x559,0x1ec0,0x1eb8,0x10e1,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x7dd,0x1f54,0x11d3,0x559,0x559,0x1235,0x1236,0x7e5,0x559,0x559,0x559,0x559,
+0x559,0xebd,0xec5,0xecd,0xed5,0xedd,0xee5,0xeec,0xef0,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x7e9,0x1067,0x1e03,0x106d,0x1e03,0x1075,0x107a,0x107f,
+0x107f,0x1e88,0x1ea8,0x1eb0,0x1f1c,0x1e90,0x1f74,0x1e98,0x1f24,0x1f7c,0x1f7c,0x119d,0x11a5,0x124d,0x1253,0x125b,
+0x1263,0x1f9c,0x1f9c,0x1f9c,0x1f9c,0x12a7,0x1f9c,0x12ad,0x12b1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,
+0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,
+0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f1,0x7f2,0xb8a,0x18b1,0x18b1,0x18b1,0x7fa,0x7fa,0x7fa,
+0x7fa,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x802,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,
+0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,
+0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,
+0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,
+0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0x7fa,0xbdd,0xbe4,0xbec,0xbf4,0x196e,0x196e,0x196e,
+0xbfc,0xc04,0xc07,0x199e,0x1996,0xc3a,0xd56,0xd5a,0xd5e,0x559,0x559,0x559,0x559,0xd66,0x1b19,0xd6e,
+0xf58,0x1822,0xb1d,0xb23,0x101f,0xc0f,0x19e2,0xca0,0x559,0x1837,0x182a,0x182f,0x1976,0xc17,0xc1f,0x114b,
+0x1151,0x1d7b,0xf79,0x1d6b,0xf50,0x1327,0x132f,0x559,0x559,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3,0x1da3,
+0x1da3,0x1da3,0xfc7,0xfcf,0xfd7,0x12e4,0x12e8,0x559,0x559,0x1b21,0xd7e,0x1b29,0x1b29,0xd82,0xe8d,0xe95,
+0xe9d,0x1bf1,0x1bd9,0x1bf9,0x1c01,0x1be9,0xe25,0xe29,0xe30,0xe38,0xe3c,0xe44,0xe4c,0xe4e,0xe4e,0xe4e,
+0xe4e,0x1c62,0x1c6a,0x1c62,0x1c70,0x1c78,0x1c43,0x1c80,0x1c88,0x1c62,0x1c90,0x1c98,0x1c9f,0x1ca7,0x1c4b,0x1c62,
+0x1cac,0x1c53,0x1c5a,0x1cb4,0x1cba,0x1d5c,0x1d63,0x1d55,0x1cc1,0x1cc9,0x1cd1,0x1cd9,0x1dd3,0x1ce1,0x1ce9,0xea5,
+0xead,0x1c33,0x1c33,0x1c33,0xeb5,0x1d83,0x1d83,0xf81,0xf89,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,
+0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e3b,0x1e40,0x1e3b,0x1e3b,0x1e3b,0x10a7,0x10a9,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1159,0x1c3b,0x1f14,0x1f14,0x1f14,0x1f14,0x1f14,0x1f14,
+0x1f14,0x1f34,0x1161,0x123e,0x1245,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,0x1f3c,
+0x117d,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,
+0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbf,0x1bbd,0x1bc7,0x1bbd,0x1bbd,
+0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bca,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1bd1,0x1209,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,
+0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,0x1ee0,
+0x1ee4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1fb4,0x1299,
+0x129f,0x12b9,0x12bc,0x12bc,0x12bc,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,
+0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x559,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18bc,
+0x1387,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x138f,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,
+0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x18c4,0x13b6,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1393,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x139b,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,
+0x1387,0x1387,0x1387,0x1387,0x1387,0x1387,0x1393,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x13be,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x1cf1,0x13c6,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x13ce,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,
+0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x13d6,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1741,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1749,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,0x1751,
+0x1751,0x1751,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,0x1759,
+0x1759,0x1759,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,0x18b9,
+0x18b9,0x18b9,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,0x1c09,
+0x1c09,0x1c09,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,0x1e80,
+0x1e80,0x1e80,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,0x1ed8,
+0x1ed8,0x1ed8,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,0x1f2c,
+0x1f2c,0x1f2c,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,
+0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,
+0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,
+0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,0x1fac,
+0x1fac,0x1fac,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,0x1fe4,
+0x1fe4,0x1fe4,0x538,0x538,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e5,0x2ee,0x2e8,
+0x2e8,0x2eb,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,
+0x2e2,0x2e2,0x2e2,0x2e2,0x7da,0x7d4,0x7b9,0x79e,0x7aa,0x7a7,0x79e,0x7b6,0x7a4,0x7b0,0x79e,0x7cb,
+0x7c2,0x7b3,0x7d7,0x7ad,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x79b,0x7bf,0x7bc,
+0x7c5,0x7c5,0x7c5,0x7d4,0x79e,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e6,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,
+0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7e0,0x7a4,
+0x7aa,0x7b0,0x7d1,0x798,0x7ce,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7e3,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,
+0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7dd,0x7a4,
+0x7c8,0x7a1,0x7c5,0x2e2,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2f1,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,
-0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,0x2e2,
-0x2e2,0x2e2,0x2e2,0x2e2,0x2e5,0x63c,0x7e0,0x7e3,0x642,0x7e3,0x7dd,0x636,0x62d,0x2eb,0x64b,0x2ee,
-0x7e6,0x624,0x639,0x7da,0x63f,0x648,0x62a,0x62a,0x630,0x2e8,0x636,0x633,0x62d,0x62a,0x64b,0x2ee,
-0x627,0x627,0x627,0x63c,0x2f7,0x2f7,0x2f7,0x2f7,0x2f7,0x2f7,0x654,0x2f7,0x2f7,0x2f7,0x2f7,0x2f7,
-0x2f7,0x2f7,0x2f7,0x2f7,0x654,0x2f7,0x2f7,0x2f7,0x2f7,0x2f7,0x2f7,0x645,0x654,0x2f7,0x2f7,0x2f7,
-0x2f7,0x2f7,0x654,0x64e,0x651,0x651,0x2f4,0x2f4,0x2f4,0x2f4,0x64e,0x2f4,0x651,0x651,0x651,0x2f4,
-0x651,0x651,0x2f4,0x2f4,0x64e,0x2f4,0x651,0x651,0x2f4,0x2f4,0x2f4,0x645,0x64e,0x651,0x651,0x2f4,
-0x651,0x2f4,0x64e,0x2f4,0x303,0x65a,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,
-0x303,0x2fa,0x303,0x2fa,0x300,0x657,0x303,0x65a,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x65a,
-0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x660,0x657,0x303,0x2fa,0x303,0x65a,
-0x303,0x2fa,0x303,0x2fa,0x303,0x657,0x663,0x65d,0x303,0x2fa,0x303,0x2fa,0x657,0x303,0x2fa,0x303,
-0x2fa,0x303,0x2fa,0x663,0x65d,0x660,0x657,0x303,0x65a,0x303,0x2fa,0x303,0x65a,0x666,0x660,0x657,
-0x303,0x65a,0x303,0x2fa,0x303,0x2fa,0x660,0x657,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,
-0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x660,0x657,0x303,0x2fa,0x303,0x65a,
-0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x2fa,0x303,0x303,0x2fa,0x303,
-0x2fa,0x303,0x2fa,0x2fd,0x306,0x312,0x312,0x306,0x312,0x306,0x312,0x312,0x306,0x312,0x312,0x312,
-0x306,0x306,0x312,0x312,0x312,0x312,0x306,0x312,0x312,0x306,0x312,0x312,0x312,0x306,0x306,0x306,
-0x312,0x312,0x306,0x312,0x315,0x309,0x312,0x306,0x312,0x306,0x312,0x312,0x306,0x312,0x306,0x306,
-0x312,0x306,0x312,0x315,0x309,0x312,0x312,0x312,0x306,0x312,0x306,0x312,0x312,0x306,0x306,0x30f,
-0x312,0x306,0x306,0x306,0x30f,0x30f,0x30f,0x30f,0x318,0x318,0x30c,0x318,0x318,0x30c,0x318,0x318,
-0x30c,0x315,0x669,0x315,0x669,0x315,0x669,0x315,0x669,0x315,0x669,0x315,0x669,0x315,0x669,0x315,
-0x669,0x306,0x315,0x309,0x315,0x309,0x315,0x309,0x312,0x306,0x315,0x309,0x315,0x309,0x315,0x309,
-0x315,0x309,0x315,0x309,0x309,0x318,0x318,0x30c,0x315,0x309,0x9bd,0x9bd,0x9c0,0x9ba,0x315,0x309,
-0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,
-0x315,0x309,0x315,0x309,0x315,0x309,0x315,0x309,0x9c0,0x9ba,0x9c0,0x9ba,0x9bd,0x9b7,0x9c0,0x9ba,
-0xb79,0xc72,0x9bd,0x9b7,0x9bd,0x9b7,0x9c0,0x9ba,0x9c0,0x9ba,0x9c0,0x9ba,0x9c0,0x9ba,0x9c0,0x9ba,
-0x9c0,0x9ba,0x9c0,0x9ba,0xc72,0xc72,0xc72,0xd6b,0xd6b,0xd6b,0xd6e,0xd6e,0xd6b,0xd6e,0xd6e,0xd6b,
-0xd6b,0xd6e,0xeac,0xeaf,0xeaf,0xeaf,0xeaf,0xeac,0xeaf,0xeac,0xeaf,0xeac,0xeaf,0xeac,0xeaf,0xeac,
-0x31b,0x66c,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,
-0x31b,0x66c,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,
-0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,
-0x31e,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,0x31b,
-0x31b,0x31b,0x31b,0x31b,0x31b,0x9c3,0x9c3,0x9c3,0x9c3,0x9c3,0xc75,0xc75,0x333,0x333,0x333,0x333,
-0x333,0x333,0x333,0x333,0x333,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x327,0x327,0x324,0x324,
-0x672,0x324,0x32a,0x675,0x32d,0x675,0x675,0x675,0x32d,0x675,0x32a,0x32a,0x678,0x330,0x324,0x324,
-0x324,0x324,0x324,0x324,0x66f,0x66f,0x66f,0x66f,0x321,0x66f,0x324,0xaef,0x333,0x333,0x333,0x333,
-0x333,0x324,0x324,0x324,0x324,0x324,0x9cc,0x9cc,0x9c9,0x9c6,0x9c9,0xc78,0xc78,0xc78,0xc78,0xc78,
-0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0xc78,0x67b,0x67b,0x67b,0x67b,
-0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,
-0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,
-0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,
-0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67b,0x67e,0x67e,0x91e,0x67e,
-0x67e,0x921,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xc2a,0xd35,0xd35,0xd35,0xd35,
-0xd35,0xd35,0xd35,0xd35,0xe70,0xe70,0xe70,0xe70,0xe73,0xd38,0xd38,0xd38,0x681,0x681,0xaf5,0xc6f,
-0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xf5a,0xf57,0xf5a,0xf57,
-0x33f,0x348,0xf5a,0xf57,9,9,0x34e,0xeb2,0xeb2,0xeb2,0x336,0x149d,9,9,9,9,
-0x34b,0x339,0x35d,0x33c,0x35d,0x35d,0x35d,9,0x35d,9,0x35d,0x35d,0x354,0x687,0x687,0x687,
-0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,0x687,9,0x687,
-0x687,0x687,0x687,0x687,0x687,0x687,0x35d,0x35d,0x354,0x354,0x354,0x354,0x354,0x684,0x684,0x684,
-0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x684,0x351,0x684,
-0x684,0x684,0x684,0x684,0x684,0x684,0x354,0x354,0x354,0x354,0x354,0xf5a,0x360,0x360,0x363,0x35d,
-0x35d,0x360,0x357,0x9cf,0xb82,0xb7f,0x35a,0x9cf,0x35a,0x9cf,0x35a,0x9cf,0x35a,0x9cf,0x345,0x342,
-0x345,0x342,0x345,0x342,0x345,0x342,0x345,0x342,0x345,0x342,0x345,0x342,0x360,0x360,0x357,0x351,
-0xb31,0xb2e,0xb7c,0xc7e,0xc7b,0xc81,0xc7e,0xc7b,0xd71,0xd74,0xd74,0xd74,0x9de,0x693,0x36f,0x372,
-0x36f,0x36f,0x36f,0x372,0x36f,0x36f,0x36f,0x36f,0x372,0x9de,0x372,0x36f,0x690,0x690,0x690,0x690,
-0x690,0x690,0x690,0x690,0x690,0x693,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,
-0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x690,0x68a,0x68a,0x68a,0x68a,
-0x68a,0x68a,0x68a,0x68a,0x68a,0x68d,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,
-0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x9d8,0x68d,0x369,0x36c,0x369,0x369,0x369,0x36c,
-0x369,0x369,0x369,0x369,0x36c,0x9d8,0x36c,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,
-0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x372,0x36c,
-0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x366,0x92a,0x92d,0x90f,0x90f,0x1101,
-0x9d2,0x9d2,0xb88,0xb85,0x9db,0x9d5,0x9db,0x9d5,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,
-0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,
-0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,
-0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x369,0x36f,0x372,0x36c,0x36f,0x369,0xb88,0xb85,0x36f,
-0x369,0xb88,0xb85,0x36f,0x369,0xb88,0xb85,0xeb5,0x372,0x36c,0x372,0x36c,0x36f,0x369,0x372,0x36c,
-0x36f,0x369,0x372,0x36c,0x372,0x36c,0x372,0x36c,0x36f,0x369,0x372,0x36c,0x372,0x36c,0x372,0x36c,
-0x36f,0x369,0x372,0x36c,0x9de,0x9d8,0x372,0x36c,0x372,0x36c,0x372,0x36c,0x372,0x36c,0xd7a,0xd77,
-0x372,0x36c,0xeb8,0xeb5,0xeb8,0xeb5,0xeb8,0xeb5,0xbee,0xbeb,0xbee,0xbeb,0xbee,0xbeb,0xbee,0xbeb,
-0xbee,0xbeb,0xbee,0xbeb,0xbee,0xbeb,0xbee,0xbeb,0xee5,0xee2,0xee5,0xee2,0xfd5,0xfd2,0xfd5,0xfd2,
-0xfd5,0xfd2,0xfd5,0xfd2,0xfd5,0xfd2,0xfd5,0xfd2,0xfd5,0xfd2,0xfd5,0xfd2,0x113a,0x1137,0x1317,0x1314,
-0x14d3,0x14d0,0x14d3,0x14d0,0x14d3,0x14d0,0x14d3,0x14d0,0xc,0x384,0x384,0x384,0x384,0x384,0x384,0x384,
-0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,0x384,
-0x384,0x384,0x384,0xc,0xc,0x387,0x375,0x375,0x375,0x37b,0x375,0x378,0x18d8,0x37e,0x37e,0x37e,
-0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,
-0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x37e,0x381,
-0x18d8,0x38a,0x9e1,0xc,0xc,0x14a0,0x14a0,0x13bc,0xf,0x951,0x951,0x951,0x951,0x951,0x951,0x951,
-0x951,0x951,0x951,0x951,0x951,0x951,0x951,0x951,0x951,0x951,0xd7d,0x951,0x951,0x951,0x951,0x951,
-0x951,0x951,0x951,0x951,0x951,0x951,0x951,0x951,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,
-0x38d,0x38d,0xebb,0x38d,0x38d,0x38d,0x399,0x38d,0x390,0x38d,0x38d,0x39c,0x954,0xd80,0xd83,0xd80,
-0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,
-0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,0x39f,
-0x39f,0x39f,0x39f,0xf,0xf,0xf,0xf,0x18db,0x39f,0x39f,0x39f,0x396,0x393,0xf,0xf,0xf,
-0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xc96,0xc96,0xc96,0xc96,0x13bf,0x14a3,0xf63,0xf63,
-0xf63,0xf60,0xf60,0xd89,0x897,0xc90,0xc8d,0xc8d,0xc84,0xc84,0xc84,0xc84,0xc84,0xc84,0xf5d,0xf5d,
-0xf5d,0xf5d,0xf5d,0x894,0x149a,0x1aeb,0xd8c,0x89a,0x12de,0x3ba,0x3bd,0x3bd,0x3bd,0x3bd,0x3bd,0x3ba,
-0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0xf66,0xf66,0xf66,0xf66,0xf66,0x89d,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x915,0x915,0x915,0x915,0x915,0x915,0x915,0x915,0xb28,0xb28,0xb28,0xc84,0xc8a,
-0xc87,0xd86,0xd86,0xd86,0xd86,0xd86,0xd86,0x12db,0x930,0x930,0x930,0x930,0x930,0x930,0x930,0x930,
-0x930,0x930,0x3b4,0x3b1,0x3ae,0x3ab,0xb8b,0xb8b,0x912,0x3ba,0x3ba,0x3c6,0x3ba,0x3c0,0x3c0,0x3c0,
-0x3c0,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x9e7,0x9e7,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x9e7,0x3bd,0x3ba,0x3bd,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,0x3ba,
-0x3ba,0x3ba,0x3ba,0x9e7,0x3ba,0x3ba,0x3ba,0x3bd,0x933,0x3ba,0x3a5,0x3a5,0x3a5,0x3a5,0x3a5,0x3a5,
-0x3a5,0x3a2,0x3ab,0x3a8,0x3a8,0x3a5,0x3a5,0x3a5,0x3a5,0x3c3,0x3c3,0x3a5,0x3a5,0x3ab,0x3a8,0x3a8,
-0x3a8,0x3a5,0xc93,0xc93,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x3b7,0x9e7,0x9e7,
-0x9e7,0x9e4,0x9e4,0xc93,0x9fc,0x9fc,0x9fc,0x9f6,0x9f6,0x9f6,0x9f6,0x9f6,0x9f6,0x9f6,0x9f6,0x9f3,
-0x9f6,0x9f3,0x12,0x9ff,0x9f9,0x9ea,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,
-0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,0x9f9,
-0x9f9,0xc99,0xc99,0xc99,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,0x9f0,
-0x9f0,0x9f0,0x9f0,0x9f0,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x9ed,0x12,
-0x12,0xc99,0xc99,0xc99,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,
-0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,
-0xde9,0xde9,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,0xfe7,
-0xfe7,0xfe7,0xfe7,0xfe7,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,
-0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,
-0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa05,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,
-0xa02,0xa02,0xa02,0xa02,0xa02,0xb8e,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-0x15,0x15,0x15,0x15,0xefd,0xefd,0xefd,0xefd,0xefd,0xefd,0xefd,0xefd,0xefd,0xefd,0xf00,0xf00,
-0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,
-0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xf00,0xef4,
-0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xef4,0xf03,0xf03,0xef7,0xef7,0xefa,0xf09,0xf06,0x102,
-0x102,0x18ff,0x1902,0x1902,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0xb01,0xb01,0xb04,0xb04,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,0xb01,
-0x6f,0x6f,0x6f,0x6f,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x1605,0x1605,0x1605,0x1605,0x1605,
-0x1605,0x1605,0x1605,0x1605,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x163e,0x163e,0x163e,
-0x163e,0x163e,0x163e,0x163e,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x16b,0x16b,0x16b,
+0,0,0,0,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x300,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,
+0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,0x2f1,
+0x2f1,0x2f1,0x2f1,0x2f1,0x2f4,0x64b,0x7ef,0x7f2,0x651,0x7f2,0x7ec,0x645,0x63c,0x2fa,0x65a,0x2fd,
+0x7f5,0x633,0x648,0x7e9,0x64e,0x657,0x639,0x639,0x63f,0x2f7,0x645,0x642,0x63c,0x639,0x65a,0x2fd,
+0x636,0x636,0x636,0x64b,0x306,0x306,0x306,0x306,0x306,0x306,0x663,0x306,0x306,0x306,0x306,0x306,
+0x306,0x306,0x306,0x306,0x663,0x306,0x306,0x306,0x306,0x306,0x306,0x654,0x663,0x306,0x306,0x306,
+0x306,0x306,0x663,0x65d,0x660,0x660,0x303,0x303,0x303,0x303,0x65d,0x303,0x660,0x660,0x660,0x303,
+0x660,0x660,0x303,0x303,0x65d,0x303,0x660,0x660,0x303,0x303,0x303,0x654,0x65d,0x660,0x660,0x303,
+0x660,0x303,0x65d,0x303,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,
+0x312,0x309,0x312,0x309,0x30f,0x666,0x312,0x669,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x669,
+0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x669,
+0x312,0x309,0x312,0x309,0x312,0x666,0x672,0x66c,0x312,0x309,0x312,0x309,0x666,0x312,0x309,0x312,
+0x309,0x312,0x309,0x672,0x66c,0x66f,0x666,0x312,0x669,0x312,0x309,0x312,0x669,0x675,0x66f,0x666,
+0x312,0x669,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,
+0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x66f,0x666,0x312,0x309,0x312,0x669,
+0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x309,0x312,0x312,0x309,0x312,
+0x309,0x312,0x309,0x30c,0x315,0x321,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x321,0x321,0x321,
+0x315,0x315,0x321,0x321,0x321,0x321,0x315,0x321,0x321,0x315,0x321,0x321,0x321,0x315,0x315,0x315,
+0x321,0x321,0x315,0x321,0x324,0x318,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x321,0x315,0x315,
+0x321,0x315,0x321,0x324,0x318,0x321,0x321,0x321,0x315,0x321,0x315,0x321,0x321,0x315,0x315,0x31e,
+0x321,0x315,0x315,0x315,0x31e,0x31e,0x31e,0x31e,0x327,0x327,0x31b,0x327,0x327,0x31b,0x327,0x327,
+0x31b,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,0x678,0x324,
+0x678,0x315,0x324,0x318,0x324,0x318,0x324,0x318,0x321,0x315,0x324,0x318,0x324,0x318,0x324,0x318,
+0x324,0x318,0x324,0x318,0x318,0x327,0x327,0x31b,0x324,0x318,0x9cf,0x9cf,0x9d2,0x9cc,0x324,0x318,
+0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,
+0x324,0x318,0x324,0x318,0x324,0x318,0x324,0x318,0x9d2,0x9cc,0x9d2,0x9cc,0x9cf,0x9c9,0x9d2,0x9cc,
+0xb8b,0xc84,0x9cf,0x9c9,0x9cf,0x9c9,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,0x9d2,0x9cc,
+0x9d2,0x9cc,0x9d2,0x9cc,0xc84,0xc84,0xc84,0xd7d,0xd7d,0xd7d,0xd80,0xd80,0xd7d,0xd80,0xd80,0xd7d,
+0xd7d,0xd80,0xebe,0xec1,0xec1,0xec1,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe,0xec1,0xebe,
+0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,
+0x32a,0x67b,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,
+0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,
+0x32d,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,0x32a,
+0x32a,0x32a,0x32a,0x32a,0x32a,0x9d5,0x9d5,0x9d5,0x9d5,0x9d5,0xc87,0xc87,0x342,0x342,0x342,0x342,
+0x342,0x342,0x342,0x342,0x342,0x339,0x339,0x339,0x339,0x339,0x339,0x339,0x336,0x336,0x333,0x333,
+0x681,0x333,0x339,0x684,0x33c,0x684,0x684,0x684,0x33c,0x684,0x339,0x339,0x687,0x33f,0x333,0x333,
+0x333,0x333,0x333,0x333,0x67e,0x67e,0x67e,0x67e,0x330,0x67e,0x333,0xb01,0x342,0x342,0x342,0x342,
+0x342,0x333,0x333,0x333,0x333,0x333,0x9de,0x9de,0x9db,0x9d8,0x9db,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,
+0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0xc8a,0x68a,0x68a,0x68a,0x68a,
+0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,
+0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,
+0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,
+0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68a,0x68d,0x68d,0x92d,0x68d,
+0x68d,0x930,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xb04,0xc3c,0xd47,0xd47,0xd47,0xd47,
+0xd47,0xd47,0xd47,0xd47,0xe82,0xe82,0xe82,0xe82,0xe85,0xd4a,0xd4a,0xd4a,0x690,0x690,0xb07,0xc81,
+0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xc81,0xf6c,0xf69,0xf6c,0xf69,
+0x34e,0x357,0xf6c,0xf69,9,9,0x35d,0xec4,0xec4,0xec4,0x345,0x14af,9,9,9,9,
+0x35a,0x348,0x36c,0x34b,0x36c,0x36c,0x36c,9,0x36c,9,0x36c,0x36c,0x363,0x696,0x696,0x696,
+0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,0x696,9,0x696,
+0x696,0x696,0x696,0x696,0x696,0x696,0x36c,0x36c,0x363,0x363,0x363,0x363,0x363,0x693,0x693,0x693,
+0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x693,0x360,0x693,
+0x693,0x693,0x693,0x693,0x693,0x693,0x363,0x363,0x363,0x363,0x363,0xf6c,0x36f,0x36f,0x372,0x36c,
+0x36c,0x36f,0x366,0x9e1,0xb94,0xb91,0x369,0x9e1,0x369,0x9e1,0x369,0x9e1,0x369,0x9e1,0x354,0x351,
+0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x354,0x351,0x36f,0x36f,0x366,0x360,
+0xb43,0xb40,0xb8e,0xc90,0xc8d,0xc93,0xc90,0xc8d,0xd83,0xd86,0xd86,0xd86,0x9f0,0x6a2,0x37e,0x381,
+0x37e,0x37e,0x37e,0x381,0x37e,0x37e,0x37e,0x37e,0x381,0x9f0,0x381,0x37e,0x69f,0x69f,0x69f,0x69f,
+0x69f,0x69f,0x69f,0x69f,0x69f,0x6a2,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,
+0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x69f,0x699,0x699,0x699,0x699,
+0x699,0x699,0x699,0x699,0x699,0x69c,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,
+0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x699,0x9ea,0x69c,0x378,0x37b,0x378,0x378,0x378,0x37b,
+0x378,0x378,0x378,0x378,0x37b,0x9ea,0x37b,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,
+0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x381,0x37b,
+0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x375,0x939,0x93c,0x91e,0x91e,0x1116,
+0x9e4,0x9e4,0xb9a,0xb97,0x9ed,0x9e7,0x9ed,0x9e7,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,
+0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,
+0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,
+0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x378,0x37e,0x381,0x37b,0x37e,0x378,0xb9a,0xb97,0x37e,
+0x378,0xb9a,0xb97,0x37e,0x378,0xb9a,0xb97,0xec7,0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b,
+0x37e,0x378,0x381,0x37b,0x381,0x37b,0x381,0x37b,0x37e,0x378,0x381,0x37b,0x381,0x37b,0x381,0x37b,
+0x37e,0x378,0x381,0x37b,0x9f0,0x9ea,0x381,0x37b,0x381,0x37b,0x381,0x37b,0x381,0x37b,0xd8c,0xd89,
+0x381,0x37b,0xeca,0xec7,0xeca,0xec7,0xeca,0xec7,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,
+0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xc00,0xbfd,0xef7,0xef4,0xef7,0xef4,0xfe7,0xfe4,0xfe7,0xfe4,
+0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0xfe7,0xfe4,0x114f,0x114c,0x1329,0x1326,
+0x14e5,0x14e2,0x14e5,0x14e2,0x14e5,0x14e2,0x14e5,0x14e2,0xc,0x393,0x393,0x393,0x393,0x393,0x393,0x393,
+0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,0x393,
+0x393,0x393,0x393,0xc,0xc,0x396,0x384,0x384,0x384,0x38a,0x384,0x387,0x18ea,0x38d,0x38d,0x38d,
+0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,
+0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x38d,0x390,
+0x18ea,0x399,0x9f3,0xc,0xc,0x14b2,0x14b2,0x13ce,0xf,0x960,0x960,0x960,0x960,0x960,0x960,0x960,
+0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0xd8f,0x960,0x960,0x960,0x960,0x960,
+0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x960,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,0x39c,
+0x39c,0x39c,0xecd,0x39c,0x39c,0x39c,0x3a8,0x39c,0x39f,0x39c,0x39c,0x3ab,0x963,0xd92,0xd95,0xd92,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,
+0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,0x3ae,
+0x3ae,0x3ae,0x3ae,0xf,0xf,0xf,0xf,0x18ed,0x3ae,0x3ae,0x3ae,0x3a5,0x3a2,0xf,0xf,0xf,
+0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xca8,0xca8,0xca8,0xca8,0x13d1,0x14b5,0xf75,0xf75,
+0xf75,0xf72,0xf72,0xd9b,0x8a6,0xca2,0xc9f,0xc9f,0xc96,0xc96,0xc96,0xc96,0xc96,0xc96,0xf6f,0xf6f,
+0xf6f,0xf6f,0xf6f,0x8a3,0x14ac,0x1afd,0xd9e,0x8a9,0x12f0,0x3c9,0x3cc,0x3cc,0x3cc,0x3cc,0x3cc,0x3c9,
+0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0xf78,0xf78,0xf78,0xf78,0xf78,0x8ac,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0x924,0xb3a,0xb3a,0xb3a,0xc96,0xc9c,
+0xc99,0xd98,0xd98,0xd98,0xd98,0xd98,0xd98,0x12ed,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,
+0x93f,0x93f,0x3c3,0x3c0,0x3bd,0x3ba,0xb9d,0xb9d,0x921,0x3c9,0x3c9,0x3d5,0x3c9,0x3cf,0x3cf,0x3cf,
+0x3cf,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x9f9,0x9f9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x9f9,0x3cc,0x3c9,0x3cc,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,0x3c9,
+0x3c9,0x3c9,0x3c9,0x9f9,0x3c9,0x3c9,0x3c9,0x3cc,0x942,0x3c9,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,0x3b4,
+0x3b4,0x3b1,0x3ba,0x3b7,0x3b7,0x3b4,0x3b4,0x3b4,0x3b4,0x3d2,0x3d2,0x3b4,0x3b4,0x3ba,0x3b7,0x3b7,
+0x3b7,0x3b4,0xca5,0xca5,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x3c6,0x9f9,0x9f9,
+0x9f9,0x9f6,0x9f6,0xca5,0xa0e,0xa0e,0xa0e,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa08,0xa05,
+0xa08,0xa05,0x12,0xa11,0xa0b,0x9fc,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,
+0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,0xa0b,
+0xa0b,0xcab,0xcab,0xcab,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,0xa02,
+0xa02,0xa02,0xa02,0xa02,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x9ff,0x12,
+0x12,0xcab,0xcab,0xcab,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,
+0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,0xdfb,
+0xdfb,0xdfb,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,0xff9,
+0xff9,0xff9,0xff9,0xff9,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
+0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
+0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa14,0xa14,0xa14,0xa14,0xa14,0xa14,
+0xa14,0xa14,0xa14,0xa14,0xa14,0xba0,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+0x15,0x15,0x15,0x15,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,0xf12,0xf12,
+0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,
+0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf06,
+0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf06,0xf15,0xf15,0xf09,0xf09,0xf0c,0xf1b,0xf18,0x102,
+0x102,0x1911,0x1914,0x1914,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xb13,0xb13,0xb16,0xb16,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,0xb13,
+0x6f,0x6f,0x6f,0x6f,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1e0,0x1617,0x1617,0x1617,0x1617,0x1617,
+0x1617,0x1617,0x1617,0x1617,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1650,0x1650,0x1650,
+0x1650,0x1650,0x1650,0x1650,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x16b,0x16b,0x16b,
0x16b,0x16b,0x16b,0x16b,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,
-0x1c5,0x1c5,0x1c5,0x1c5,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1476,0x1476,0x1476,0x1476,0x1476,0x1476,0x1476,0x1476,0x1476,0x1476,0x1aa,0x1aa,
-0x1aa,0x1aa,0x1aa,0x1aa,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,0x204,0x204,0x204,0x204,0x204,
-0x204,0x204,0x204,0x204,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,0x24c,
-0x24c,0x24c,0x24c,0x24c,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x194d,0x194d,0x194d,0x194d,0x194d,0x194d,0x194d,0x194d,0x194d,0x194d,0x252,0x252,
-0x252,0x252,0x252,0x252,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1aaf,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,
-0x28e,0x28e,0x28e,0x28e,0x1740,0x1740,0x1740,0x1740,0x20a,0x20a,0x20a,0x20a,0x20a,0x20a,0x20a,0x20a,
-0x20a,0x20a,0x20a,0x20a,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,
-0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,
-0x162c,0x162c,0x162c,0x162c,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x2a3,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,0x1bb1,
-0x2a3,0x1bb1,0x1bb1,0x2a3,0x16a4,0x16a4,0x16a4,0x16a4,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,
-0x1f2,0x1f2,0x1f2,0x1f2,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,
-0x2b8,0x2b8,0x2b8,0x2b8,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0xde0,0xde0,0xddd,0xddd,0xddd,0xde0,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,
+0,0,0,0,0x1bdb,0x1bd8,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,
+0x1c2,0x1c2,0x1c2,0x1c2,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1488,0x1a7,0x1a7,
+0x1a7,0x1a7,0x1a7,0x1a7,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x201,0x201,0x201,0x201,0x201,
+0x201,0x201,0x201,0x201,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,
+0x249,0x249,0x249,0x249,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x195f,0x24f,0x24f,
+0x24f,0x24f,0x24f,0x24f,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1ac1,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,
+0x28b,0x28b,0x28b,0x28b,0x1752,0x1752,0x1752,0x1752,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,
+0x207,0x207,0x207,0x207,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,
+0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,
+0x163e,0x163e,0x163e,0x163e,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x2a0,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3,0x1bc3,
+0x2a0,0x1bc3,0x1bc3,0x2a0,0x16b6,0x16b6,0x16b6,0x16b6,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,
+0x1ef,0x1ef,0x1ef,0x1ef,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,
+0x2b5,0x2b5,0x2b5,0x2b5,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0xdf2,0xdf2,0xdef,0xdef,0xdef,0xdf2,0xd5,0xd5,0xd5,0xd5,0xd5,0xd5,
0xd5,0xd5,0xd5,0xd5,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x216,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,
-0x1758,0x1758,0x1758,0x1758,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x17dc,0x17dc,0x222,0x17dc,0x17dc,0x222,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x222,
-0x222,0x222,0x222,0x222,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x1a01,0x273,0x273,
-0x273,0x273,0x1a04,0x19fe,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,
-0x1b81,0x1b81,0x1b81,0x1b81,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0,0,0x258,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,
-0x1962,0x1962,0x1962,0x1962,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,
-0x276,0x276,0x276,0x276,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x213,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,
+0x176a,0x176a,0x176a,0x176a,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
+0x2bb,0x2bb,0x2bb,0x1bf6,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x1a13,0x270,0x270,
+0x270,0x270,0x1a16,0x1a10,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,
+0x1b93,0x1b93,0x1b93,0x1b93,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,
+0x1c26,0x1c26,0x1c26,0x1c26,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0x255,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,
+0x1974,0x1974,0x1974,0x1974,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,0x273,
+0x273,0x273,0x273,0x273,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-0,0,0x94e,0x94e,3,3,3,3,3,3,3,3,3,3,3,3,
+0,0,0x95d,0x95d,3,3,3,3,3,3,3,3,3,3,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
-3,3,3,3,3,3,0x94e,0x94e,6,6,6,6,6,6,6,6,
+3,3,3,3,3,3,0x95d,0x95d,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,
-0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,6,6,6,6,6,6,6,6,
-6,6,6,6,6,6,6,6,0x14a9,0x3e1,0x3f0,0x3f0,0x18,0x3f6,0x3f6,0x3f6,
-0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x18,0x18,0x3f6,0x3f6,0x18,0x18,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,
-0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x18,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,0x3f6,
-0x3f6,0x18,0x3f6,0x18,0x18,0x18,0x3f6,0x3f6,0x3f6,0x3f6,0x18,0x18,0x3e4,0xc9f,0x3e1,0x3f0,
-0x3f0,0x3e1,0x3e1,0x3e1,0x3e1,0x18,0x18,0x3f0,0x3f0,0x18,0x18,0x3f3,0x3f3,0x3e7,0xd92,0x18,
-0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3e1,0x18,0x18,0x18,0x18,0x3f9,0x3f9,0x18,0x3f9,
-0x3f6,0x3f6,0x3e1,0x3e1,0x18,0x18,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,0x939,
-0x3f6,0x3f6,0x3ed,0x3ed,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ed,0x3ea,0x1110,0x1839,0x1836,0x18de,0x18,
-0x1b,0xca2,0x3fc,0xca5,0x1b,0x408,0x408,0x408,0x408,0x408,0x408,0x1b,0x1b,0x1b,0x1b,0x408,
-0x408,0x1b,0x1b,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x408,
-0x408,0x1b,0x408,0x408,0x408,0x408,0x408,0x408,0x408,0x1b,0x408,0x40b,0x1b,0x408,0x40b,0x1b,
-0x408,0x408,0x1b,0x1b,0x3ff,0x1b,0x405,0x405,0x405,0x3fc,0x3fc,0x1b,0x1b,0x1b,0x1b,0x3fc,
-0x3fc,0x1b,0x1b,0x3fc,0x3fc,0x402,0x1b,0x1b,0x1b,0xf6f,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
-0x1b,0x40b,0x40b,0x40b,0x408,0x1b,0x40b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x93c,0x93c,
-0x93c,0x93c,0x93c,0x93c,0x93c,0x93c,0x93c,0x93c,0x3fc,0x3fc,0x408,0x408,0x408,0xf6f,0x18e1,0x1b,
-0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1e,0x40e,0x40e,0x417,0x1e,0x41a,0x41a,0x41a,
-0x41a,0x41a,0x41a,0x41a,0xcae,0x41a,0x1e,0x41a,0x41a,0x41a,0x1e,0x41a,0x41a,0x41a,0x41a,0x41a,
-0x41a,0x41a,0x41a,0x41a,0x41a,0x41a,0x41a,0x41a,0x41a,0x1e,0x41a,0x41a,0x41a,0x41a,0x41a,0x41a,
-0x41a,0x1e,0x41a,0x41a,0x1e,0x41a,0x41a,0x41a,0x41a,0x41a,0x1e,0x1e,0x411,0x41a,0x417,0x417,
-0x417,0x40e,0x40e,0x40e,0x40e,0x40e,0x1e,0x40e,0x40e,0x417,0x1e,0x417,0x417,0x414,0x1e,0x1e,
-0x41a,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
-0x41a,0xcae,0xca8,0xca8,0x1e,0x1e,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,0x93f,
-0x13c2,0xcab,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x16b9,0x183c,0x183c,0x183c,0x183f,0x183f,0x183f,
-0x21,0x41d,0x42c,0x42c,0x21,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x21,0x21,0x432,
-0x432,0x21,0x21,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x432,
-0x432,0x21,0x432,0x432,0x432,0x432,0x432,0x432,0x432,0x21,0x432,0x432,0x21,0xcb1,0x432,0x432,
-0x432,0x432,0x21,0x21,0x420,0x432,0x41d,0x41d,0x42c,0x41d,0x41d,0x41d,0xf72,0x21,0x21,0x42c,
-0x42f,0x21,0x21,0x42f,0x42f,0x423,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x1a49,0x41d,0x41d,
-0x21,0x21,0x21,0x21,0x435,0x435,0x21,0x432,0x432,0x432,0xf72,0xf72,0x21,0x21,0x429,0x429,
-0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x426,0xcb1,0x12ea,0x12ea,0x12ea,0x12ea,0x12ea,0x12ea,
-0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x24,0x24,0x438,0x444,0x24,0x444,0x444,0x444,
-0x444,0x444,0x444,0x24,0x24,0x24,0x444,0x444,0x444,0x24,0x444,0x444,0x447,0x444,0x24,0x24,
-0x24,0x444,0x444,0x24,0x444,0x24,0x444,0x444,0x24,0x24,0x24,0x444,0x444,0x24,0x24,0x24,
-0x444,0x444,0x444,0x24,0x24,0x24,0x444,0x444,0x444,0x444,0x444,0x444,0x444,0x444,0xd95,0x444,
-0x444,0x444,0x24,0x24,0x24,0x24,0x438,0x43e,0x438,0x43e,0x43e,0x24,0x24,0x24,0x43e,0x43e,
-0x43e,0x24,0x441,0x441,0x441,0x43b,0x24,0x24,0xf75,0x24,0x24,0x24,0x24,0x24,0x24,0x438,
-0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0xea9,0x945,0x945,0x945,0x945,0x945,
-0x945,0x945,0x945,0x945,0x942,0x942,0x942,0xd65,0xcb4,0xcb4,0xcb4,0xcb4,0xcb4,0xcb7,0xcb4,0x24,
-0x24,0x24,0x24,0x24,0x14ac,0x456,0x456,0x456,0x18e4,0x459,0x459,0x459,0x459,0x459,0x459,0x459,
-0x459,0x27,0x459,0x459,0x459,0x27,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,
-0x459,0x459,0x459,0x459,0x459,0x27,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,0x459,
-0x14af,0x459,0x459,0x459,0x459,0x459,0x27,0x27,0x1aee,0xf7e,0x44a,0x44a,0x44a,0x456,0x456,0x456,
-0x456,0x27,0x44a,0x44a,0x44d,0x27,0x44a,0x44a,0x44a,0x450,0x27,0x27,0x27,0x27,0x27,0x27,
-0x27,0x44a,0x44a,0x27,0xf7e,0xf7e,0x16bc,0x27,0x27,0x1af1,0x27,0x27,0x459,0x459,0xf78,0xf78,
-0x27,0x27,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x27,0x27,0x27,0x27,
-0x27,0x27,0x27,0x19ad,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0xf7b,0x177c,0x14b2,0x462,0x462,
-0x18e7,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x2a,0x468,0x468,0x468,0x2a,0x468,0x468,
-0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x2a,0x468,0x468,
-0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x2a,0x468,0x468,0x468,0x468,0x468,0x2a,0x2a,
-0xcba,0xcbd,0x462,0x45c,0x465,0x462,0x45c,0x462,0x462,0x2a,0x45c,0x465,0x465,0x2a,0x465,0x465,
-0x45c,0x45f,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x45c,0x45c,0x2a,0x2a,0x2a,0x2a,0x2a,
-0x2a,0x1af4,0x468,0x2a,0x468,0x468,0xec1,0xec1,0x2a,0x2a,0x948,0x948,0x948,0x948,0x948,0x948,
-0x948,0x948,0x948,0x948,0x2a,0xec4,0xec4,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
-0x2a,0x2a,0x2a,0x2a,0x1842,0x14b5,0x474,0x474,0x1a4c,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,
-0x47a,0x2d,0x47a,0x47a,0x47a,0x2d,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,
-0x47a,0x47a,0x47a,0x47a,0x474,0x46b,0x46b,0x46b,0xf81,0x2d,0x474,0x474,0x474,0x2d,0x477,0x477,
-0x477,0x46e,0x12f0,0x177f,0x2d,0x2d,0x2d,0x2d,0x1782,0x1782,0x1782,0x46b,0x177f,0x177f,0x177f,0x177f,
-0x177f,0x177f,0x177f,0x16bf,0x47a,0x47a,0xf81,0xf81,0x2d,0x2d,0x471,0x471,0x471,0x471,0x471,0x471,
-0x471,0x471,0x471,0x471,0xf84,0xf84,0xf84,0xf84,0xf84,0xf84,0x177f,0x177f,0x177f,0xf87,0xf8a,0xf8a,
-0xf8a,0xf8a,0xf8a,0xf8a,0x30,0x1a4f,0xa11,0xa11,0x30,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
-0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0x30,0x30,0x30,0xa17,0xa17,
-0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,
-0xa17,0xa17,0x30,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0x30,0xa17,0x30,0x30,
-0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0xa17,0x30,0x30,0x30,0xa0b,0x30,0x30,0x30,0x30,0xa08,
-0xa11,0xa11,0xa08,0xa08,0xa08,0x30,0xa08,0x30,0xa11,0xa11,0xa14,0xa11,0xa14,0xa14,0xa14,0xa08,
-0x30,0x30,0x30,0x30,0x30,0x30,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,0x14b8,
-0x30,0x30,0xa11,0xa11,0xa0e,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
-0x33,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,
-0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,0x495,
-0x495,0x480,0x495,0x492,0x480,0x480,0x480,0x480,0x480,0x480,0x486,0x33,0x33,0x33,0x33,0x47d,
-0x49b,0x49b,0x49b,0x49b,0x49b,0x495,0x498,0x483,0x483,0x483,0x483,0x483,0x483,0x480,0x483,0x489,
-0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x48c,0x48c,0x33,0x33,0x33,0x33,
+6,6,6,6,6,6,6,6,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,
+0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,6,6,6,6,6,6,6,6,
+6,6,6,6,6,6,6,6,0x14bb,0x3f0,0x3ff,0x3ff,0x18,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x405,0x18,0x18,0x405,0x405,0x18,0x18,0x405,0x405,0x405,0x405,0x405,
+0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x405,0x18,0x405,0x405,0x405,0x405,0x405,0x405,
+0x405,0x18,0x405,0x18,0x18,0x18,0x405,0x405,0x405,0x405,0x18,0x18,0x3f3,0xcb1,0x3f0,0x3ff,
+0x3ff,0x3f0,0x3f0,0x3f0,0x3f0,0x18,0x18,0x3ff,0x3ff,0x18,0x18,0x402,0x402,0x3f6,0xda4,0x18,
+0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3f0,0x18,0x18,0x18,0x18,0x408,0x408,0x18,0x408,
+0x405,0x405,0x3f0,0x3f0,0x18,0x18,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,0x948,
+0x405,0x405,0x3fc,0x3fc,0x3f9,0x3f9,0x3f9,0x3f9,0x3f9,0x3fc,0x3f9,0x1125,0x184b,0x1848,0x18f0,0x18,
+0x1b,0xcb4,0x40b,0xcb7,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x1b,0x1b,0x1b,0x1b,0x417,
+0x417,0x1b,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x417,
+0x417,0x1b,0x417,0x417,0x417,0x417,0x417,0x417,0x417,0x1b,0x417,0x41a,0x1b,0x417,0x41a,0x1b,
+0x417,0x417,0x1b,0x1b,0x40e,0x1b,0x414,0x414,0x414,0x40b,0x40b,0x1b,0x1b,0x1b,0x1b,0x40b,
+0x40b,0x1b,0x1b,0x40b,0x40b,0x411,0x1b,0x1b,0x1b,0xf81,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,
+0x1b,0x41a,0x41a,0x41a,0x417,0x1b,0x41a,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x94b,0x94b,
+0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x94b,0x40b,0x40b,0x417,0x417,0x417,0xf81,0x18f3,0x1b,
+0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1b,0x1e,0x41d,0x41d,0x426,0x1e,0x429,0x429,0x429,
+0x429,0x429,0x429,0x429,0xcc0,0x429,0x1e,0x429,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,
+0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,0x429,
+0x429,0x1e,0x429,0x429,0x1e,0x429,0x429,0x429,0x429,0x429,0x1e,0x1e,0x420,0x429,0x426,0x426,
+0x426,0x41d,0x41d,0x41d,0x41d,0x41d,0x1e,0x41d,0x41d,0x426,0x1e,0x426,0x426,0x423,0x1e,0x1e,
+0x429,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
+0x429,0xcc0,0xcba,0xcba,0x1e,0x1e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,0x94e,
+0x13d4,0xcbd,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x16cb,0x184e,0x184e,0x184e,0x1851,0x1851,0x1851,
+0x21,0x42c,0x43b,0x43b,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x21,0x21,0x441,
+0x441,0x21,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x441,
+0x441,0x21,0x441,0x441,0x441,0x441,0x441,0x441,0x441,0x21,0x441,0x441,0x21,0xcc3,0x441,0x441,
+0x441,0x441,0x21,0x21,0x42f,0x441,0x42c,0x42c,0x43b,0x42c,0x42c,0x42c,0xf84,0x21,0x21,0x43b,
+0x43e,0x21,0x21,0x43e,0x43e,0x432,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x1a5b,0x42c,0x42c,
+0x21,0x21,0x21,0x21,0x444,0x444,0x21,0x441,0x441,0x441,0xf84,0xf84,0x21,0x21,0x438,0x438,
+0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x438,0x435,0xcc3,0x12fc,0x12fc,0x12fc,0x12fc,0x12fc,0x12fc,
+0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x24,0x24,0x447,0x453,0x24,0x453,0x453,0x453,
+0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x24,0x453,0x453,0x456,0x453,0x24,0x24,
+0x24,0x453,0x453,0x24,0x453,0x24,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x24,0x24,0x24,
+0x453,0x453,0x453,0x24,0x24,0x24,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0x453,0xda7,0x453,
+0x453,0x453,0x24,0x24,0x24,0x24,0x447,0x44d,0x447,0x44d,0x44d,0x24,0x24,0x24,0x44d,0x44d,
+0x44d,0x24,0x450,0x450,0x450,0x44a,0x24,0x24,0xf87,0x24,0x24,0x24,0x24,0x24,0x24,0x447,
+0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0xebb,0x954,0x954,0x954,0x954,0x954,
+0x954,0x954,0x954,0x954,0x951,0x951,0x951,0xd77,0xcc6,0xcc6,0xcc6,0xcc6,0xcc6,0xcc9,0xcc6,0x24,
+0x24,0x24,0x24,0x24,0x14be,0x465,0x465,0x465,0x18f6,0x468,0x468,0x468,0x468,0x468,0x468,0x468,
+0x468,0x27,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,
+0x468,0x468,0x468,0x468,0x468,0x27,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,0x468,
+0x14c1,0x468,0x468,0x468,0x468,0x468,0x27,0x27,0x1b00,0xf90,0x459,0x459,0x459,0x465,0x465,0x465,
+0x465,0x27,0x459,0x459,0x45c,0x27,0x459,0x459,0x459,0x45f,0x27,0x27,0x27,0x27,0x27,0x27,
+0x27,0x459,0x459,0x27,0xf90,0xf90,0x16ce,0x27,0x27,0x1b03,0x27,0x27,0x468,0x468,0xf8a,0xf8a,
+0x27,0x27,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x462,0x27,0x27,0x27,0x27,
+0x27,0x27,0x27,0x19bf,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0xf8d,0x178e,0x14c4,0x471,0x471,
+0x18f9,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,0x477,0x2a,0x477,0x477,
+0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,
+0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x477,0x2a,0x477,0x477,0x477,0x477,0x477,0x2a,0x2a,
+0xccc,0xccf,0x471,0x46b,0x474,0x471,0x46b,0x471,0x471,0x2a,0x46b,0x474,0x474,0x2a,0x474,0x474,
+0x46b,0x46e,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x46b,0x46b,0x2a,0x2a,0x2a,0x2a,0x2a,
+0x2a,0x1b06,0x477,0x2a,0x477,0x477,0xed3,0xed3,0x2a,0x2a,0x957,0x957,0x957,0x957,0x957,0x957,
+0x957,0x957,0x957,0x957,0x2a,0xed6,0xed6,0x1bc9,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,0x2a,
+0x2a,0x2a,0x2a,0x2a,0x1854,0x14c7,0x483,0x483,0x1a5e,0x489,0x489,0x489,0x489,0x489,0x489,0x489,
+0x489,0x2d,0x489,0x489,0x489,0x2d,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,
+0x489,0x489,0x489,0x489,0x483,0x47a,0x47a,0x47a,0xf93,0x2d,0x483,0x483,0x483,0x2d,0x486,0x486,
+0x486,0x47d,0x1302,0x1791,0x2d,0x2d,0x2d,0x2d,0x1794,0x1794,0x1794,0x47a,0x1791,0x1791,0x1791,0x1791,
+0x1791,0x1791,0x1791,0x16d1,0x489,0x489,0xf93,0xf93,0x2d,0x2d,0x480,0x480,0x480,0x480,0x480,0x480,
+0x480,0x480,0x480,0x480,0xf96,0xf96,0xf96,0xf96,0xf96,0xf96,0x1791,0x1791,0x1791,0xf99,0xf9c,0xf9c,
+0xf9c,0xf9c,0xf9c,0xf9c,0x30,0x1a61,0xa23,0xa23,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,
+0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0x30,0x30,0xa29,0xa29,
+0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,
+0xa29,0xa29,0x30,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0xa29,0x30,0x30,
+0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0xa29,0x30,0x30,0x30,0xa1d,0x30,0x30,0x30,0x30,0xa1a,
+0xa23,0xa23,0xa1a,0xa1a,0xa1a,0x30,0xa1a,0x30,0xa23,0xa23,0xa26,0xa23,0xa26,0xa26,0xa26,0xa1a,
+0x30,0x30,0x30,0x30,0x30,0x30,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,
+0x30,0x30,0xa23,0xa23,0xa20,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
+0x33,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,
+0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,
+0x4a4,0x48f,0x4a4,0x4a1,0x48f,0x48f,0x48f,0x48f,0x48f,0x48f,0x495,0x33,0x33,0x33,0x33,0x48c,
+0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x4a4,0x4a7,0x492,0x492,0x492,0x492,0x492,0x492,0x48f,0x492,0x498,
+0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x49b,0x49b,0x33,0x33,0x33,0x33,
0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
-0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x4aa,0x4aa,0x36,
-0x4aa,0x36,0x19b3,0x4aa,0x4aa,0x19b3,0x4aa,0x36,0x19b3,0x4aa,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,
-0x4aa,0x4aa,0x4aa,0x4aa,0x19b3,0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x4aa,0x19b3,0x4aa,0x4aa,0x4aa,
-0x36,0x4aa,0x36,0x4aa,0x19b3,0x19b3,0x4aa,0x4aa,0x19b3,0x4aa,0x4aa,0x4aa,0x4aa,0x49e,0x4aa,0x4a7,
-0x49e,0x49e,0x49e,0x49e,0x49e,0x49e,0x19b0,0x49e,0x49e,0x4aa,0x36,0x36,0x4b3,0x4b3,0x4b3,0x4b3,
-0x4b3,0x36,0x4b0,0x36,0x4a1,0x4a1,0x4a1,0x4a1,0x4a1,0x49e,0x36,0x36,0x4a4,0x4a4,0x4a4,0x4a4,
-0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x4a4,0x36,0x36,0x4ad,0x4ad,0x13c5,0x13c5,0x36,0x36,0x36,0x36,
+0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x4b9,0x4b9,0x36,
+0x4b9,0x36,0x19c5,0x4b9,0x4b9,0x19c5,0x4b9,0x36,0x19c5,0x4b9,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,0x19c5,
+0x4b9,0x4b9,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9,
+0x36,0x4b9,0x36,0x4b9,0x19c5,0x19c5,0x4b9,0x4b9,0x19c5,0x4b9,0x4b9,0x4b9,0x4b9,0x4ad,0x4b9,0x4b6,
+0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x4ad,0x19c2,0x4ad,0x4ad,0x4b9,0x36,0x36,0x4c2,0x4c2,0x4c2,0x4c2,
+0x4c2,0x36,0x4bf,0x36,0x4b0,0x4b0,0x4b0,0x4b0,0x4b0,0x4ad,0x1bcc,0x36,0x4b3,0x4b3,0x4b3,0x4b3,
+0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x4b3,0x36,0x36,0x4bc,0x4bc,0x13d7,0x13d7,0x36,0x36,0x36,0x36,
0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x98a,0x98a,0x98a,0x98d,
-0x98a,0x98a,0x98a,0x98a,0x39,0x98a,0x98a,0x98a,0x98a,0x98d,0x98a,0x98a,0x98a,0x98a,0x98d,0x98a,
-0x98a,0x98a,0x98a,0x98d,0x98a,0x98a,0x98a,0x98a,0x98d,0x98a,0x98a,0x98a,0x98a,0x98a,0x98a,0x98a,
-0x98a,0x98a,0x98a,0x98a,0x98a,0x98d,0xa26,0xf96,0xf96,0x39,0x39,0x39,0x39,0x957,0x957,0x95a,
-0x957,0x95a,0x95a,0x963,0x95a,0x963,0x957,0x957,0x957,0x957,0x957,0x984,0x957,0x95a,0x95d,0x95d,
-0x960,0x969,0x95d,0x95d,0x98a,0x98a,0x98a,0x98a,0x12f9,0x12f3,0x12f3,0x12f3,0x957,0x957,0x957,0x95a,
-0x957,0x957,0xa1a,0x957,0x39,0x957,0x957,0x957,0x957,0x95a,0x957,0x957,0x957,0x957,0x95a,0x957,
-0x957,0x957,0x957,0x95a,0x957,0x957,0x957,0x957,0x95a,0x957,0xa1a,0xa1a,0xa1a,0x957,0x957,0x957,
-0x957,0x957,0x957,0x957,0xa1a,0x95a,0xa1a,0xa1a,0xa1a,0x39,0xa23,0xa23,0xa20,0xa20,0xa20,0xa20,
-0xa20,0xa20,0xa1d,0xa20,0xa20,0xa20,0xa20,0xa20,0xa20,0x39,0xf8d,0xa20,0xd98,0xd98,0xf90,0xf93,
-0xf8d,0x1113,0x1113,0x1113,0x1113,0x12f6,0x12f6,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,
+0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x99c,0x99c,0x99c,0x99f,
+0x99c,0x99c,0x99c,0x99c,0x39,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,
+0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99f,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,
+0x99c,0x99c,0x99c,0x99c,0x99c,0x99f,0xa38,0xfa8,0xfa8,0x39,0x39,0x39,0x39,0x966,0x966,0x969,
+0x966,0x969,0x969,0x975,0x969,0x975,0x966,0x966,0x966,0x966,0x966,0x996,0x966,0x969,0x96f,0x96f,
+0x972,0x97b,0x96c,0x96c,0x99c,0x99c,0x99c,0x99c,0x130b,0x1305,0x1305,0x1305,0x966,0x966,0x966,0x969,
+0x966,0x966,0xa2c,0x966,0x39,0x966,0x966,0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966,
+0x966,0x966,0x966,0x969,0x966,0x966,0x966,0x966,0x969,0x966,0xa2c,0xa2c,0xa2c,0x966,0x966,0x966,
+0x966,0x966,0x966,0x966,0xa2c,0x969,0xa2c,0xa2c,0xa2c,0x39,0xa35,0xa35,0xa32,0xa32,0xa32,0xa32,
+0xa32,0xa32,0xa2f,0xa32,0xa32,0xa32,0xa32,0xa32,0xa32,0x39,0xf9f,0xa32,0xdaa,0xdaa,0xfa2,0xfa5,
+0xf9f,0x1128,0x1128,0x1128,0x1128,0x1308,0x1308,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,
0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,
-0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x3c,0x13cb,
-0x3c,0x3c,0x3c,0x3c,0x3c,0x13cb,0x3c,0x3c,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,
-0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,
-0xa50,0x3f,0xa50,0xa50,0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0x3f,
-0xa50,0x3f,0xa50,0xa50,0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,
-0xa50,0x3f,0xa50,0xa50,0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,0xa50,0x3f,0xa50,0xa50,
-0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0x3f,0xa50,0x3f,0xa50,0xa50,
-0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0x3f,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xda7,0xa50,0x3f,0xa50,0xa50,0xa50,0xa50,0x3f,0x3f,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xda7,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0x3f,0x3f,0x12fc,0x12fc,0xda1,0xda4,0xa4a,0xa53,0xa47,
-0xa47,0xa47,0xa47,0xa53,0xa53,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa44,0xa44,
-0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0xa44,0x3f,0x3f,0x3f,0xa56,0xa56,0xa56,0xa56,
-0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,
-0xa56,0x16c5,0x42,0x42,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x16c2,0x42,0x42,0xa68,0xa6b,0xa6b,0xa6b,
-0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,
-0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa6b,0xa65,0xa62,0x45,0x45,0x45,0xa71,0xa71,0xa71,0xa71,
-0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa6e,0xa6e,0xa6e,0xa71,0xa71,0xa71,0x14bb,0x14bb,0x14bb,
-0x14bb,0x14bb,0x14bb,0x14bb,0x14bb,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0xa92,0xa92,0xa92,0xa92,
-0xa92,0xa92,0xa74,0xa92,0xa92,0xa77,0xa77,0xa77,0xa77,0xa77,0xa77,0xa77,0xa77,0xa77,0xa7a,0xa77,
-0xa89,0xa89,0xa8c,0xa95,0xa83,0xa80,0xa89,0xa86,0xa95,0xcc0,0x4b,0x4b,0xa8f,0xa8f,0xa8f,0xa8f,
-0xa8f,0xa8f,0xa8f,0xa8f,0xa8f,0xa8f,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xcc3,0xcc3,0xcc3,0xcc3,
-0xcc3,0xcc3,0xcc3,0xcc3,0xcc3,0xcc3,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xaa4,0xaa4,0xb1c,0xb1f,
-0xaaa,0xb19,0xaa7,0xaa4,0xaad,0xabc,0xab0,0xabf,0xabf,0xabf,0xa9b,0x1af7,0xab3,0xab3,0xab3,0xab3,
-0xab3,0xab3,0xab3,0xab3,0xab3,0xab3,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0x18ea,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xa9e,0xfb4,0x4e,0x4e,0x4e,0x4e,0x4e,0x116a,0x116a,0x116a,0x116a,
-0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x51,0x51,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x51,0x51,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x51,0x4da,0x51,0x4da,0x51,0x4da,0x51,0x4da,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x4d7,0x51,0x51,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x51,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d1,0x4d7,0x4d1,0x4d1,0x4ce,0x4d7,0x4d7,
-0x4d7,0x51,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4ce,0x4ce,0x4ce,0x4d7,0x4d7,0x4d7,0x4d7,
-0x51,0x51,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x51,0x4ce,0x4ce,0x4ce,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4ce,0x4ce,0x4ce,0x51,0x51,0x4d7,0x4d7,
-0x4d7,0x51,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d4,0x4d1,0x51,0xb94,0xb97,0xb97,0xb97,
-0xfbd,0x54,0x1497,0x1497,0x1497,0x1497,0x4e3,0x4e3,0x4e3,0x4e3,0x4e3,0x4e3,0x52e,0xba9,0x57,0x57,
-0x6c9,0x52e,0x52e,0x52e,0x52e,0x52e,0x534,0x546,0x534,0x540,0x53a,0x6cc,0x52b,0x6c6,0x6c6,0x6c6,
-0x6c6,0x52b,0x52b,0x52b,0x52b,0x52b,0x531,0x543,0x531,0x53d,0x537,0x57,0xdb0,0xdb0,0xdb0,0xdb0,
-0xdb0,0x12ff,0x12ff,0x12ff,0x12ff,0x12ff,0x12ff,0x12ff,0x12ff,0x57,0x57,0x57,0x1afa,0x5a,0x5a,0x5a,
-0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x555,0x555,0x555,0x555,
-0x555,0x555,0x555,0x555,0x555,0x555,0x555,0x555,0x555,0x552,0x552,0x552,0x552,0x555,0xacb,0xacb,
-0xbaf,0xbb5,0xbb5,0xbb2,0xbb2,0xbb2,0xbb2,0xdb6,0xec7,0xec7,0xec7,0xec7,0x10fe,0x5d,0x5d,0x5d,
-0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x585,0x585,0x585,0xad4,
-0xed0,0xfc3,0xfc3,0xfc3,0xfc3,0x125d,0x16cb,0x16cb,0x60,0x60,0x60,0x60,0x6f3,0x6f3,0x6f3,0x6f3,
-0x6f3,0x6f3,0x6f3,0x6f3,0x6f3,0x6f3,0x591,0x591,0x58e,0x58e,0x58e,0x58e,0x5b2,0x5b2,0x5b2,0x5b2,
-0x5b2,0xadd,0xadd,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,
-0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x5b5,0x5b5,0x5b5,0x5b5,
-0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
-0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0xaf8,0xaf8,0xaf8,0xaf8,
-0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,
-0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0x69,0xaf8,0xaf8,0xaf8,0xaf8,0xafb,0xaf8,0xaf8,0xaf8,0xaf8,
-0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xafb,
-0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0xafe,0xafe,0xafe,0xafe,
-0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,
-0xafe,0xafe,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x72,0x813,0x80d,0x813,
-0x80d,0x813,0x80d,0x813,0x80d,0x813,0x80d,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,
-0x810,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,0x80d,0x80d,0x80d,0x813,
-0x80d,0x813,0x80d,0x813,0x80d,0x80d,0x80d,0x80d,0x80d,0x80d,0x813,0x80d,0x80d,0x80d,0x80d,0x80d,
-0x810,0xc4e,0xc4e,0x72,0x72,0x927,0x927,0x8ee,0x8ee,0x816,0x819,0xc4b,0x75,0x75,0x75,0x75,
-0x75,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,
-0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x10ec,0x18b1,0x1998,
-0x78,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
-0x82e,0x82e,0x82e,0x78,0x8f7,0x8f7,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,0x8fa,
-0x8fa,0x8fa,0x8fa,0x8fa,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,
-0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,0x837,
-0x837,0xd4a,0xd4a,0x7b,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
-0xb10,0x7e,0x7e,0x7e,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,
-0xb16,0xb16,0xb16,0xb16,0xb16,0xc57,0xb16,0xb16,0xb16,0xc57,0xb16,0x81,0x81,0x81,0x81,0x81,
-0x81,0x81,0x81,0x81,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,
-0x1191,0x1191,0x1191,0x1191,0x9ae,0x9ae,0x9ae,0x9ae,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
-0x84,0x84,0x84,0x84,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,
-0x1206,0x1206,0x1206,0x1206,0x5fa,0x5fa,0x5fa,0x5fa,0x5fa,0x5fa,0x5fa,0x87,0x87,0x87,0x87,0x87,
-0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x87,0x87,0x87,0x87,
-0x87,0xae9,0x5eb,0x5f1,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x5ee,0x5f1,0x5f1,
-0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x87,0x5f1,0x5f1,0x5f1,0x5f1,
-0x5f1,0x87,0x5f1,0x87,0x5f1,0x5f1,0x87,0x5f1,0x5f1,0x87,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,0x5f1,
-0x5f1,0x5f1,0x5f1,0x5f4,0x606,0x600,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,
-0x603,0x609,0x606,0x600,0x1311,0x1311,0x1afd,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,
-0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x606,0x600,0x603,0x609,0x606,0x600,0x606,0x600,0x606,
-0x600,0x606,0x606,0x600,0x600,0x600,0x600,0x603,0x600,0x600,0x603,0x600,0x603,0x603,0x603,0x600,
-0x603,0x603,0x603,0x603,0x8a,0x8a,0x603,0x603,0x603,0x603,0x600,0x600,0x603,0x600,0x600,0x600,
-0x600,0x603,0x600,0x600,0x600,0x600,0x600,0x603,0x603,0x603,0x600,0x600,0x8a,0x8a,0x8a,0x8a,
-0x8a,0x8a,0x8a,0x1afd,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,
-0xb34,0xb34,0xb34,0xb34,0x84f,0x861,0x85e,0x861,0x85e,0xc6c,0xc6c,0xd56,0xd53,0x852,0x852,0x852,
-0x852,0x864,0x864,0x864,0x87c,0x87f,0x88e,0x8d,0x882,0x885,0x891,0x891,0x879,0x870,0x86a,0x870,
-0x86a,0x870,0x86a,0x86d,0x86d,0x888,0x888,0x88b,0x888,0x888,0x888,0x8d,0x888,0x876,0x873,0x86d,
-0x8d,0x8d,0x8d,0x8d,0x612,0x61e,0x612,0xbe8,0x612,0x90,0x612,0x61e,0x612,0x61e,0x612,0x61e,
-0x612,0x61e,0x612,0x61e,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,
-0x61e,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x61b,
-0x615,0x90,0x90,0x60f,0x750,0x753,0x768,0x76b,0x74a,0x753,0x753,0x96,0x732,0x735,0x735,0x735,
-0x735,0x732,0x732,0x96,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0xaec,0xaec,0xaec,
-0x9b1,0x72c,0x621,0x621,0x96,0x77a,0x759,0x74a,0x753,0x750,0x74a,0x75c,0x74d,0x747,0x74a,0x768,
-0x75f,0x756,0x777,0x74a,0x774,0x774,0x774,0x774,0x774,0x774,0x774,0x774,0x774,0x774,0x765,0x762,
-0x768,0x768,0x768,0x77a,0x73b,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,
-0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,
-0x738,0x738,0x738,0x96,0x96,0x96,0x738,0x738,0x738,0x738,0x738,0x738,0x96,0x96,0x738,0x738,
-0x738,0x738,0x738,0x738,0x96,0x96,0x738,0x738,0x738,0x738,0x738,0x738,0x96,0x96,0x738,0x738,
-0x738,0x96,0x96,0x96,0xb37,0xb37,0xb37,0xb37,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
-0x99,0x184e,0x184e,0x184e,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,
-0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0x9c,0x9c,0x9c,0x9c,0x9c,0x1614,0x1614,0x1614,0x1614,
-0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0xb46,0xb46,0xb46,0xb46,
-0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,
-0xb46,0xb46,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xa2,0xa2,0xfcf,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0x16d1,0x16d1,0x16d1,0x16d1,
-0x16d1,0x16d1,0x16d1,0x16d1,0x16d1,0x1b00,0x1b00,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,
-0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xa5,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xa5,0xb6a,0xb6a,0xa5,0xa5,0xb6a,0xa5,
-0xa5,0xb6a,0xb6a,0xa5,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb67,0xa5,0xb67,0xa5,0xb67,0xb67,0xb67,0xb67,0xcde,0xb67,0xb67,
-0xa5,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb67,
-0xb6a,0xb6a,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xa5,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xa5,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xa5,0xb6a,0xa5,0xa5,0xa5,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xa5,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xdc8,0xdc8,0xa5,0xa5,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb61,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xedf,0xedc,0xa5,0xa5,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
-0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xa8,0xb70,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,
+0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x3c,0x13dd,
+0x3c,0x3c,0x3c,0x3c,0x3c,0x13dd,0x3c,0x3c,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,
+0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,
+0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,
+0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,
+0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0x3f,0xa62,0xa62,
+0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0xa62,0x3f,0xa62,0xa62,
+0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xdb9,0xa62,0x3f,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0x3f,0x3f,0x130e,0x130e,0xdb3,0xdb6,0xa5c,0xa65,0xa59,
+0xa59,0xa59,0xa59,0xa65,0xa65,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa5f,0xa56,0xa56,
+0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0x3f,0x3f,0x3f,0xa68,0xa68,0xa68,0xa68,
+0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,
+0xa68,0x16d7,0x42,0x42,0x16d4,0x16d4,0x16d4,0x16d4,0x16d4,0x16d4,0x42,0x42,0xa7a,0xa7d,0xa7d,0xa7d,
+0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,
+0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa7d,0xa77,0xa74,0x45,0x45,0x45,0xa83,0xa83,0xa83,0xa83,
+0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa80,0xa80,0xa80,0xa83,0xa83,0xa83,0x14cd,0x14cd,0x14cd,
+0x14cd,0x14cd,0x14cd,0x14cd,0x14cd,0x48,0x48,0x48,0x48,0x48,0x48,0x48,0xaa4,0xaa4,0xaa4,0xaa4,
+0xaa4,0xaa4,0xa86,0xaa4,0xaa4,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa89,0xa8c,0xa89,
+0xa9b,0xa9b,0xa9e,0xaa7,0xa95,0xa92,0xa9b,0xa98,0xaa7,0xcd2,0x4b,0x4b,0xaa1,0xaa1,0xaa1,0xaa1,
+0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0xaa1,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xcd5,0xcd5,0xcd5,0xcd5,
+0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0xab6,0xab6,0xb2e,0xb31,
+0xabc,0xb2b,0xab9,0xab6,0xabf,0xace,0xac2,0xad1,0xad1,0xad1,0xaad,0x1b09,0xac5,0xac5,0xac5,0xac5,
+0xac5,0xac5,0xac5,0xac5,0xac5,0xac5,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0x18fc,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0x4e,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xab0,0xfc6,0x4e,0x4e,0x4e,0x4e,0x4e,0x117f,0x117f,0x117f,0x117f,
+0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x51,0x51,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x51,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9,0x51,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x51,0x51,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e0,0x4e6,0x4e0,0x4e0,0x4dd,0x4e6,0x4e6,
+0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd,0x4e6,0x4e6,0x4e6,0x4e6,
+0x51,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x51,0x4dd,0x4dd,0x4dd,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e6,0x4e6,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4dd,0x4dd,0x4dd,0x51,0x51,0x4e6,0x4e6,
+0x4e6,0x51,0x4e6,0x4e6,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e3,0x4e0,0x51,0xba6,0xba9,0xba9,0xba9,
+0xfcf,0x54,0x14a9,0x14a9,0x14a9,0x14a9,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x4f2,0x53d,0xbbb,0x57,0x57,
+0x6d8,0x53d,0x53d,0x53d,0x53d,0x53d,0x543,0x555,0x543,0x54f,0x549,0x6db,0x53a,0x6d5,0x6d5,0x6d5,
+0x6d5,0x53a,0x53a,0x53a,0x53a,0x53a,0x540,0x552,0x540,0x54c,0x546,0x57,0xdc2,0xdc2,0xdc2,0xdc2,
+0xdc2,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x57,0x57,0x57,0x1b0c,0x5a,0x5a,0x5a,
+0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x5a,0x564,0x564,0x564,0x564,
+0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x564,0x561,0x561,0x561,0x561,0x564,0xadd,0xadd,
+0xbc1,0xbc7,0xbc7,0xbc4,0xbc4,0xbc4,0xbc4,0xdc8,0xed9,0xed9,0xed9,0xed9,0x1113,0x5d,0x5d,0x5d,
+0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x5d,0x594,0x594,0x594,0xae6,
+0xee2,0xfd5,0xfd5,0xfd5,0xfd5,0x126f,0x16dd,0x16dd,0x60,0x60,0x60,0x60,0x702,0x702,0x702,0x702,
+0x702,0x702,0x702,0x702,0x702,0x702,0x5a0,0x5a0,0x59d,0x59d,0x59d,0x59d,0x5c1,0x5c1,0x5c1,0x5c1,
+0x5c1,0xaef,0xaef,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,
+0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x5c4,0x5c4,0x5c4,0x5c4,
+0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
+0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0xb0a,0xb0a,0xb0a,0xb0a,
+0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,
+0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0x69,0xb0a,0xb0a,0xb0a,0xb0a,0xb0d,0xb0a,0xb0a,0xb0a,0xb0a,
+0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0d,
+0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0x69,0xb10,0xb10,0xb10,0xb10,
+0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
+0xb10,0xb10,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x72,0x822,0x81c,0x822,
+0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,
+0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81c,0x81c,0x81c,0x822,
+0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c,
+0x81f,0xc60,0xc60,0x72,0x72,0x936,0x936,0x8fd,0x8fd,0x825,0x828,0xc5d,0x75,0x75,0x75,0x75,
+0x75,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,
+0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x1101,0x18c3,0x19aa,
+0x78,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,
+0x83d,0x83d,0x83d,0x78,0x906,0x906,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,0x909,
+0x909,0x909,0x909,0x909,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,
+0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,
+0x846,0xd5c,0xd5c,0x7b,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,
+0xb22,0x7e,0x7e,0x7e,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,
+0xb28,0xb28,0xb28,0xb28,0xb28,0xc69,0xb28,0xb28,0xb28,0xc69,0xb28,0x81,0x81,0x81,0x81,0x81,
+0x81,0x81,0x81,0x81,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,
+0x11a6,0x11a6,0x11a6,0x11a6,0x9c0,0x9c0,0x9c0,0x9c0,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,
+0x84,0x84,0x84,0x84,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,
+0x121b,0x121b,0x121b,0x121b,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x87,0x87,0x87,0x87,0x87,
+0x87,0x87,0x87,0x87,0x87,0x87,0x87,0x5f7,0x5f7,0x5f7,0x5f7,0x5f7,0x87,0x87,0x87,0x87,
+0x87,0xafb,0x5fa,0x600,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x5fd,0x600,0x600,
+0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x87,0x600,0x600,0x600,0x600,
+0x600,0x87,0x600,0x87,0x600,0x600,0x87,0x600,0x600,0x87,0x600,0x600,0x600,0x600,0x600,0x600,
+0x600,0x600,0x600,0x603,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,
+0x612,0x618,0x615,0x60f,0x1323,0x1323,0x1b0f,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,
+0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x8a,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,
+0x60f,0x615,0x615,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x612,0x612,0x60f,
+0x612,0x612,0x612,0x612,0x8a,0x8a,0x612,0x612,0x612,0x612,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,
+0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x60f,0x60f,0x8a,0x8a,0x8a,0x8a,
+0x8a,0x8a,0x8a,0x1b0f,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,
+0xb46,0xb46,0xb46,0xb46,0x85e,0x870,0x86d,0x870,0x86d,0xc7e,0xc7e,0xd68,0xd65,0x861,0x861,0x861,
+0x861,0x873,0x873,0x873,0x88b,0x88e,0x89d,0x8d,0x891,0x894,0x8a0,0x8a0,0x888,0x87f,0x879,0x87f,
+0x879,0x87f,0x879,0x87c,0x87c,0x897,0x897,0x89a,0x897,0x897,0x897,0x8d,0x897,0x885,0x882,0x87c,
+0x8d,0x8d,0x8d,0x8d,0x621,0x62d,0x621,0xbfa,0x621,0x90,0x621,0x62d,0x621,0x62d,0x621,0x62d,
+0x621,0x62d,0x621,0x62d,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,
+0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,
+0x624,0x90,0x90,0x61e,0x75f,0x762,0x777,0x77a,0x759,0x762,0x762,0x96,0x741,0x744,0x744,0x744,
+0x744,0x741,0x741,0x96,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0x93,0xafe,0xafe,0xafe,
+0x9c3,0x73b,0x630,0x630,0x96,0x789,0x768,0x759,0x762,0x75f,0x759,0x76b,0x75c,0x756,0x759,0x777,
+0x76e,0x765,0x786,0x759,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x783,0x774,0x771,
+0x777,0x777,0x777,0x789,0x74a,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,
+0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,0x747,
+0x747,0x747,0x747,0x96,0x96,0x96,0x747,0x747,0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747,
+0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747,0x747,0x747,0x747,0x747,0x96,0x96,0x747,0x747,
+0x747,0x96,0x96,0x96,0xb49,0xb49,0xb49,0xb49,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
+0x99,0x1860,0x1860,0x1860,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,
+0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0xb4f,0x9c,0x9c,0x9c,0x9c,0x9c,0x1626,0x1626,0x1626,0x1626,
+0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0xb58,0xb58,0xb58,0xb58,
+0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,
+0xb58,0xb58,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0x9f,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xa2,0xa2,0xfe1,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0x16e3,0x16e3,0x16e3,0x16e3,
+0x16e3,0x16e3,0x16e3,0x16e3,0x16e3,0x1b12,0x1b12,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,
+0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xa2,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xa5,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xa5,
+0xa5,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xa5,0xb79,0xa5,0xb79,0xb79,0xb79,0xb79,0xcf0,0xb79,0xb79,
+0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,
+0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xa5,0xb7c,0xa5,0xa5,0xa5,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xa5,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xdda,0xdda,0xa5,0xa5,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xef1,0xeee,0xa5,0xa5,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,
+0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xa8,0xb82,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,
0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,
-0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,
-0xbf7,0xbf7,0xbf7,0xbf7,0xbf7,0x1b06,0xbf7,0xbf7,0xbf7,0xbf7,0xbf1,0xbf1,0xbf4,0x1b03,0xab,0xab,
-0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x1b06,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,
-0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xc00,0xbfa,0xbfa,0xbfd,0xc60,0xc60,0xae,
-0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,
-0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc06,0xc03,0xc03,0xb1,0xb1,0xb1,0xb1,
-0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,
-0xc0c,0xc0c,0xc0c,0xc0c,0xc0c,0xb4,0xc0c,0xc0c,0xc0c,0xb4,0xc09,0xc09,0xb4,0xb4,0xb4,0xb4,
-0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,
-0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,
-0xcf0,0xcf0,0xcf0,0xcf0,0xcf0,0x14d6,0x14d6,0xb7,0xce1,0xce1,0xce1,0xced,0xced,0xced,0xced,0xce1,
-0xce1,0xced,0xced,0xced,0xb7,0xb7,0xb7,0xb7,0xced,0xced,0xce1,0xced,0xced,0xced,0xced,0xced,
-0xced,0xce4,0xce4,0xce4,0xb7,0xb7,0xb7,0xb7,0xce7,0xb7,0xb7,0xb7,0xcf3,0xcf3,0xcea,0xcea,
-0xcea,0xcea,0xcea,0xcea,0xcea,0xcea,0xcea,0xcea,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,
-0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xcf6,0xba,0xba,0xcf6,0xcf6,0xcf6,0xcf6,
-0xcf6,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,
-0xbd,0xbd,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0xbd,0x1a52,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,
-0xc0,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,
-0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xc0,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,
-0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xc0,0xd1a,0xd1a,0xc0,0xd1a,
-0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xc0,0xc0,
-0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xc0,0xc0,
+0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xa8,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,0xc09,
+0xc09,0xc09,0xc09,0xc09,0xc09,0x1b18,0xc09,0xc09,0xc09,0xc09,0xc03,0xc03,0xc06,0x1b15,0xab,0xab,
+0xab,0xab,0xab,0xab,0xab,0xab,0xab,0x1b18,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,
+0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc0c,0xc0c,0xc0f,0xc72,0xc72,0xae,
+0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xae,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,
+0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc15,0xc15,0xb1,0xb1,0xb1,0xb1,
+0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,
+0xc1e,0xc1e,0xc1e,0xc1e,0xc1e,0xb4,0xc1e,0xc1e,0xc1e,0xb4,0xc1b,0xc1b,0xb4,0xb4,0xb4,0xb4,
+0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xb4,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,
+0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,0xd02,
+0xd02,0xd02,0xd02,0xd02,0xd02,0x14e8,0x14e8,0xb7,0xcf3,0xcf3,0xcf3,0xcff,0xcff,0xcff,0xcff,0xcf3,
+0xcf3,0xcff,0xcff,0xcff,0xb7,0xb7,0xb7,0xb7,0xcff,0xcff,0xcf3,0xcff,0xcff,0xcff,0xcff,0xcff,
+0xcff,0xcf6,0xcf6,0xcf6,0xb7,0xb7,0xb7,0xb7,0xcf9,0xb7,0xb7,0xb7,0xd05,0xd05,0xcfc,0xcfc,
+0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xcfc,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,
+0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xba,0xba,0xd08,0xd08,0xd08,0xd08,
+0xd08,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0xba,0x14eb,0x14eb,0x14eb,0x14eb,
+0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,
+0xbd,0xbd,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,
+0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0xbd,0x1a64,0x14eb,0x14eb,0x14eb,0x14eb,
+0x14eb,0x14eb,0x14eb,0x14eb,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,
+0xc0,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,
+0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,
+0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xd2c,0xd2c,0xc0,0xd2c,
+0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xc0,
+0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xc0,0xc0,
0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
-0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,
-0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xc3,0xc3,0xc3,0xc3,0xc3,
-0xd5c,0xd5c,0xd62,0xc6,0xc6,0xc6,0xc6,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,
-0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,0xd59,
-0xc6,0xc6,0xc6,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd5f,0xd23,0xd23,0xd23,0xd23,
-0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,
-0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xc9,0xd20,0xd2c,0xd2c,0xd2c,0xd2c,
-0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,
-0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xd2c,0xcc,0xcc,0xd29,0xd29,0xd29,0xd29,
-0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x1812,0x1812,0x1812,0x1812,
-0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0xd2f,0xd2f,0xd2f,0xd2f,
-0xd2f,0xd2f,0xcf,0xcf,0xd2f,0xcf,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
-0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xcf,0xd2f,
-0xd2f,0xcf,0xcf,0xcf,0xd2f,0xcf,0xcf,0xd2f,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,
-0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd2,
-0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,
-0xde3,0xde3,0xde3,0x14dc,0x14dc,0x1788,0x1788,0xd8,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,
-0x10cb,0x10cb,0x10cb,0x10cb,0x1a61,0x129,0x129,0x129,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,
-0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdec,
-0xdec,0xdf2,0xdf2,0xdec,0xdb,0xdb,0xdef,0xdef,0x10fb,0x10fb,0x10fb,0x10fb,0xde,0xde,0xde,0xde,
-0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,
-0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xc5d,0xe07,0xe04,0xe07,0xe04,0xe04,0xdfb,0xdfb,0xdfb,
-0xdfb,0xdfb,0xdfb,0x1146,0x1143,0x1146,0x1143,0x1140,0x1140,0x1140,0x13d4,0x13d1,0xe1,0xe1,0xe1,0xe1,
-0xe1,0xe01,0xdfe,0xdfe,0xdfe,0xdfb,0xe01,0xdfe,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,
-0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe4,
-0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe4,
-0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe4,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe4,
-0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe0a,0xe4,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,
-0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0xe10,0xe0d,0xe0d,0xe0d,0xe0d,0xe0d,0xe0d,0xe0d,0xe0d,
-0xe0d,0xe0d,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xea,0x13d7,
-0xea,0xea,0xea,0xea,0xea,0x13d7,0xea,0xea,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,
-0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe2b,0xe1f,0xe1f,0xe1f,0xed,0xe1f,0xe1f,0xed,
-0xed,0xed,0xed,0xed,0xe1f,0xe1f,0xe1f,0xe1f,0xe2b,0xe2b,0xe2b,0xe2b,0xed,0xe2b,0xe2b,0xe2b,
-0xed,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,
-0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0x18f3,0x18f3,0xed,0xed,0xe1c,0xe1c,0xe1c,0xed,
-0xed,0xed,0xed,0xe22,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0x18f0,0xed,0xed,0xed,
-0xed,0xed,0xed,0xed,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe2e,0xe2e,0xe25,0xed,0xed,0xed,
-0xed,0xed,0xed,0xed,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0x114c,0x114c,
-0xf0,0xf0,0xf0,0xf0,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3d,0xe3d,0xe3d,0xe3a,0xe3a,0xe3d,0xe3a,
-0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
-0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0x1149,0xf0,0xf0,0xf0,0xe34,0xe34,
-0xe43,0xe43,0xe43,0xe43,0xf3,0xf3,0xf3,0xf3,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,
-0xe40,0xe43,0xe43,0xe43,0xe43,0xe43,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,
-0x14eb,0x14f1,0x14ee,0x1833,0x178e,0x1857,0x1857,0x1857,0x1857,0x1857,0x18f9,0x18f6,0x18fc,0x18f6,0x18fc,0x19b9,
-0x1a55,0x1a55,0x1a55,0x1b18,0x1b18,0x1b12,0x1b0f,0x1b12,0x1b0f,0x1b12,0x1b0f,0x1b12,0x1b0f,0x1b15,0xf6,0xf6,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xc3,0xc3,0xc3,0xc3,0xc3,
+0xd6e,0xd6e,0xd74,0xc6,0xc6,0xc6,0xc6,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,
+0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,0xd6b,
+0xc6,0xc6,0xc6,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd71,0xd35,0xd35,0xd35,0xd35,
+0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,
+0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xd35,0xc9,0xd32,0xd3e,0xd3e,0xd3e,0xd3e,
+0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,
+0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xcc,0xcc,0xd3b,0xd3b,0xd3b,0xd3b,
+0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xd3b,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x1824,0x1824,0x1824,0x1824,
+0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0xd41,0xd41,0xd41,0xd41,
+0xd41,0xd41,0xcf,0xcf,0xd41,0xcf,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,
+0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xd41,0xcf,0xd41,
+0xd41,0xcf,0xcf,0xcf,0xd41,0xcf,0xcf,0xd41,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,
+0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd2,
+0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xd2,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,
+0xdf5,0xdf5,0xdf5,0x14ee,0x14ee,0x179a,0x179a,0xd8,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,
+0x10e0,0x10e0,0x10e0,0x10e0,0x1a73,0x129,0x129,0x129,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,
+0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xe07,0xdfe,
+0xdfe,0xe04,0xe04,0xdfe,0xdb,0xdb,0xe01,0xe01,0x1110,0x1110,0x1110,0x1110,0xde,0xde,0xde,0xde,
+0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xde,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,
+0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xc6f,0xe19,0xe16,0xe19,0xe16,0xe16,0xe0d,0xe0d,0xe0d,
+0xe0d,0xe0d,0xe0d,0x115b,0x1158,0x115b,0x1158,0x1155,0x1155,0x1155,0x13e6,0x13e3,0xe1,0xe1,0xe1,0xe1,
+0xe1,0xe13,0xe10,0xe10,0xe10,0xe0d,0xe13,0xe10,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,
+0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,
+0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,
+0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,
+0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe1c,0xe4,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,
+0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe22,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,0xe1f,
+0xe1f,0xe1f,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xea,0x13e9,
+0xea,0xea,0xea,0xea,0xea,0x13e9,0xea,0xea,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,
+0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe3d,0xe31,0xe31,0xe31,0xed,0xe31,0xe31,0xed,
+0xed,0xed,0xed,0xed,0xe31,0xe31,0xe31,0xe31,0xe3d,0xe3d,0xe3d,0xe3d,0xed,0xe3d,0xe3d,0xe3d,
+0xed,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,
+0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0xe3d,0x1905,0x1905,0xed,0xed,0xe2e,0xe2e,0xe2e,0xed,
+0xed,0xed,0xed,0xe34,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0xe37,0x1902,0xed,0xed,0xed,
+0xed,0xed,0xed,0xed,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe40,0xe40,0xe37,0xed,0xed,0xed,
+0xed,0xed,0xed,0xed,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0x1161,0x1161,
+0xf0,0xf0,0xf0,0xf0,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4f,0xe4f,0xe4f,0xe4c,0xe4c,0xe4f,0xe4c,
+0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0x115e,0xf0,0xf0,0xf0,0xe46,0xe46,
+0xe55,0xe55,0xe55,0xe55,0xf3,0xf3,0xf3,0xf3,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,
+0xe52,0xe55,0xe55,0xe55,0xe55,0xe55,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,0xf3,
+0x14fd,0x1503,0x1500,0x1845,0x17a0,0x1869,0x1869,0x1869,0x1869,0x1869,0x190b,0x1908,0x190e,0x1908,0x190e,0x19cb,
+0x1a67,0x1a67,0x1a67,0x1b2a,0x1b2a,0x1b24,0x1b21,0x1b24,0x1b21,0x1b24,0x1b21,0x1b24,0x1b21,0x1b27,0xf6,0xf6,
0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,
0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,0xf6,
-0xe67,0xe67,0xe67,0xe64,0xe64,0xe5b,0xe5b,0xe64,0xe61,0xe61,0xe61,0xe61,0x1a58,0xf9,0xf9,0xf9,
-0x12ba,0x12ba,0x12ba,0x12bd,0x12bd,0x12bd,0x12b4,0x12b4,0x12b7,0x12b4,0x14d,0x14d,0x14d,0x14d,0x14d,0x14d,
-0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0x13e3,0x13e3,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xe6d,
-0x1323,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0x1320,
-0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,0xc30,
-0xe9a,0xe8b,0xe85,0xe97,0xe94,0xe8e,0xe8e,0xe9d,0xe88,0xe91,0xff,0xff,0xff,0xff,0xff,0xff,
-0xf21,0xf21,0xf0c,0xf21,0xf24,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0x1b1b,0x105,0x105,0x105,
-0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf1b,0xf2d,0xf2d,0xf12,0xf18,0xf2d,0xf2d,
-0xf15,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf0f,0xf0f,0xf0f,0xf0f,0xf0f,
-0xf0f,0xf0f,0xf0f,0xf0f,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0xf12,0x1b1e,0x1b1e,0x105,
-0x1b27,0x1b21,0x19bf,0x19bc,0x19bf,0x19bf,0x19bf,0x1a5e,0x1a5b,0x1a5e,0x1a5b,0x108,0x108,0x108,0x108,0x108,
-0x1b27,0x1b21,0x108,0x1b21,0x108,0x1b21,0x1b27,0x1b21,0x1b27,0x1b21,0x108,0x108,0x108,0x108,0x108,0x108,
-0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x1b24,0x1b24,
-0x1b24,0x1a5e,0x1a5b,0x14fa,0x13ec,0x13ec,0x1326,0x1026,0x1026,0x1026,0x1026,0x1026,0xf3c,0xf3c,0xf3c,0xf3c,
-0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,
-0xf39,0xf39,0xf3f,0xf3f,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0xf48,0xf48,0xf48,0xf48,
-0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,0xf48,
-0xf48,0xf48,0xf42,0xf42,0xf42,0xf42,0x1155,0x1155,0x10e,0x10e,0x10e,0xf45,0x1500,0x1500,0x1500,0x1500,
-0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,
-0x1500,0x1500,0x1500,0x1500,0x1500,0x16e0,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,
+0xe79,0xe79,0xe79,0xe76,0xe76,0xe6d,0xe6d,0xe76,0xe73,0xe73,0xe73,0xe73,0x1a6a,0xf9,0xf9,0xf9,
+0x12cc,0x12cc,0x12cc,0x12cf,0x12cf,0x12cf,0x12c6,0x12c6,0x12c9,0x12c6,0x14d,0x14d,0x14d,0x14d,0x14d,0x14d,
+0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0x13f5,0x13f5,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xe7f,
+0x1335,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0xfc,0x1332,
+0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,0xc42,
+0xeac,0xe9d,0xe97,0xea9,0xea6,0xea0,0xea0,0xeaf,0xe9a,0xea3,0xff,0xff,0xff,0xff,0xff,0xff,
+0xf33,0xf33,0xf1e,0xf33,0xf36,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0x1b2d,0x105,0x105,0x105,
+0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf2d,0xf3f,0xf3f,0xf24,0xf2a,0xf3f,0xf3f,
+0xf27,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf21,0xf21,0xf21,0xf21,0xf21,
+0xf21,0xf21,0xf21,0xf21,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0xf24,0x1b30,0x1b30,0x105,
+0x1b39,0x1b33,0x19d1,0x19ce,0x19d1,0x19d1,0x19d1,0x1a70,0x1a6d,0x1a70,0x1a6d,0x108,0x108,0x108,0x108,0x108,
+0x1b39,0x1b33,0x108,0x1b33,0x108,0x1b33,0x1b39,0x1b33,0x1b39,0x1b33,0x108,0x108,0x108,0x108,0x108,0x108,
+0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x108,0x1b36,0x1b36,
+0x1b36,0x1a70,0x1a6d,0x150c,0x13fe,0x13fe,0x1338,0x103b,0x103b,0x103b,0x103b,0x103b,0xf4e,0xf4e,0xf4e,0xf4e,
+0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,
+0xf4b,0xf4b,0xf51,0xf51,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0x10b,0xf5a,0xf5a,0xf5a,0xf5a,
+0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,0xf5a,
+0xf5a,0xf5a,0xf54,0xf54,0xf54,0xf54,0x116a,0x116a,0x10e,0x10e,0x10e,0xf57,0x1512,0x1512,0x1512,0x1512,
+0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,
+0x1512,0x1512,0x1512,0x1512,0x1512,0x16f2,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,
0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,
-0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0xf51,0xf51,0xf51,0x1506,0x1506,0x1506,0x1506,0x1506,
-0x1506,0x1506,0x1506,0x1506,0x1506,0x1506,0x1506,0x114,0xf4e,0xf4e,0xf4e,0xf4e,0x1503,0x114,0x114,0x114,
-0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,
-0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0xf54,0x190b,0x190b,0x190b,0x190b,0x190b,0x190b,
-0x190b,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x104d,0x104d,0x104d,0x104d,0x104a,0x104a,0x104a,0x104a,
-0x104a,0x104a,0x104a,0x104a,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x103b,0x104a,0x104a,0x1041,0x103e,
-0x11a,0x11a,0x11a,0x1050,0x1050,0x1044,0x1044,0x1044,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047,0x1047,
-0x1047,0x1047,0x11a,0x11a,0x11a,0x104d,0x104d,0x104d,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053,0x1053,
-0x1053,0x1053,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,
-0x1068,0x1068,0x106b,0x106b,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,
-0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x1092,0x1092,0x1092,0x1092,0x108c,0x1794,0x120,0x120,
-0x120,0x120,0x120,0x120,0x120,0x120,0x1098,0x1098,0x108f,0x108f,0x108f,0x108f,0x108f,0x108f,0x108f,0x108f,
-0x108f,0x108f,0x120,0x120,0x120,0x120,0x120,0x120,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10aa,
-0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10b0,0x10b3,0x123,0x123,0x123,0x123,
-0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x10ad,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,
-0x10c5,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10c2,0x10c2,0x10b9,0x10b9,0x10c2,0x10c2,0x10b9,0x10b9,0x126,
-0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x10c5,0x10c5,0x10c5,0x10b9,0x10c5,0x10c5,0x10c5,0x10c5,
-0x10c5,0x10c5,0x10c5,0x10c5,0x10b9,0x10c2,0x126,0x126,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,
-0x10bf,0x10bf,0x126,0x126,0x10bc,0x10c8,0x10c8,0x10c8,0x1512,0x129,0x129,0x129,0x129,0x129,0x129,0x129,
+0x111,0x111,0x111,0x111,0x111,0x111,0x111,0x111,0xf63,0xf63,0xf63,0x1518,0x1518,0x1518,0x1518,0x1518,
+0x1518,0x1518,0x1518,0x1518,0x1518,0x1518,0x1518,0x114,0xf60,0xf60,0xf60,0xf60,0x1515,0x114,0x114,0x114,
+0x114,0x114,0x114,0x114,0x114,0x114,0x114,0x114,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,
+0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0xf66,0x191d,0x191d,0x191d,0x191d,0x191d,0x191d,
+0x191d,0x117,0x117,0x117,0x117,0x117,0x117,0x117,0x1062,0x1062,0x1062,0x1062,0x105f,0x105f,0x105f,0x105f,
+0x105f,0x105f,0x105f,0x105f,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x1050,0x105f,0x105f,0x1056,0x1053,
+0x11a,0x11a,0x11a,0x1065,0x1065,0x1059,0x1059,0x1059,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,0x105c,
+0x105c,0x105c,0x11a,0x11a,0x11a,0x1062,0x1062,0x1062,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,0x1068,
+0x1068,0x1068,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d,0x107d,
+0x107d,0x107d,0x1080,0x1080,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,
+0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x11d,0x10a7,0x10a7,0x10a7,0x10a7,0x10a1,0x17a6,0x120,0x120,
+0x120,0x120,0x120,0x120,0x120,0x120,0x10ad,0x10ad,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,
+0x10a4,0x10a4,0x120,0x120,0x120,0x120,0x120,0x120,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10bf,
+0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10bf,0x10c5,0x10c8,0x123,0x123,0x123,0x123,
+0x123,0x123,0x123,0x123,0x123,0x123,0x123,0x10c2,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,
+0x10da,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10d7,0x10d7,0x10ce,0x10ce,0x10d7,0x10d7,0x10ce,0x10ce,0x126,
+0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x126,0x10da,0x10da,0x10da,0x10ce,0x10da,0x10da,0x10da,0x10da,
+0x10da,0x10da,0x10da,0x10da,0x10ce,0x10d7,0x126,0x126,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,
+0x10d4,0x10d4,0x126,0x126,0x10d1,0x10dd,0x10dd,0x10dd,0x1524,0x129,0x129,0x129,0x129,0x129,0x129,0x129,
0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,
-0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,
-0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,
-0x10ce,0x10ce,0x10ce,0x10ce,0x10ce,0x10d1,0x12c,0x12c,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,
-0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,
-0x10d4,0x10d4,0x10d4,0x10d4,0x10d4,0x12f,0x12f,0x12f,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,
-0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x132,0x132,0x132,0x132,0x132,0x132,0x132,
-0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,
-0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,0x10dd,
-0x10dd,0x10dd,0x135,0x135,0x135,0x135,0x135,0x10da,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,
-0x10e0,0x10e0,0x10e0,0x10e0,0x138,0x138,0x138,0x138,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
-0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x13b,0x13b,0x13b,0x13b,
-0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x115b,0x115b,0x115b,0x115b,0x1164,0x115b,0x115b,0x115b,
-0x1164,0x115b,0x115b,0x115b,0x115b,0x1158,0x13e,0x13e,0x1161,0x1161,0x1161,0x1161,0x1161,0x1161,0x1161,0x1167,
-0x1161,0x1167,0x1161,0x1161,0x1161,0x1167,0x1167,0x13e,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,
-0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x141,0x141,
-0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,
-0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1182,0x116d,0x1182,
-0x116d,0x116d,0x116d,0x116d,0x116d,0x116d,0x116d,0x144,0x1176,0x117f,0x116d,0x117f,0x117f,0x116d,0x116d,0x116d,
-0x116d,0x116d,0x116d,0x116d,0x116d,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x116d,0x116d,0x1173,0x1173,0x1173,
-0x1173,0x1173,0x1173,0x1173,0x1173,0x144,0x144,0x1170,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,
-0x117c,0x117c,0x144,0x144,0x144,0x144,0x144,0x144,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,0x117c,
-0x117c,0x117c,0x144,0x144,0x144,0x144,0x144,0x144,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1188,
-0x118b,0x118b,0x118b,0x118b,0x1179,0x1179,0x144,0x144,0x1551,0x1551,0x1551,0x1551,0x1551,0x1551,0x1551,0x1551,
-0x1551,0x1551,0x1551,0x1551,0x1551,0x1551,0x154e,0x1a73,0x12cf,0x12a8,0x12c6,0x12c6,0x12c6,0x12c6,0x12c6,0x12c6,
-0x12c6,0x12ae,0x12ab,0x12a2,0x12a2,0x12cc,0x12a2,0x12a2,0x12a2,0x12a2,0x12b1,0x148b,0x1491,0x148e,0x148e,0x18d2,
-0x16a7,0x16a7,0x1a40,0x147,0x147,0x147,0x147,0x147,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,
-0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x1197,0x1197,0x119a,0x11a3,0x119d,0x119d,0x119d,0x11a3,
-0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,
-0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,0x1293,
-0x1293,0x1293,0x1293,0x1293,0x1293,0x150,0x150,0x150,0x11c1,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b8,
-0x11c7,0x11c7,0x11b5,0x11b5,0x11b5,0x11b5,0x153,0x12c3,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,
-0x11bb,0x11bb,0x153,0x153,0x153,0x153,0x11b5,0x11b5,0x11e5,0x11d9,0x11e5,0x156,0x156,0x156,0x156,0x156,
+0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x129,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
+0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
+0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e6,0x12c,0x12c,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,
+0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,
+0x10e9,0x10e9,0x10e9,0x10e9,0x10e9,0x12f,0x12f,0x12f,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,
+0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x132,0x132,0x132,0x132,0x132,0x132,0x132,
+0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x132,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,
+0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,0x10f2,
+0x10f2,0x10f2,0x135,0x135,0x135,0x135,0x135,0x10ef,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,
+0x10f5,0x10f5,0x10f5,0x10f5,0x138,0x138,0x138,0x138,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,
+0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x13b,0x13b,0x13b,0x13b,
+0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x13b,0x1170,0x1170,0x1170,0x1170,0x1179,0x1170,0x1170,0x1170,
+0x1179,0x1170,0x1170,0x1170,0x1170,0x116d,0x13e,0x13e,0x1176,0x1176,0x1176,0x1176,0x1176,0x1176,0x1176,0x117c,
+0x1176,0x117c,0x1176,0x1176,0x1176,0x117c,0x117c,0x13e,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,
+0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x141,0x141,
+0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x141,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,
+0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x1197,0x1182,0x1197,
+0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x1182,0x144,0x118b,0x1194,0x1182,0x1194,0x1194,0x1182,0x1182,0x1182,
+0x1182,0x1182,0x1182,0x1182,0x1182,0x1197,0x1197,0x1197,0x1197,0x1197,0x1197,0x1182,0x1182,0x1188,0x1188,0x1188,
+0x1188,0x1188,0x1188,0x1188,0x1188,0x144,0x144,0x1185,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,
+0x1191,0x1191,0x144,0x144,0x144,0x144,0x144,0x144,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,
+0x1191,0x1191,0x144,0x144,0x144,0x144,0x144,0x144,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x118e,0x119d,
+0x11a0,0x11a0,0x11a0,0x11a0,0x118e,0x118e,0x144,0x144,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,
+0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1560,0x1a85,0x12e1,0x12ba,0x12d8,0x12d8,0x12d8,0x12d8,0x12d8,0x12d8,
+0x12d8,0x12c0,0x12bd,0x12b4,0x12b4,0x12de,0x12b4,0x12b4,0x12b4,0x12b4,0x12c3,0x149d,0x14a3,0x14a0,0x14a0,0x18e4,
+0x16b9,0x16b9,0x1a52,0x147,0x147,0x147,0x147,0x147,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,
+0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11ac,0x11ac,0x11af,0x11b8,0x11b2,0x11b2,0x11b2,0x11b8,
+0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x14a,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,
+0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,
+0x12a5,0x12a5,0x12a5,0x12a5,0x12a5,0x150,0x150,0x150,0x11d6,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11ca,0x11cd,
+0x11dc,0x11dc,0x11ca,0x11ca,0x11ca,0x11ca,0x153,0x12d5,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,
+0x11d0,0x11d0,0x153,0x153,0x153,0x153,0x11ca,0x11ca,0x11fa,0x11ee,0x11fa,0x156,0x156,0x156,0x156,0x156,
0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,0x156,
-0x156,0x156,0x156,0x11e2,0x11e2,0x11e8,0x11dc,0x11df,0x11fd,0x11fd,0x11fd,0x11f7,0x11f7,0x11ee,0x11f7,0x11f7,
-0x11ee,0x11f7,0x11f7,0x1200,0x11fa,0x11f1,0x159,0x159,0x11f4,0x11f4,0x11f4,0x11f4,0x11f4,0x11f4,0x11f4,0x11f4,
-0x11f4,0x11f4,0x159,0x159,0x159,0x159,0x159,0x159,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x1206,0x15c,
-0x15c,0x15c,0x15c,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,
-0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,0x1203,
-0x15c,0x15c,0x15c,0x15c,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,
-0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x120f,0x15f,0x120c,0x1209,0x1209,0x1209,0x1209,
-0x1209,0x1209,0x1209,0x1209,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,
-0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x162,0x162,0x162,0x1218,0x121b,0x121b,
-0x121b,0x121b,0x121b,0x121b,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,
-0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x165,0x165,0x1221,0x1221,0x1221,0x1221,
-0x1221,0x1221,0x1221,0x1221,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,
-0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x168,0x168,0x168,0x168,0x168,0x1227,0x1227,0x1227,0x1227,
-0x1227,0x1227,0x1227,0x1227,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,
-0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,0x1230,
-0x1230,0x1230,0x1230,0x16e,0x124b,0x124b,0x1b2a,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,
-0x171,0x1914,0x171,0x171,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,
-0x146a,0x146a,0x146a,0x146a,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,
-0x1251,0x1251,0x1251,0x174,0x19e3,0x19e3,0x19e3,0x19e3,0x19e3,0x19e3,0x19e3,0x19e6,0x19e0,0x26a,0x26a,0x26a,
-0x26a,0x26a,0x26a,0x26a,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,
-0x1815,0x1a64,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
+0x156,0x156,0x156,0x11f7,0x11f7,0x11fd,0x11f1,0x11f4,0x1212,0x1212,0x1212,0x120c,0x120c,0x1203,0x120c,0x120c,
+0x1203,0x120c,0x120c,0x1215,0x120f,0x1206,0x159,0x159,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209,0x1209,
+0x1209,0x1209,0x159,0x159,0x159,0x159,0x159,0x159,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x121b,0x15c,
+0x15c,0x15c,0x15c,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,
+0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,0x1218,
+0x15c,0x15c,0x15c,0x15c,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,
+0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x1224,0x15f,0x1221,0x121e,0x121e,0x121e,0x121e,
+0x121e,0x121e,0x121e,0x121e,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,
+0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x162,0x162,0x162,0x122d,0x1230,0x1230,
+0x1230,0x1230,0x1230,0x1230,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,
+0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x1239,0x165,0x165,0x1236,0x1236,0x1236,0x1236,
+0x1236,0x1236,0x1236,0x1236,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,
+0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x123f,0x168,0x168,0x168,0x168,0x168,0x123c,0x123c,0x123c,0x123c,
+0x123c,0x123c,0x123c,0x123c,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,
+0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,
+0x1245,0x1245,0x1245,0x16e,0x125d,0x125d,0x1b3c,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,0x171,
+0x171,0x1926,0x171,0x171,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,
+0x147c,0x147c,0x147c,0x147c,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,
+0x1827,0x1a76,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,
+0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,0x174,
+0x174,0x174,0x174,0x174,0x174,0x174,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,
+0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,0x1344,
+0x12ae,0x13a7,0x13a7,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
+0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,0x12ab,
+0x12ab,0x12ab,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x182a,0x177,0x177,0x177,0x177,
+0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x12a8,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
+0x13cb,0x13cb,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
+0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,
-0x177,0x177,0x177,0x177,0x177,0x177,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,
-0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,0x1332,
-0x129c,0x1395,0x1395,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,
-0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,0x1299,
-0x1299,0x1299,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1395,0x1818,0x17a,0x17a,0x17a,0x17a,
-0x1296,0x1296,0x1296,0x1296,0x1296,0x1296,0x1296,0x1296,0x1296,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,
-0x13b9,0x13b9,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,
-0x18b7,0x18b7,0x18b7,0x18b7,0x18b7,0x18b7,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,
-0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,
-0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x17a,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,
-0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,0x133b,
-0x133b,0x1335,0x1335,0x1335,0x17d,0x17d,0x1338,0x17d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x133e,0x1347,
-0x1341,0x1341,0x1347,0x1347,0x1347,0x1341,0x1347,0x1341,0x1341,0x1341,0x134a,0x134a,0x180,0x180,0x180,0x180,
-0x180,0x180,0x180,0x180,0x1344,0x1344,0x1344,0x1344,0x183,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x183,
-0x183,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x183,0x183,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x183,
-0x183,0x183,0x183,0x183,0x183,0x183,0x183,0x183,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x183,
-0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x1350,0x183,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,
-0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x1353,0x1353,0x1353,0x1353,0x1353,0x1353,0x1356,0x1368,
-0x1368,0x135c,0x135c,0x135c,0x135c,0x135c,0x186,0x186,0x186,0x186,0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,
-0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,0x1359,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,
-0x135f,0x135f,0x135f,0x135f,0x1b30,0x1b33,0x1b33,0x1b2d,0x1b2d,0x1b33,0x186,0x186,0x186,0x186,0x186,0x186,
-0x186,0x186,0x186,0x1521,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,
-0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x189,0x189,0x189,
-0x189,0x189,0x189,0x189,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,
-0x136e,0x136e,0x136e,0x18c,0x18c,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,
-0x136e,0x136e,0x136e,0x1524,0x18c,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,
-0x136e,0x136e,0x136e,0x139e,0x18c,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,0x136e,
-0x136e,0x136e,0x136e,0x136e,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,
-0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x1524,0x18c,0x18c,0x18c,0x18c,0x18c,0x18c,
-0x18c,0x18c,0x18c,0x18c,0x13b3,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,
-0x169e,0x1530,0x1530,0x1530,0x1770,0x1821,0x1821,0x185a,0x185a,0x1a22,0x1acd,0x1acd,0x18f,0x18f,0x18f,0x18f,
-0x18f,0x1b9c,0x1b9c,0x1b9c,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x1530,0x169b,
-0x169b,0x18f,0x18f,0x18f,0x1530,0x1530,0x1530,0x1530,0x1821,0x1821,0x1821,0x18bd,0x18bd,0x199e,0x1a22,0x1acd,
-0x1acd,0x18f,0x18f,0x18f,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,
-0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,
-0x192,0x192,0x192,0x192,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,
-0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,
-0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x195,0x140d,0x195,0x195,0x140d,0x195,0x140d,0x140d,0x140d,
-0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x195,0x140d,
-0x195,0x195,0x195,0x195,0x195,0x195,0x140d,0x195,0x195,0x195,0x195,0x140d,0x195,0x140d,0x195,0x140d,
-0x195,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x195,0x140d,0x195,0x195,0x140d,0x195,0x140d,0x195,0x140d,
-0x195,0x140d,0x195,0x140d,0x195,0x140d,0x140d,0x195,0x140d,0x195,0x195,0x140d,0x140d,0x140d,0x140d,0x195,
-0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x140d,
-0x140d,0x195,0x140d,0x195,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,
-0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,
-0x195,0x195,0x195,0x195,0x195,0x140d,0x140d,0x140d,0x195,0x140d,0x140d,0x140d,0x140d,0x140d,0x195,0x140d,
-0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,0x140d,
-0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,
-0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,
-0x140a,0x140a,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,
-0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1410,0x1410,0x1410,0x1410,0x1410,0x141f,0x1410,0x1413,0x1413,
-0x1410,0x1410,0x1410,0x1416,0x1416,0x198,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,0x141c,
-0x1419,0x1425,0x1425,0x1425,0x1920,0x191d,0x191d,0x1a6a,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,
-0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,
-0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x1431,0x142e,0x1428,0x1428,0x142e,0x142e,
-0x1437,0x1437,0x1431,0x1434,0x1434,0x142e,0x142b,0x19b,0x19b,0x19b,0x19b,0x19b,0x19b,0x19b,0x19b,0x19b,
-0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,
-0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x143a,0x19e,0x19e,0x19e,0x19e,0x16f5,0x16f5,0x143a,0x143a,
-0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,
-0x19e,0x19e,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,
-0x1446,0x1446,0x1446,0x1446,0x1446,0x19cb,0x19cb,0x19cb,0x19cb,0x19cb,0x19cb,0x1a1,0x1a1,0x1a1,0x1a1,0x19c5,
-0x1446,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,
-0x19c8,0x19c8,0x19c8,0x19c8,0x19c8,0x19c8,0x19c8,0x19c8,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1440,
-0x1440,0x1440,0x1440,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,0x1449,
-0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x146a,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,
-0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,
-0x146d,0x146d,0x146d,0x146d,0x146d,0x146d,0x146d,0x146d,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,
-0x12c9,0x12c6,0x12c9,0x12a5,0x12c6,0x12cc,0x12cc,0x12cf,0x12cc,0x12cf,0x12d2,0x12c6,0x12cf,0x12cf,0x12c6,0x12c6,
-0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x1470,0x1479,0x1470,0x1479,0x1479,
-0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x147c,0x1473,0x19ce,0x1b3f,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,
-0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1ad,0x1ad,
-0x153f,0x153f,0x153f,0x153f,0x153f,0x1545,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,
-0x154b,0x154b,0x154b,0x154b,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1b0,0x1548,
-0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x2b5,0x1b8a,0x1b8a,0x1b8a,0x1b8a,
-0x16aa,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,
-0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x1b3,0x1b3,0x1b3,0x1b3,
-0x1a73,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b45,0x1b42,0x1b42,0x1b42,0x1b6,
-0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,
-0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,
-0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x1b9,0x1b9,0x1b9,0x1b9,0x1b9,
-0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x1b9,0x1b9,0x1b9,
-0x1b9,0x1b9,0x1b9,0x1b9,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x1b9,0x1b9,
-0x155a,0x1554,0x1557,0x1560,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1bc,0x1bc,0x1bc,0x1bc,
-0x1bc,0x1bc,0x1bc,0x1bc,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,
-0x154b,0x154b,0x154b,0x154b,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,
-0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1923,0x1923,0x1923,0x1923,0x1bf,0x1bf,0x1bf,
-0x1bf,0x1bf,0x1bf,0x1bf,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,0x1a25,
-0x1bf,0x1bf,0x1bf,0x1bf,0x1b9f,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,
-0x1bf,0x1bf,0x1bf,0x1bf,0x170a,0x16ad,0x156f,0x16b3,0x1c2,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,
-0x1578,0x1c2,0x1c2,0x1578,0x1578,0x1c2,0x1c2,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,
-0x1578,0x1578,0x1578,0x1578,0x1578,0x1c2,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1c2,0x1578,0x1578,
-0x1c2,0x1578,0x1578,0x1578,0x1578,0x1578,0x1c2,0x19aa,0x16b0,0x1578,0x1569,0x156f,0x1569,0x156f,0x156f,0x156f,
-0x156f,0x1c2,0x1c2,0x156f,0x156f,0x1c2,0x1c2,0x1572,0x1572,0x1575,0x1c2,0x1c2,0x170d,0x1c2,0x1c2,0x1c2,
-0x1c2,0x1c2,0x1c2,0x1569,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x157b,0x1578,0x1578,0x1578,0x1578,0x156f,0x156f,
-0x1c2,0x1c2,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x156c,0x1c2,0x1c2,0x1c2,0x156c,0x156c,0x156c,0x156c,
-0x156c,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1c2,0x1590,0x1590,0x1590,0x1590,
-0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1c5,0x1590,
-0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x1590,0x158a,0x158a,0x158a,0x157e,
-0x157e,0x157e,0x158a,0x158a,0x157e,0x158d,0x1581,0x157e,0x1593,0x1593,0x1587,0x1593,0x1593,0x1584,0x17a3,0x1c5,
-0x15a2,0x15a2,0x15a2,0x1596,0x1596,0x1596,0x1596,0x1596,0x1596,0x1599,0x159c,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,
-0x159f,0x159f,0x159f,0x159f,0x159f,0x159f,0x159f,0x159f,0x159f,0x159f,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,0x1c8,
-0x1710,0x1710,0x1710,0x1710,0x15ae,0x15ab,0x19d1,0x19d1,0x1a79,0x1a7c,0x1a76,0x1a76,0x1cb,0x1cb,0x1cb,0x1cb,
-0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
-0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,
-0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,
-0x15c0,0x15c0,0x15c0,0x15b7,0x15ba,0x15bd,0x15c0,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,
-0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15c3,0x15c3,0x1d4,0x1d4,0x1d4,0x1d4,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,
-0x15cc,0x15cc,0x16b6,0x15cc,0x15cc,0x15cc,0x15c9,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,
-0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x1d7,0x1d7,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,0x15d5,
-0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,
-0x15db,0x15ed,0x15ed,0x15e1,0x15ea,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,
-0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x15e4,0x1da,0x1da,0x1da,0x1da,0x1da,0x1da,
-0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,
-0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x15f3,0x1dd,
-0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x15f0,0x1dd,0x1dd,0x1dd,0x1dd,0x15f6,0x15f6,
-0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
-0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x15f9,0x1602,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,
-0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15ff,0x15ff,0x15ff,0x15ff,0x15ff,0x1e0,
-0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,
-0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1608,0x1e3,
-0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,
-0x1614,0x1614,0x1614,0x1614,0x1614,0x1614,0x1611,0x1611,0x1611,0x1611,0x1611,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,
-0x162c,0x162c,0x162f,0x162f,0x1632,0x1623,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,
-0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1e9,0x1623,0x1623,0x1623,0x1623,0x1623,
-0x1623,0x1623,0x1e9,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,
-0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x162c,0x162c,0x162c,
-0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,
-0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,
-0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,0x1644,
-0x1644,0x1644,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1ef,0x1641,0x1641,0x1641,0x1641,0x1ef,0x1ef,0x1ef,
-0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x1647,
-0x1659,0x1659,0x1647,0x1647,0x1647,0x1647,0x1f5,0x1f5,0x1659,0x1659,0x165c,0x165c,0x1647,0x1647,0x1659,0x164d,
-0x164a,0x1650,0x1662,0x1662,0x1653,0x1653,0x1656,0x1656,0x1656,0x1662,0x1719,0x1719,0x1719,0x1719,0x1719,0x1719,
-0x1719,0x1719,0x1719,0x1719,0x1719,0x1719,0x1719,0x1719,0x1716,0x1716,0x1716,0x1716,0x1713,0x1713,0x1f5,0x1f5,
-0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,
-0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,
-0x1f8,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,0x1665,
-0x1665,0x1665,0x1665,0x1665,0x1665,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,
-0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1fb,0x1fb,0x1fb,0x1fb,
-0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1668,0x1668,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1fb,0x1fb,0x1a7f,0x1a7f,0x1fb,0x1fb,
-0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,
-0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,
-0x166b,0x167a,0x1671,0x166e,0x1680,0x1680,0x1674,0x1680,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,
-0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,
-0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1686,0x1683,0x1683,0x1683,0x1683,0x1683,0x1683,
-0x1683,0x1683,0x1683,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x201,0x168c,
-0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,
-0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x172e,0x1926,0x204,0x204,0x171c,0x171c,0x171c,
-0x1728,0x1728,0x171c,0x171c,0x171c,0x171c,0x172b,0x171c,0x171c,0x171c,0x171c,0x171f,0x204,0x204,0x204,0x204,
-0x1725,0x1725,0x1725,0x1725,0x1725,0x1725,0x1725,0x1725,0x1725,0x1725,0x1722,0x1722,0x1731,0x1731,0x1731,0x1722,
-0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,
-0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,
-0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x207,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,
-0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x20d,0x1746,0x1746,0x20d,0x20d,
-0x20d,0x20d,0x20d,0x1743,0x1743,0x1743,0x1743,0x1743,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x210,
-0x1749,0x210,0x1749,0x1749,0x1749,0x1749,0x210,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,
-0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x210,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,0x1749,
-0x1749,0x174c,0x210,0x210,0x210,0x210,0x210,0x210,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,
-0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,
-0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x213,0x213,0x213,0x213,0x213,
-0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,
-0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x213,0x213,0x213,0x213,0x213,
-0x213,0x213,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x175b,0x175b,0x175b,0x175b,0x1758,0x175b,0x175b,0x175e,
-0x1761,0x175e,0x175e,0x175b,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,0x216,
-0x216,0x216,0x216,0x1758,0x1758,0x1758,0x1758,0x1758,0x17b8,0x17b8,0x17b8,0x17b8,0x17af,0x17af,0x17af,0x17a9,
-0x17ac,0x17ac,0x17ac,0x19d4,0x219,0x219,0x219,0x219,0x17b5,0x17b5,0x17b5,0x17b5,0x17b5,0x17b5,0x17b5,0x17b5,
-0x17b5,0x17b5,0x219,0x219,0x219,0x219,0x17b2,0x17b2,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,
-0x17d3,0x21c,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,
-0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d3,0x17d0,0x17be,0x17be,0x17be,0x17be,
-0x17be,0x17be,0x17be,0x21c,0x17be,0x17be,0x17be,0x17be,0x17be,0x17be,0x17d0,0x17c1,0x17d3,0x17d6,0x17d6,0x17ca,
-0x17c7,0x17c7,0x21c,0x21c,0x21c,0x21c,0x21c,0x21c,0x21c,0x21c,0x21c,0x21c,0x17cd,0x17cd,0x17cd,0x17cd,
-0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,
-0x17c4,0x17c4,0x17c4,0x17c4,0x17c4,0x21c,0x21c,0x21c,0x17e2,0x17e5,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,
-0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,0x17d9,
-0x17d9,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x21f,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,
-0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x222,
-0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,
-0x17dc,0x222,0x222,0x17dc,0x17dc,0x17dc,0x17dc,0x17dc,0x182a,0x18c6,0x1a2e,0x1a31,0x1ad9,0x225,0x225,0x225,
-0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x1ad6,0x1ad6,0x225,0x225,0x225,0x225,0x225,0x225,
-0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,
-0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x228,0x228,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,
-0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x228,0x17e8,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,
-0x17df,0x17e8,0x17df,0x17df,0x17e8,0x17df,0x17df,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,
-0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x22b,0x22b,0x22b,
+0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x177,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,
+0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,
+0x134d,0x1347,0x1347,0x1347,0x17a,0x17a,0x134a,0x17a,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x1350,0x1359,
+0x1353,0x1353,0x1359,0x1359,0x1359,0x1353,0x1359,0x1353,0x1353,0x1353,0x135c,0x135c,0x17d,0x17d,0x17d,0x17d,
+0x17d,0x17d,0x17d,0x17d,0x1356,0x1356,0x1356,0x1356,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,
+0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,
+0x180,0x180,0x180,0x180,0x180,0x180,0x180,0x180,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,
+0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x1362,0x180,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,
+0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1368,0x137a,
+0x137a,0x136e,0x136e,0x136e,0x136e,0x136e,0x183,0x183,0x183,0x183,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,
+0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,
+0x1371,0x1371,0x1371,0x1371,0x1b42,0x1b45,0x1b45,0x1b3f,0x1b3f,0x1b45,0x183,0x183,0x183,0x183,0x183,0x183,
+0x183,0x183,0x183,0x1533,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,
+0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x186,0x186,0x186,
+0x186,0x186,0x186,0x186,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,
+0x1380,0x1380,0x1380,0x189,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,
+0x1380,0x1380,0x1380,0x1536,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,
+0x1380,0x1380,0x1380,0x13b0,0x189,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,0x1380,
+0x1380,0x1380,0x1380,0x1380,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,
+0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x189,0x189,0x189,0x189,0x189,0x189,
+0x189,0x189,0x189,0x189,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,
+0x16b0,0x1542,0x1542,0x1542,0x1782,0x1833,0x1833,0x186c,0x186c,0x1a34,0x1adf,0x1adf,0x18c,0x18c,0x18c,0x18c,
+0x1c2c,0x1bae,0x1bae,0x1bae,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x16ad,
+0x16ad,0x18c,0x18c,0x18c,0x1542,0x1542,0x1542,0x1542,0x1833,0x1833,0x1833,0x18cf,0x18cf,0x19b0,0x1a34,0x1adf,
+0x1adf,0x18c,0x18c,0x18c,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,
+0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1bd2,0x1bd2,0x1bd2,0x18f,0x18f,0x18f,0x18f,0x1bd2,
+0x1bd2,0x1bd2,0x1bd2,0x1bd2,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,
+0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,
+0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x192,0x141f,0x141f,0x141f,
+0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x192,0x141f,
+0x192,0x192,0x192,0x192,0x192,0x192,0x141f,0x192,0x192,0x192,0x192,0x141f,0x192,0x141f,0x192,0x141f,
+0x192,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x192,0x141f,0x192,0x141f,
+0x192,0x141f,0x192,0x141f,0x192,0x141f,0x141f,0x192,0x141f,0x192,0x192,0x141f,0x141f,0x141f,0x141f,0x192,
+0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,
+0x141f,0x192,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,
+0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,
+0x192,0x192,0x192,0x192,0x192,0x141f,0x141f,0x141f,0x192,0x141f,0x141f,0x141f,0x141f,0x141f,0x192,0x141f,
+0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,0x141f,
+0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,
+0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,
+0x141c,0x141c,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,0x192,
+0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1422,0x1422,0x1422,0x1422,0x1422,0x1431,0x1422,0x1425,0x1425,
+0x1422,0x1422,0x1422,0x1428,0x1428,0x195,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,0x142e,
+0x142b,0x1437,0x1437,0x1437,0x1932,0x192f,0x192f,0x1a7c,0x195,0x195,0x195,0x195,0x195,0x195,0x195,0x195,
+0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,
+0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1440,0x143a,0x143a,0x1440,0x1440,
+0x1449,0x1449,0x1443,0x1446,0x1446,0x1440,0x143d,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,0x198,
+0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,
+0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x19b,0x19b,0x19b,0x19b,0x1707,0x1707,0x144c,0x144c,
+0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,
+0x19b,0x19b,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,
+0x1458,0x1458,0x1458,0x1458,0x1458,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19e,0x19e,0x19e,0x19e,0x19d7,
+0x1458,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,
+0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19da,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x19e,0x1452,
+0x1452,0x1452,0x1452,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,0x145b,
+0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x147c,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1479,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,0x1a1,
+0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,0x1a4,
+0x12db,0x12d8,0x12db,0x12b7,0x12d8,0x12de,0x12de,0x12e1,0x12de,0x12e1,0x12e4,0x12d8,0x12e1,0x12e1,0x12d8,0x12d8,
+0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1482,0x148b,0x1482,0x148b,0x148b,
+0x1482,0x1482,0x1482,0x1482,0x1482,0x1482,0x148e,0x1485,0x19e0,0x1b51,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,0x1a7,
+0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1aa,0x1aa,
+0x1551,0x1551,0x1551,0x1551,0x1551,0x1557,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,0x1aa,
+0x155d,0x155d,0x155d,0x155d,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x1ad,0x155a,
+0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2,0x1b9c,0x1b9c,0x1b9c,0x1b9c,
+0x16bc,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,
+0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x16b3,0x1b0,0x1b0,0x1b0,0x1b0,
+0x1a85,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b57,0x1b54,0x1b54,0x1b54,0x1b3,
+0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,
+0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,0x1b3,
+0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6,0x1b6,0x1b6,0x1b6,
+0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6,0x1b6,
+0x1b6,0x1b6,0x1b6,0x1b6,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1b6,0x1b6,
+0x156c,0x1566,0x1569,0x1572,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1b9,0x1b9,0x1b9,0x1b9,
+0x1b9,0x1b9,0x1b9,0x1b9,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,
+0x155d,0x155d,0x155d,0x155d,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,
+0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1935,0x1935,0x1935,0x1935,0x1bd5,0x1bc,0x1bc,
+0x1bc,0x1bc,0x1bc,0x1bc,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,0x1a37,
+0x1bc,0x1bc,0x1bc,0x1bc,0x1bb1,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,0x1bc,
+0x1bc,0x1bc,0x1bc,0x1bc,0x171c,0x16bf,0x1581,0x16c5,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,
+0x158a,0x1bf,0x1bf,0x158a,0x158a,0x1bf,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,
+0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x158a,0x158a,
+0x1bf,0x158a,0x158a,0x158a,0x158a,0x158a,0x1bf,0x19bc,0x16c2,0x158a,0x157b,0x1581,0x157b,0x1581,0x1581,0x1581,
+0x1581,0x1bf,0x1bf,0x1581,0x1581,0x1bf,0x1bf,0x1584,0x1584,0x1587,0x1bf,0x1bf,0x171f,0x1bf,0x1bf,0x1bf,
+0x1bf,0x1bf,0x1bf,0x157b,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x158d,0x158a,0x158a,0x158a,0x158a,0x1581,0x1581,
+0x1bf,0x1bf,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x157e,0x1bf,0x1bf,0x1bf,0x157e,0x157e,0x157e,0x157e,
+0x157e,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x1bf,0x15a2,0x15a2,0x15a2,0x15a2,
+0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x1c2,0x15a2,
+0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15b4,0x15b4,0x15b4,0x15a8,
+0x15a8,0x15a8,0x15a8,0x15a8,0x15a8,0x15ab,0x15ae,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x15b1,0x15b1,0x15b1,0x15b1,
+0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x15b1,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1c5,0x1722,0x1722,0x1722,0x1722,
+0x15c0,0x15bd,0x19e3,0x19e3,0x1a8b,0x1a8e,0x1a88,0x1a88,0x1c8,0x1c8,0x1c8,0x1c8,0x174f,0x174f,0x174f,0x174f,
+0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x15c6,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,
+0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x1cb,0x15d2,0x15d2,0x15d2,0x15d2,
+0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15d2,0x15c9,
+0x15cc,0x15cf,0x15d2,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x1ce,0x15e1,0x15e1,0x15e1,0x15e1,
+0x15e1,0x15d5,0x15d5,0x1d1,0x1d1,0x1d1,0x1d1,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15de,0x15de,0x16c8,0x15de,
+0x15de,0x15de,0x15db,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x1d1,0x15ea,0x15ea,0x15ea,0x15ea,
+0x15ea,0x1d4,0x1d4,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e7,0x15e4,0x15e4,0x15e4,0x15e4,
+0x15e4,0x15e4,0x15e4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x1d4,0x15ed,0x15ff,0x15ff,0x15f3,
+0x15fc,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x15f6,0x15f6,0x15f6,0x15f6,
+0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x15f6,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1d7,0x1605,0x1605,0x1605,0x1605,
+0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,
+0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1605,0x1da,0x1602,0x1602,0x1602,0x1602,
+0x1602,0x1602,0x1602,0x1602,0x1602,0x1602,0x1da,0x1da,0x1da,0x1da,0x1608,0x1608,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
+0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1611,0x1611,0x1611,0x1611,
+0x1611,0x160b,0x1614,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x1611,0x160e,0x160e,0x160e,0x160e,
+0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x1611,0x1611,0x1611,0x1611,0x1611,0x1dd,0x161a,0x161a,0x161a,0x161a,
+0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,
+0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x161a,0x1e0,0x1626,0x1626,0x1626,0x1626,
+0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,0x1626,
+0x1626,0x1626,0x1623,0x1623,0x1623,0x1623,0x1623,0x1e3,0x1e3,0x1e3,0x1e3,0x1e3,0x163e,0x163e,0x1641,0x1641,
+0x1644,0x1635,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x163b,0x163b,0x163b,0x163b,
+0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x1e6,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x1e6,0x163e,
+0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,
+0x163e,0x163e,0x163e,0x163e,0x1e6,0x1e6,0x1e6,0x1e6,0x1e6,0x163e,0x163e,0x163e,0x164d,0x164d,0x164d,0x164d,
+0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,
+0x164d,0x164d,0x164d,0x164d,0x164d,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1e9,0x1656,0x1656,0x1656,0x1656,
+0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1656,0x1ec,0x1ec,
+0x1ec,0x1ec,0x1ec,0x1ec,0x1ec,0x1653,0x1653,0x1653,0x1653,0x1ec,0x1ec,0x1ec,0x1671,0x1671,0x1671,0x1671,
+0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1659,0x166b,0x166b,0x1659,0x1659,
+0x1659,0x1659,0x1f2,0x1f2,0x166b,0x166b,0x166e,0x166e,0x1659,0x1659,0x166b,0x165f,0x165c,0x1662,0x1674,0x1674,
+0x1665,0x1665,0x1668,0x1668,0x1668,0x1674,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,0x172b,
+0x172b,0x172b,0x172b,0x172b,0x1728,0x1728,0x1728,0x1728,0x1725,0x1725,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,
+0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,
+0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f2,0x1f5,0x1677,0x1677,0x1677,
+0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,0x1677,
+0x1677,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x1f5,0x167a,0x167a,0x167a,0x167a,
+0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,
+0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8,
+0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,
+0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1f8,0x1f8,
+0x1f8,0x1f8,0x1f8,0x1f8,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,
+0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1f8,0x1f8,0x1a91,0x1a91,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,
+0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,
+0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x1f8,0x167d,0x168c,0x1683,0x1680,
+0x1692,0x1692,0x1686,0x1692,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1689,0x1689,0x1689,0x1689,
+0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1fb,0x1698,0x1698,0x1698,0x1698,
+0x1698,0x1698,0x1698,0x1698,0x1698,0x1698,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1695,0x1fe,
+0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x1fe,0x169e,0x1740,0x1740,0x1740,0x1740,
+0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,
+0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1938,0x201,0x201,0x172e,0x172e,0x172e,0x173a,0x173a,0x172e,0x172e,
+0x172e,0x172e,0x173d,0x172e,0x172e,0x172e,0x172e,0x1731,0x201,0x201,0x201,0x201,0x1737,0x1737,0x1737,0x1737,
+0x1737,0x1737,0x1737,0x1737,0x1737,0x1737,0x1734,0x1734,0x1743,0x1743,0x1743,0x1734,0x1746,0x1746,0x1746,0x1746,
+0x1746,0x1746,0x1746,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,
+0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,0x204,
+0x204,0x204,0x204,0x204,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,
+0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x20a,0x1758,0x1758,0x20a,0x20a,0x20a,0x20a,0x20a,0x1755,
+0x1755,0x1755,0x1755,0x1755,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x20d,0x175b,0x20d,0x175b,0x175b,
+0x175b,0x175b,0x20d,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,
+0x175b,0x175b,0x20d,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175e,0x20d,0x20d,
+0x20d,0x20d,0x20d,0x20d,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,
+0x15b7,0x15b7,0x15b7,0x15b7,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,
+0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x210,
+0x210,0x210,0x210,0x210,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,
+0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x210,0x210,0x210,0x210,0x210,0x210,0x210,0x1761,0x1761,
+0x1761,0x1761,0x1761,0x1761,0x176d,0x176d,0x176d,0x176d,0x176a,0x176d,0x176d,0x1770,0x1773,0x1770,0x1770,0x176d,
+0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x213,0x176a,
+0x176a,0x176a,0x176a,0x176a,0x17ca,0x17ca,0x17ca,0x17ca,0x17c1,0x17c1,0x17c1,0x17bb,0x17be,0x17be,0x17be,0x19e6,
+0x216,0x216,0x216,0x216,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x17c7,0x216,0x216,
+0x216,0x216,0x17c4,0x17c4,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x219,0x17e5,0x17e5,
+0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,
+0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e5,0x17e2,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x219,
+0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17d0,0x17e2,0x17d3,0x17e5,0x17e8,0x17e8,0x17dc,0x17d9,0x17d9,0x219,0x219,
+0x219,0x219,0x219,0x219,0x219,0x219,0x219,0x219,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,0x17df,
+0x17df,0x17df,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,0x17d6,
+0x17d6,0x219,0x219,0x219,0x17f4,0x17f7,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,
+0x17fd,0x17fd,0x17fd,0x17fd,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x17eb,0x21c,0x21c,0x21c,
+0x21c,0x21c,0x21c,0x21c,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,
+0x1956,0x1956,0x1956,0x1956,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x17ee,0x17ee,
+0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x21f,0x17ee,
+0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x21f,0x17ee,0x17ee,0x17ee,0x17ee,0x17ee,0x21f,
+0x21f,0x21f,0x21f,0x21f,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,
+0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x183c,0x18d8,0x1a40,0x1a43,0x1aeb,0x222,0x222,0x222,0x222,0x222,0x222,0x222,
+0x222,0x222,0x222,0x222,0x1ae8,0x1ae8,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,0x222,
+0x222,0x222,0x222,0x222,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,0x17fd,
+0x17fd,0x17fd,0x17fd,0x17fd,0x225,0x225,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,
+0x17f1,0x17f1,0x17f1,0x17f1,0x225,0x17fa,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17fa,0x17f1,0x17f1,
+0x17fa,0x17f1,0x17f1,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x225,0x1800,0x1800,0x1800,0x1800,
+0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x1800,0x228,0x228,0x228,0x228,0x228,0x228,0x228,
+0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x228,0x1818,0x1818,0x1809,0x1803,
+0x1803,0x1818,0x1806,0x181b,0x181b,0x181b,0x181b,0x181e,0x181e,0x1812,0x180f,0x180c,0x1815,0x1815,0x1815,0x1815,
+0x1815,0x1815,0x1815,0x1815,0x1815,0x1815,0x1a94,0x1812,0x22b,0x180c,0x193b,0x19e9,0x1a97,0x1a97,0x22b,0x22b,
0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,
-0x1806,0x1806,0x17f7,0x17f1,0x17f1,0x1806,0x17f4,0x1809,0x1809,0x1809,0x1809,0x180c,0x180c,0x1800,0x17fd,0x17fa,
-0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1a82,0x1800,0x22e,0x17fa,0x1929,0x19d7,
-0x1a85,0x1a85,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,
-0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,0x22e,
-0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,0x1812,
-0x1812,0x1812,0x1812,0x1812,0x231,0x231,0x231,0x231,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,
-0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,0x180f,
-0x180f,0x180f,0x180f,0x180f,0x231,0x231,0x231,0x231,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,
-0x182d,0x182d,0x182d,0x182d,0x182d,0x19a7,0x19a7,0x19a7,0x19a7,0x19a7,0x1a34,0x1a34,0x1a34,0x1a34,0x1a34,0x1a34,
-0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x1ba8,0x1ba8,0x1ba8,0x237,0x237,0x237,0x237,0x237,
-0x237,0x237,0x237,0x237,0x237,0x237,0x237,0x237,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,
-0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x23a,
-0x186c,0x186c,0x23a,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,
-0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x186c,0x1860,0x1860,0x1860,0x1860,0x1860,0x1860,0x23a,
-0x23a,0x23a,0x1860,0x23a,0x1860,0x1860,0x23a,0x1860,0x1860,0x1860,0x1863,0x1860,0x1866,0x1866,0x186f,0x1860,
-0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x1869,0x1869,0x1869,0x1869,0x1869,0x1869,0x1869,0x1869,
-0x1869,0x1869,0x23a,0x23a,0x23a,0x23a,0x23a,0x23a,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,
-0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,
-0x18cf,0x18cf,0x18cf,0x18cf,0x23d,0x23d,0x23d,0x23d,0x187e,0x1881,0x1881,0x240,0x240,0x240,0x240,0x240,
-0x240,0x240,0x240,0x240,0x240,0x240,0x240,0x240,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,
-0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1890,0x1890,0x1890,0x1890,0x1890,0x1890,0x1890,0x1890,
-0x1890,0x1890,0x1890,0x243,0x243,0x243,0x243,0x243,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,
-0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x189c,0x189f,0x18ae,0x18ae,0x189f,0x18a2,0x189c,0x1899,
-0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x1887,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1884,
-0x1884,0x1872,0x1872,0x1872,0x1887,0x1887,0x1887,0x1887,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,
-0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x249,0x249,0x249,0x249,
-0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x249,0x192f,0x192f,0x192f,0x192f,0x192f,0x192f,0x192f,0x192f,
-0x192f,0x192f,0x192f,0x192f,0x192f,0x192f,0x249,0x249,0x1a3d,0x1a3d,0x1a3d,0x1a3d,0x1adf,0x27c,0x27c,0x27c,
-0x1a3d,0x1a3d,0x1a3d,0x1bab,0x1bab,0x27c,0x27c,0x27c,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,
-0x1941,0x1941,0x1941,0x1941,0x193e,0x193e,0x193e,0x1932,0x1932,0x1932,0x1932,0x1932,0x1932,0x1932,0x1932,0x1932,
-0x193e,0x1938,0x1935,0x193b,0x24c,0x24c,0x24c,0x24c,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,
-0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,
-0x1944,0x1944,0x1944,0x24f,0x24f,0x1944,0x1944,0x1944,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x252,0x1953,
-0x1953,0x252,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,
-0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1950,0x1950,0x1950,0x1950,0x1950,0x252,
-0x1947,0x1947,0x252,0x1950,0x1950,0x1947,0x1950,0x194a,0x1953,0x252,0x252,0x252,0x252,0x252,0x252,0x252,
-0x195c,0x195c,0x195f,0x195f,0x1956,0x1956,0x1956,0x1956,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,
-0x1959,0x1959,0x1959,0x1959,0x1959,0x1959,0x1959,0x1959,0x1959,0x1959,0x255,0x255,0x255,0x255,0x255,0x255,
-0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1965,0x1962,0x1962,0x1962,
-0x1965,0x1962,0x1962,0x1962,0x1962,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x258,
-0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,
-0x196e,0x196e,0x196e,0x1968,0x1968,0x196b,0x196b,0x1971,0x1971,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,
-0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,
-0x1974,0x1974,0x1974,0x1974,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,0x25e,
-0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,
-0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x1977,0x197a,0x1983,0x1977,0x1977,0x261,0x261,0x261,0x261,0x261,
-0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1989,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,
-0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,
-0x1992,0x1992,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198c,0x198f,0x198f,0x198f,
-0x198f,0x1995,0x1995,0x1995,0x1995,0x1995,0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x267,
-0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x267,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,
-0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x1b72,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,
-0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x19e9,0x26d,
-0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,
-0x270,0x270,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,
-0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f8,0x19f5,0x19f5,0x19f5,0x19ec,0x19ec,0x19ec,0x19ec,
-0x270,0x270,0x19ec,0x19ec,0x19f5,0x19f5,0x19f5,0x19f5,0x19ef,0x19f8,0x19f2,0x19f8,0x19f5,0x270,0x270,0x270,
-0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,
-0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x270,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,
-0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x273,0x273,0x273,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x1a04,
-0x1a04,0x1a04,0x1a04,0x1a04,0x1a07,0x1a07,0x273,0x273,0x276,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,
+0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x22b,0x1824,0x1824,0x1824,0x1824,
+0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,
+0x22e,0x22e,0x22e,0x22e,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,
+0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,0x1821,
+0x22e,0x22e,0x22e,0x22e,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,
+0x183f,0x19b9,0x19b9,0x19b9,0x19b9,0x19b9,0x1a46,0x1a46,0x1a46,0x1a46,0x1a46,0x1a46,0x231,0x231,0x231,0x231,
+0x231,0x231,0x231,0x231,0x1bba,0x1bba,0x1bba,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234,0x234,
+0x234,0x234,0x234,0x234,0x276,0x276,0x1c2f,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,
+0x276,0x276,0x276,0x276,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x237,0x187e,0x187e,0x237,0x187e,
+0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,0x187e,
+0x187e,0x187e,0x187e,0x187e,0x187e,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x237,0x237,0x237,0x1872,0x237,
+0x1872,0x1872,0x237,0x1872,0x1872,0x1872,0x1875,0x1872,0x1878,0x1878,0x1881,0x1872,0x237,0x237,0x237,0x237,
+0x237,0x237,0x237,0x237,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x187b,0x237,0x237,
+0x237,0x237,0x237,0x237,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,
+0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,
+0x23a,0x23a,0x23a,0x23a,0x1890,0x1893,0x1893,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,0x23d,
+0x23d,0x23d,0x23d,0x23d,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,0x1b96,
+0x1b96,0x1b96,0x1b96,0x1b96,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x18a2,0x240,
+0x240,0x240,0x240,0x240,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,
+0x1b63,0x1b63,0x1b63,0x1b63,0x18ae,0x18b1,0x18c0,0x18c0,0x18b1,0x18b4,0x18ae,0x18ab,0x243,0x243,0x243,0x243,
+0x243,0x243,0x243,0x243,0x1899,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1896,0x1896,0x1884,0x1884,0x1884,
+0x1899,0x1899,0x1899,0x1899,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,
+0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x246,0x246,0x246,0x246,0x246,0x246,0x246,0x246,
+0x246,0x246,0x246,0x246,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,
+0x1941,0x1941,0x246,0x246,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1c35,0x1c35,0x1c35,0x1a4f,0x1a4f,0x1a4f,0x1bbd,
+0x1bbd,0x279,0x279,0x279,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,
+0x1950,0x1950,0x1950,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1944,0x1950,0x194a,0x1947,0x194d,
+0x249,0x249,0x249,0x249,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,
+0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x1956,0x24c,
+0x24c,0x1956,0x1956,0x1956,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x24f,0x1965,0x1965,0x24f,0x1965,0x1965,
+0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,
+0x1965,0x1965,0x1965,0x1965,0x1965,0x1965,0x1962,0x1962,0x1962,0x1962,0x1962,0x24f,0x1959,0x1959,0x24f,0x1962,
+0x1962,0x1959,0x1962,0x195c,0x1965,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x24f,0x196e,0x196e,0x1971,0x1971,
+0x1968,0x1968,0x1968,0x1968,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x252,0x196b,0x196b,0x196b,0x196b,
+0x196b,0x196b,0x196b,0x196b,0x196b,0x196b,0x252,0x252,0x252,0x252,0x252,0x252,0x1974,0x1974,0x1974,0x1974,
+0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1977,0x1974,0x1974,0x1974,0x1977,0x1974,0x1974,0x1974,
+0x1974,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x255,0x1980,0x1980,0x1980,0x1980,
+0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x197a,
+0x197a,0x197d,0x197d,0x1983,0x1983,0x258,0x258,0x258,0x258,0x258,0x258,0x258,0x1986,0x1986,0x1986,0x1986,
+0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,0x1986,
+0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x25b,0x1989,0x1989,0x1989,0x1989,
+0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,
+0x1989,0x1989,0x1989,0x198c,0x1995,0x1989,0x1989,0x25e,0x25e,0x25e,0x25e,0x25e,0x1998,0x1998,0x1998,0x1998,
+0x1998,0x1998,0x1998,0x199b,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x261,0x19a4,0x19a4,0x19a4,0x19a4,
+0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x19a4,0x199e,0x199e,
+0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x199e,0x19a1,0x19a1,0x19a1,0x19a1,0x19a7,0x19a7,0x19a7,
+0x19a7,0x19a7,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,0x264,
+0x264,0x264,0x264,0x264,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,0x1b84,
+0x1b84,0x1b84,0x1b84,0x1b84,0x1be7,0x1bed,0x1bed,0x1bed,0x1bed,0x1bed,0x1bed,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,
+0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x1bea,0x267,0x267,0x267,0x267,0x267,0x267,
+0x267,0x267,0x267,0x267,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,
+0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x19fb,0x26a,0x26a,0x26a,0x26a,0x26a,
+0x26a,0x26a,0x26a,0x26a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x26d,0x26d,0x1a0a,0x1a0a,
0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,
-0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x276,0x276,0x279,0x279,0x279,0x279,
-0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1a37,0x1a37,0x1a37,0x279,
-0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1a3a,0x1a3a,0x1a3a,0x1a3a,
-0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,
-0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x1a3d,0x1a3d,0x1a3d,0x1adf,0x1adf,0x1adf,0x1adf,0x27c,
-0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x1a3d,0x1a3d,0x1a3d,0x1a3d,0x1a3d,0x1a3d,0x1adf,0x1adf,
-0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1bab,0x1bab,0x1bab,0x1bab,0x27c,0x27c,0x27c,
-0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1bab,0x1bab,0x1bab,0x1bab,0x27c,0x27c,0x27c,0x27c,0x27c,
-0x1adf,0x1adf,0x1adf,0x1bae,0x1bae,0x1bae,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,
-0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1adf,0x1bab,0x1bab,0x1bab,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,
-0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x1bab,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,
-0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x1bae,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,
-0x1a13,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,
-0x1a0d,0x1a0d,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x27f,0x1a10,
-0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a16,0x1a16,0x1a16,0x1a16,
-0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x282,0x282,0x282,0x282,0x282,0x1a19,
-0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a88,0x1a88,0x1a88,0x1a88,0x1a88,0x1a88,0x1a88,0x285,0x285,0x285,0x285,
-0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,0x285,
-0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x288,0x288,0x1aa6,0x288,0x288,0x1aa6,0x1aa6,0x1aa6,0x1aa6,
-0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x288,0x1aa6,0x1aa6,0x288,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,
-0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1aa6,0x1a8e,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x288,0x1a9d,
-0x1aa0,0x288,0x288,0x1a8e,0x1a8e,0x1aa3,0x1a94,0x1aa9,0x1a9d,0x1aa9,0x1a9d,0x1a91,0x1aac,0x1a97,0x1aac,0x288,
-0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,
-0x1a9a,0x1a9a,0x288,0x288,0x288,0x288,0x288,0x288,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,
-0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x28b,0x28b,
-0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,
-0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,0x28b,
-0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,
-0x1ab2,0x1ab2,0x1ab2,0x291,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,
-0x1ab2,0x1ab2,0x1ab2,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,
-0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x1ab5,0x1ab5,0x1ab5,0x1ab5,0x1ab5,0x1ab5,0x1ab5,0x1ab5,
-0x1ab5,0x1ab5,0x291,0x291,0x291,0x291,0x291,0x291,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,0x1ae8,
-0x1ae8,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,
-0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,
-0x294,0x294,0x294,0x294,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x297,0x1ab8,
-0x1ab8,0x1abb,0x297,0x297,0x1abe,0x1abe,0x297,0x297,0x297,0x297,0x297,0x297,0x297,0x297,0x297,0x297,
-0x297,0x297,0x297,0x297,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b51,0x1b4e,0x1b51,0x1b51,0x1b51,
-0x1b51,0x1b51,0x1b51,0x29a,0x1b54,0x1b54,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x1b4b,0x1b4b,0x1b4b,0x1b4b,
-0x1b4b,0x1b4b,0x1b4b,0x1b4b,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,
-0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b57,0x1b57,0x29d,0x29d,0x29d,0x29d,0x29d,0x29d,0x29d,0x29d,0x29d,
-0x29d,0x29d,0x29d,0x29d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x2a0,0x1b5d,0x1b5d,0x1b5d,0x1b5d,
-0x2a0,0x1b5d,0x1b5d,0x2a0,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,
-0x1b5d,0x1b5d,0x1b5d,0x2a0,0x1b60,0x1b66,0x1b66,0x1b63,0x1b63,0x1b63,0x2a6,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,
-0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,
-0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x2a6,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x2a6,
-0x2a6,0x2a6,0x2a6,0x2a6,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b6c,0x1b69,
-0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,0x1b69,
-0x1b69,0x1b69,0x1b69,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,
-0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,
-0x2a9,0x2a9,0x2a9,0x2a9,0x1b72,0x1b72,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b75,0x1b75,0x1b75,0x1b75,0x2ac,0x2ac,
-0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,
-0x2ac,0x2ac,0x2ac,0x2ac,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1a8b,
-0x1a8b,0x1a8b,0x1a8b,0x1a8b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
-0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
-0x1b7b,0x1b7b,0x1b7b,0x2af,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x1b78,0x2af,0x2af,
-0x2af,0x2af,0x2af,0x2af,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,0x1542,
-0x1542,0x1542,0x1542,0x1542,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,0x1b81,
-0x1b81,0x1b81,0x1b7e,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,0x2b2,
-0x2b2,0x2b2,0x2b2,0x2b2,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x2b5,
-0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x2b5,0x1b8a,0x1b8a,0x2b5,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,
-0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x2b5,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,
-0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x2b5,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x1b87,0x2b5,0x1b87,
-0x1b87,0x2b5,0x2b5,0x2b5,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,
-0x1b90,0x1b90,0x2b8,0x2b8,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,
-0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,
+0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a0a,0x1a07,0x1a07,0x1a07,0x19fe,0x19fe,0x19fe,0x19fe,0x26d,0x26d,0x19fe,0x19fe,
+0x1a07,0x1a07,0x1a07,0x1a07,0x1a01,0x1a0a,0x1a04,0x1a0a,0x1a07,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,
+0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,0x26d,
+0x26d,0x26d,0x26d,0x26d,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,
+0x1a16,0x270,0x270,0x270,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,
+0x1a19,0x1a19,0x270,0x270,0x273,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,
+0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,
+0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x1a1c,0x273,0x273,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,
+0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1a49,0x1a49,0x1a49,0x276,0x276,0x1c32,0x276,0x276,
+0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x276,0x1a4c,0x1a4c,0x1a4c,0x1a4c,0x276,0x276,0x276,0x276,
+0x276,0x276,0x276,0x276,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,
+0x18e1,0x18e1,0x18e1,0x18e1,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1af1,0x1af1,0x1af1,0x1c35,0x1c35,0x279,0x279,0x279,
+0x279,0x279,0x279,0x279,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1a4f,0x1af1,0x1af1,0x1af1,0x1af1,0x1af1,0x1af1,
+0x1af1,0x1af1,0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x1c35,0x1af1,0x1af1,0x1af1,0x1af1,
+0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x1c35,0x279,0x1c35,0x1af1,0x1af1,0x1af1,0x1bc0,
+0x1bc0,0x1bc0,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1c35,0x1c35,0x1af1,0x1af1,0x1af1,0x1af1,
+0x1af1,0x1af1,0x1af1,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x1c35,0x279,0x279,0x279,0x279,0x1bbd,0x1bbd,0x1bbd,0x1bbd,
+0x1bbd,0x1bbd,0x1bbd,0x1bbd,0x1c35,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1bc0,0x1bc0,0x1bc0,0x1bc0,
+0x1bc0,0x1bc0,0x1bc0,0x1c38,0x1c38,0x279,0x279,0x279,0x279,0x279,0x279,0x279,0x1a25,0x1a1f,0x1a1f,0x1a1f,
+0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x27c,0x27c,
+0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x27c,0x1a22,0x1a31,0x1a31,0x1a31,0x1a31,
+0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a28,0x1a28,0x1a28,0x1a28,0x1a2e,0x1a2e,0x1a2e,0x1a2e,
+0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x1a2e,0x27f,0x27f,0x27f,0x27f,0x27f,0x1a2b,0x1a9d,0x1a9d,0x1a9d,0x1a9d,
+0x1a9d,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x1a9a,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,
+0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x282,0x1ab8,0x1ab8,0x1ab8,0x1ab8,
+0x1ab8,0x1ab8,0x1ab8,0x285,0x285,0x1ab8,0x285,0x285,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,
+0x285,0x1ab8,0x1ab8,0x285,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1ab8,
+0x1ab8,0x1ab8,0x1ab8,0x1ab8,0x1aa0,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x1aaf,0x285,0x1aaf,0x1ab2,0x285,0x285,0x1aa0,
+0x1aa0,0x1ab5,0x1aa6,0x1abb,0x1aaf,0x1abb,0x1aaf,0x1aa3,0x1abe,0x1aa9,0x1abe,0x285,0x285,0x285,0x285,0x285,
+0x285,0x285,0x285,0x285,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x1aac,0x285,0x285,
+0x285,0x285,0x285,0x285,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,
+0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x288,0x288,0x288,0x288,0x288,0x288,
+0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,
+0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x288,0x1ac4,0x1ac4,0x1ac4,0x1ac4,
+0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x28e,
+0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x28e,
+0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,0x28e,
+0x28e,0x28e,0x28e,0x28e,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x28e,0x28e,
+0x28e,0x28e,0x28e,0x28e,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x1afa,0x291,0x291,0x291,
+0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,
+0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,0x291,
+0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x294,0x1aca,0x1aca,0x1acd,0x294,0x294,
+0x1ad0,0x1ad0,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,0x294,
+0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b60,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x1b63,0x297,
+0x1b66,0x1b66,0x297,0x297,0x297,0x297,0x297,0x297,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,0x1b5d,
+0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,
+0x1b6c,0x1b69,0x1b69,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,0x29a,
+0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d,0x1b6f,0x1b6f,0x29d,
+0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x1b6f,0x29d,
+0x1b72,0x1b78,0x1b78,0x1b75,0x1b75,0x1b75,0x2a3,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,
+0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,
+0x1b75,0x2a3,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x1b75,0x2a3,0x2a3,0x2a3,0x2a3,0x2a3,
+0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7e,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
+0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x2a6,
+0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x1bf0,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,
+0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,
+0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x2a6,0x1b84,0x1b84,0x1b81,0x1b81,
+0x1b81,0x1b81,0x1b87,0x1b87,0x1b87,0x1b87,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,
+0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x2a9,0x1a9d,0x1a9d,0x1a9d,0x1a9d,
+0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1a9d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
-0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
-0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
-0x18c9,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,
-0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
-0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x94e,0x94e,
-0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x2d0,0x2d0,0x2d0,0x2d0,0x2d0,
-0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
-0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0x128d,0x128d,0x128d,0x2be,0x2be,
-0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,
-0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,
+0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x2ac,0x1b8a,0x1b8a,0x1b8a,0x1b8a,
+0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x1b8a,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x2ac,0x1554,0x1554,0x1554,0x1554,
+0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1554,0x1b93,0x1b93,0x1b93,0x1b93,
+0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b93,0x1b90,0x2af,0x2af,0x2af,0x2af,0x2af,
+0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x2af,0x1b9c,0x1b9c,0x1b9c,0x1b9c,
+0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x1b9c,0x2b2,
+0x1b9c,0x1b9c,0x2b2,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99,
+0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99,
+0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x1b99,0x2b2,0x1b99,0x1b99,0x2b2,0x2b2,0x2b2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,
+0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x2b5,0x2b5,0x1ba2,0x1ba2,0x1ba2,0x1ba2,
+0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x2b5,
+0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x2b5,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,
+0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,
+0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,
+0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x2b8,0x1bf3,0x1bf3,0x1bf3,0x1bf9,0x1bf9,0x1bf9,0x1bf9,
+0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bfc,0x1bfc,0x1bfc,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,
+0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x2bb,0x1bff,0x1bff,0x1bff,0x1bff,
+0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x1bff,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,
0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,
-0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0xb76,0xb76,0xb76,0xb76,
-0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,
-0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0x2c1,0x2c1,0x129f,0x129f,0x129f,0x129f,
-0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,
-0x129f,0x1b99,0x1b99,0x1b99,0x1b99,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x13b6,0x13b6,0x13b6,0x13b6,
-0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
-0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x2c7,0x2c7,0x1773,0x1773,0x2ca,0x2ca,
-0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x18c9,0x18c9,0x18c9,0x18c9,
-0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x3d8,0x3cc,0x3cc,0x3cc,
-0x3cc,0x3cc,0x3cc,0x3cc,0x3cc,0x3d8,0x3d8,0x3d8,0x3d8,0x3d2,0x110a,0x12e4,0x3db,0x918,0x91b,0x3c9,
-0x3c9,0x1107,0x12e1,0x12e1,0x3de,0x3de,0x3de,0x3de,0x3de,0x3de,0x3de,0x3de,0x1107,0x3cc,0x3cc,0x3d8,
-0xc9c,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,
-0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3cc,0x3cc,
-0x8a0,0x8a3,0x936,0x936,0x936,0x936,0x936,0x936,0x936,0x936,0x936,0x936,0x3d5,0xf6c,0xf69,0x12e7,
-0x12e7,0x12e7,0x12e7,0x12e7,0x14a6,0x110d,0x110d,0xebe,0xebe,0xd8f,0xebe,0xebe,0x3db,0x3db,0x3db,0x3db,
-0x3db,0x3db,0x3db,0x3db,0x3db,0x3de,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3de,0x3db,0x3db,
-0x3de,0x3db,0x3db,0x3db,0x3db,0x3db,0x12e1,0x12e4,0x3cf,0x3db,0x3d8,0x3d8,0x47a,0x47a,0x47a,0x47a,
-0x47a,0x47a,0x47a,0x47a,0x47a,0x12ed,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,
-0x47a,0x47a,0x47a,0x47a,0x47a,0x47a,0x12ed,0x1845,0x1845,0xf8a,0x46b,0x474,0x4b6,0x4b6,0x4b6,0x4b6,
-0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,0x4b6,
-0x4b6,0x4b6,0x4b6,0xb91,0xb91,0xd9b,0xd9b,0x8a6,0xd9e,0x13c8,0x13c8,0x13c8,0x4b9,0x4b9,0x4b9,0x4b9,
-0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,
-0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4b9,0x4bf,0x4bf,0x4bf,0x1122,
-0x1122,0x1122,0x1122,0x1122,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,
-0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,
-0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x4bc,0x111f,0x111f,0x111f,0x111f,0x111f,0x111f,0x4c2,0x4bf,0x4bf,0x4bf,
-0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,
-0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,0x4bf,
-0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,
-0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,
-0x4cb,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c8,0x990,0xfb7,0xfb7,0xfba,0xfb7,0x4cb,0x4c5,0x4cb,0x4c5,
-0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,
-0x4cb,0x4c5,0x4cb,0x4c5,0x4cb,0x4c5,0xfba,0xfb7,0xfba,0xfb7,0xfba,0xfb7,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4d7,0x4d7,0x4d7,0x4d7,
-0x4d7,0x4d7,0x4d7,0x4d7,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x4da,0x696,0x696,0x699,0x4f5,
-0x6a5,0x6a2,0x6a2,0x69f,0x51f,0x51f,0x4dd,0x4dd,0x4dd,0x4dd,0x4dd,0xb22,0x6a8,0x501,0x6c0,0x6c3,
-0x516,0x6a8,0x504,0x504,0x4f5,0x510,0x510,0x696,0x51c,0x519,0x69c,0x4ef,0x4e6,0x4e6,0x4e9,0x4e9,
-0x4e9,0x4e9,0x4e9,0x4ec,0x4e9,0x4e9,0x4e9,0x4e0,0x528,0x525,0x522,0x522,0x6b4,0x50a,0x507,0x6b1,
-0x6ae,0x6ab,0x6bd,0x4f8,0x6ba,0x6ba,0x50d,0x510,0x6b7,0x6b7,0x50d,0x510,0x4f2,0x4f5,0x4f5,0x4f5,
-0x513,0x4fe,0x4fb,0xba6,0xac5,0xac5,0xac2,0xac2,0xac2,0xac2,0xb9d,0xb9d,0xb9d,0xb9d,0xba3,0xcc9,
-0xcc6,0xdaa,0xdad,0xba0,0xdad,0xdad,0xdad,0xdad,0xdaa,0xdad,0xdad,0xb9a,0x54c,0x54c,0x54c,0x54c,
-0x54c,0x54c,0x54c,0x549,0x54f,0x72f,0x54c,0x993,0x9b4,0xac8,0xac8,0xac8,0xbac,0xbac,0xdb3,0xdb3,
-0xdb3,0xdb3,0x112b,0x112e,0x112e,0x1302,0x1494,0x14be,0x14c1,0x14c1,0x16c8,0x1848,0x55b,0x55b,0x573,0x6d5,
-0x558,0x6cf,0x55b,0x570,0x558,0x6d5,0x56a,0x573,0x573,0x573,0x56a,0x56a,0x573,0x573,0x573,0x6db,
-0x558,0x573,0x6d8,0x558,0x567,0x573,0x573,0x573,0x573,0x573,0x558,0x558,0x55e,0x6cf,0x6d2,0x558,
-0x573,0x558,0x6de,0x558,0x573,0x561,0x579,0x6e1,0x573,0x573,0x564,0x56a,0x573,0x573,0x576,0x573,
-0x56a,0x56d,0x56d,0x56d,0x56d,0xad1,0xace,0xccc,0xdbc,0xbc1,0xbc4,0xbc4,0xbbe,0xbbb,0xbbb,0xbbb,
-0xbbb,0xbc4,0xbc1,0xbc1,0xbc1,0xbc1,0xbb8,0xbbb,0xdb9,0xeca,0xecd,0xfc0,0x1131,0x1131,0x1131,0x6e7,
-0x6e4,0x57c,0x57f,0x57f,0x57f,0x57f,0x57f,0x6e4,0x6e7,0x6e7,0x6e4,0x57f,0x6ed,0x6ed,0x6ed,0x6ed,
-0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x6ed,0x588,0x588,0x588,0x588,0x6ea,0x6ea,0x6ea,0x6ea,
-0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x6ea,0x582,0x582,0x582,0x582,0x582,0x582,0x58e,0x58e,0x58e,0x58e,
-0x58e,0x58e,0x58e,0x58e,0x58b,0x58e,0x58e,0x58e,0x58e,0x58e,0x591,0x58b,0x58e,0x58e,0x58b,0x58b,
-0x58b,0x58b,0x58e,0x58e,0x6f0,0x6f0,0x58b,0x58b,0x58e,0x58e,0x58e,0x58e,0x58e,0x58e,0x58e,0x58e,
-0x58e,0x58e,0x58e,0x58e,0x58e,0x591,0x591,0x591,0x58e,0x58e,0x6f3,0x58e,0x6f3,0x58e,0x58e,0x58e,
-0x58e,0x58e,0x58e,0x58e,0x58b,0x58e,0x58b,0x58b,0x58b,0x58b,0x58b,0x58b,0x58e,0x58e,0x58b,0x6f0,
-0x58b,0x58b,0x58b,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xad7,0xbc7,0xbc7,0xbc7,0xbc7,
-0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0xbc7,0x6f6,0x594,0x6f6,0x6f6,0x597,0x594,0x594,0x6f6,
-0x6f6,0x597,0x594,0x6f6,0x597,0x594,0x594,0x6f6,0x594,0x6f6,0x5a3,0x5a0,0x594,0x6f6,0x594,0x594,
-0x594,0x594,0x6f6,0x594,0x594,0x6f6,0x6f6,0x6f6,0x6f6,0x594,0x594,0x6f6,0x597,0x6f6,0x597,0x6f6,
-0x6f6,0x6f6,0x6f6,0x6f6,0x6fc,0x59a,0x6f6,0x59a,0x59a,0x594,0x594,0x594,0x6f6,0x6f6,0x6f6,0x6f6,
-0x594,0x594,0x594,0x594,0x6f6,0x6f6,0x594,0x594,0x594,0x597,0x594,0x594,0x597,0x594,0x594,0x597,
-0x6f6,0x597,0x594,0x594,0x6f6,0x594,0x594,0x594,0x594,0x594,0x6f6,0x594,0x594,0x594,0x594,0x594,
-0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x6f9,0x6f6,0x597,0x594,0x6f6,0x6f6,0x6f6,0x6f6,
-0x594,0x594,0x6f6,0x6f6,0x594,0x597,0x6f9,0x6f9,0x597,0x597,0x594,0x594,0x597,0x597,0x594,0x594,
-0x597,0x597,0x594,0x594,0x594,0x594,0x594,0x594,0x597,0x597,0x6f6,0x6f6,0x597,0x597,0x6f6,0x6f6,
-0x597,0x597,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x6f6,0x594,0x594,
-0x594,0x6f6,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x6f6,0x594,0x594,0x594,0x594,0x594,0x594,
-0x597,0x597,0x597,0x597,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,
-0x594,0x594,0x594,0x6f6,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,
-0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,0x594,
-0x594,0x594,0x594,0x594,0x597,0x597,0x597,0x597,0x594,0x594,0x594,0x594,0x594,0x594,0x597,0x597,
-0x597,0x597,0x594,0x59d,0x594,0x594,0xbca,0xbca,0xbca,0xbca,0xbca,0xbca,0xbca,0xbca,0xbca,0xbca,
-0xbca,0xbca,0xbca,0xbca,0x5a6,0xada,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5af,0x5ac,0x5af,0x5ac,
-0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x6ff,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x7ef,0x7ef,
-0x5a6,0x5a6,0x5a6,0x5a6,0x5a9,0x5a9,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x7f5,0x7f2,0x5a6,
-0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,
-0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,0x5a6,
-0x5a6,0x5a6,0x5a6,0xada,0xbd0,0xada,0xada,0xada,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,
-0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,
-0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x5b2,0x708,0x708,0x708,0x708,0x708,0x708,0x708,0x708,
-0x708,0x708,0x5b8,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,
-0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xc2d,0xd3b,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,
-0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x5bb,0x5be,0x5be,0x5be,
-0x5be,0x5be,0x5be,0x5be,0x5be,0x5be,0x5be,0x5be,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,
-0x70e,0x70e,0x70e,0x70e,0x5be,0x5be,0x5be,0x5be,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,
-0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,
-0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x5c1,0x5c1,0x711,0x711,0x711,0x711,0xbd3,0xbd3,
-0xbd3,0xbd3,0xbd3,0xbd3,0xbd3,0xbd3,0xbd3,0xbd3,0x717,0x717,0x5c4,0x714,0x714,0x714,0x714,0x714,
-0x714,0x714,0x5c4,0x5c4,0x5c4,0x5c4,0x5c7,0x5c7,0x5c7,0x5c7,0x717,0x717,0x5c7,0x5c7,0x717,0x717,
-0x5c4,0x5c4,0x5c4,0x5c4,0x717,0x717,0x5c7,0x5c7,0x717,0x717,0x5c4,0x5c4,0x5c4,0x5c4,0x717,0x717,
-0x714,0x5c4,0x5c7,0x717,0x5c4,0x5c4,0x714,0x717,0x717,0x717,0x5c7,0x5c7,0x5c4,0x5c4,0x5c4,0x5c4,
-0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x5c4,0x717,0x714,0x717,0x714,0x5c4,0x5c7,
-0x5c7,0x5c7,0x5c7,0x5c7,0x5c7,0x5c4,0x5c4,0x714,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,0xae0,
-0xbd6,0xbd6,0xbd6,0xbd6,0xbd6,0xc45,0xc45,0xbd6,0x5cd,0x5cd,0x5cd,0x5cd,0x5ca,0x720,0x720,0x5ca,
-0x5ca,0x71a,0x5ca,0x5ca,0x5ca,0x5ca,0x71a,0x71a,0x5ca,0x5ca,0x5ca,0x5ca,0xd44,0xd44,0xbd9,0xbd9,
-0xdc5,0xae3,0x5cd,0x5cd,0x71d,0x5d0,0x71d,0x5cd,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,
-0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,
-0x5ca,0x5cd,0x5cd,0x5cd,0x5ca,0x5ca,0x5ca,0x5ca,0x720,0x5ca,0x720,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,
-0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x5ca,0x5ca,0x5ca,0x5ca,
-0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x5ca,0x720,0x720,0x5d3,0x720,0x71a,0x71a,0x5ca,0x71a,
-0x71d,0x71a,0x71a,0x5ca,0x71a,0x720,0x5d3,0x720,0xae3,0xae3,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,
-0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xdc2,0xe79,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,
-0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,0x5d9,0x1389,0x1389,0x1389,
-0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x14c7,0x5df,0x5df,0x5df,0x5df,0x1389,0x5d9,0x5d9,
-0x5df,0x5df,0x138c,0x138c,0x5e5,0x5e5,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,
-0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x1389,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,
-0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x726,0x5d9,0x5d9,
-0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x1389,0x5d9,0x1389,0x5d9,
-0x5d9,0x5d9,0x5d9,0x1389,0x1389,0x1389,0x5d9,0x1287,0x5d9,0x5d9,0x5d9,0x5e2,0x5e2,0x5e2,0x5e2,0x130e,
-0x130e,0x5d9,0x5dc,0x5dc,0x5df,0x5d9,0x5d9,0x5d9,0xbe2,0xbdf,0xbe2,0xbdf,0xbe2,0xbdf,0xbe2,0xbdf,
-0xbe2,0xbdf,0xbe2,0xbdf,0xbe2,0xbdf,0x723,0x723,0x723,0x723,0x723,0x723,0x723,0x723,0x723,0x723,
-0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,
-0x1389,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x1389,
-0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,
-0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x5fd,0x5fd,
-0x5fd,0x5fd,0x5fd,0x5fd,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
-0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
-0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,0xb34,
-0x606,0x606,0x94b,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x5fd,0x5fd,0xbe5,0xd68,0x1afd,0x1afd,
-0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,
-0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,
-0x606,0x600,0x606,0x600,0x606,0x600,0x606,0x600,0x606,0x600,0x606,0x600,0x603,0x609,0x606,0x600,
-0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x606,0x600,0x603,0x609,
-0x606,0x600,0x606,0x600,0x603,0x609,0x606,0x600,0x603,0x609,0x606,0x600,0x606,0x600,0x1311,0x1311,
-0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x1311,0x606,0x600,0x606,0x600,
-0x606,0x600,0x603,0x609,0x603,0x609,0x606,0x600,0x606,0x600,0x606,0x600,0x606,0x600,0x606,0x600,
-0x606,0x600,0x606,0x600,0x603,0x606,0x600,0x603,0x606,0x600,0x603,0x609,0x600,0x600,0x600,0x600,
-0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
-0x600,0x600,0x600,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x606,0x606,0x606,0x606,
-0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x600,0x600,0x600,
-0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x603,0x603,0x603,
-0x603,0x603,0x603,0x603,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x600,0x606,0x909,0x90c,
-0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,0x1afd,
-0x603,0x600,0x603,0x603,0x603,0x603,0x603,0x603,0x600,0x603,0x600,0x600,0x603,0x603,0x600,0x600,
-0x603,0x603,0x600,0x603,0x600,0x603,0x600,0x600,0x603,0x600,0x600,0x603,0x600,0x603,0x600,0x600,
-0x603,0x600,0x603,0x603,0x600,0x600,0x600,0x603,0x600,0x600,0x600,0x600,0x600,0x603,0x600,0x600,
-0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,0x600,
-0x600,0x600,0x600,0x600,0x603,0x603,0x600,0x600,0x603,0x600,0x603,0x600,0x600,0x600,0x600,0x600,
-0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,
-0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,0x603,
-0x603,0x603,0x603,0x609,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,
-0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,0x606,
-0x606,0x606,0x606,0x606,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,
-0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x609,0x606,0x606,0x606,0x606,0x606,0x606,0x606,
-0x606,0x606,0x606,0x606,0x60c,0x60c,0x60c,0x60c,0xfcc,0xfcc,0xfcc,0x14ca,0x14ca,0x14ca,0x14ca,0x14ca,
-0x14ca,0x14ca,0x16ce,0x16ce,0x855,0x85b,0x85b,0x867,0x867,0x858,0x84f,0x858,0x84f,0x858,0x84f,0x858,
-0x84f,0x858,0x84f,0x858,0x61b,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x618,
-0x61e,0x61b,0x615,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,
-0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x61b,0x615,0x618,
-0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,
-0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,0x61e,0x61b,0x615,0x618,
-0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,0x705,
-0x705,0x705,0x705,0x705,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,
-0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,0x702,
-0x702,0x702,0x702,0x702,0x702,0x702,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,
-0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x70b,0x708,0x708,0x708,0x708,0x708,0x708,0x708,0x708,
-0x708,0x708,0x708,0x708,0x708,0x708,0x708,0x708,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,
-0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,
-0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x70e,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,
-0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,
-0x729,0x729,0x729,0x729,0x729,0x729,0x729,0x729,0xc33,0x8b8,0x8b2,0x8af,0x8b5,0x8ac,0x73e,0x741,
-0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x741,0x8be,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,
-0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,
-0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x73e,0x8bb,0x8bb,0x744,0x8cd,0x8d0,0x8d6,
-0x7fb,0x807,0x8eb,0x804,0x8c4,0x8c1,0x8c4,0x8c1,0x8ca,0x8c7,0x8ca,0x8c7,0x8c4,0x8c1,0x801,0x8d6,
-0x8c4,0x8c1,0x8c4,0x8c1,0x8c4,0x8c1,0x8c4,0x8c1,0x8dc,0x8e2,0x8df,0x8df,0x74a,0x786,0x786,0x786,
-0x786,0x786,0x786,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x780,
-0x780,0x780,0x780,0x780,0x780,0x780,0x780,0x74d,0x768,0x747,0x76e,0x771,0x76b,0x783,0x783,0x783,
-0x783,0x783,0x783,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,
-0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x77d,0x74d,0x768,0x747,0x768,0xc36,0x7e9,0x7e9,0x7e9,0x7e9,
-0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,
-0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x7e9,0x1281,0x1281,
-0x1281,0x1281,0x1281,0x7ec,0x801,0x804,0x804,0x804,0x804,0x804,0x804,0x804,0x804,0x804,0x924,0x924,
-0x924,0x924,0x80a,0x80a,0x8d9,0x8e8,0x8e8,0x8e8,0x8e8,0x8e5,0x7fe,0x8d3,0xb07,0xb07,0xb07,0xc48,
-0xc66,0xc63,0xb25,0x8a9,0x810,0x80d,0x810,0x813,0x80d,0x810,0x80d,0x810,0x80d,0x810,0x80d,0x80d,
-0x80d,0x80d,0x80d,0x80d,0x810,0x810,0x80d,0x810,0x810,0x80d,0x810,0x810,0x80d,0x810,0x810,0x80d,
-0x810,0x810,0x80d,0x80d,0xc69,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,
-0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,
-0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x822,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81c,
-0x81c,0x81c,0x81c,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,
-0x81f,0x81f,0x81c,0x81c,0x81c,0x81c,0x81c,0x822,0x81c,0x822,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,
-0x81c,0x81c,0x822,0x81c,0x81c,0x81c,0x81c,0x81c,0x81f,0x822,0x822,0x81f,0x81f,0x81f,0x81f,0x8f1,
-0x8f4,0x825,0x828,0xc51,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
-0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
-0x82e,0x82e,0x82e,0x82e,0x831,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
-0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,0x82e,
-0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,
-0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0x83a,0xd4d,0xd4d,0xe7c,0x834,
-0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0xd47,0xd47,0xd47,0xd47,
+0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x2be,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,
+0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x1c02,0x2c1,0x2c1,0x2c1,0x2c1,
+0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x2c1,0x1c05,0x1c05,0x1c1a,0x1c11,0x1c17,0x1c17,0x1c17,0x1c17,
+0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x2c4,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,
+0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,0x1c17,
+0x1c11,0x1c11,0x1c05,0x1c05,0x1c05,0x1c05,0x1c05,0x2c4,0x2c4,0x2c4,0x1c11,0x1c11,0x1c05,0x1c14,0x1c08,0x1c1d,
+0x1c1d,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0b,0x1c0e,0x1c0e,0x1c0e,0x1c0e,
+0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x1c0e,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x2c4,0x1c26,0x1c26,0x1c26,0x1c26,
+0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c26,0x1c20,0x1c20,0x1c20,0x1c20,0x1c23,0x1c23,0x1c23,0x1c23,
+0x1c23,0x1c23,0x1c23,0x1c23,0x1c23,0x1c23,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2c7,0x2ca,0x2ca,0x2ca,0x2ca,
+0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,
+0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x18db,0x2dc,0x2dc,0x2dc,
+0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2dc,0x2ca,0x2ca,0x2ca,0x2ca,
+0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,
+0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x95d,0x95d,0x1c3b,0x1c3b,0x1c3b,0x1c3b,
+0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x2ca,0x2ca,0x2ca,0x2ca,
+0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0x2ca,0xc6c,0xc6c,0xc6c,0xc6c,
+0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0x129f,0x129f,0x129f,0x2cd,0x2cd,0xe94,0xe94,0xe94,0xe94,
+0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,
+0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,
+0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,
+0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0x2cd,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,
+0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,
+0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0x2d0,0x2d0,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,
+0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x1bab,0x1bab,0x1bab,
+0x1bab,0x1c29,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x2d3,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,
+0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,
+0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x2d6,0x2d6,0x1785,0x1785,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,
+0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x2d9,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,
+0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,
+0x1af4,0x1af4,0x1af4,0x2df,0x2df,0x2df,0x2df,0x2df,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,
+0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x3e7,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,0x3db,
+0x3db,0x3e7,0x3e7,0x3e7,0x3e7,0x3e1,0x111f,0x12f6,0x3ea,0x927,0x92a,0x3d8,0x3d8,0x111c,0x12f3,0x12f3,
+0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x3ed,0x111c,0x3db,0x3db,0x3e7,0xcae,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3db,0x3db,0x8af,0x8b2,0x945,0x945,
+0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x945,0x3e4,0xf7e,0xf7b,0x12f9,0x12f9,0x12f9,0x12f9,0x12f9,
+0x14b8,0x1122,0x1122,0xed0,0xed0,0xda1,0xed0,0xed0,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ed,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ed,0x3ea,0x3ea,0x3ea,
+0x3ea,0x3ea,0x12f3,0x12f6,0x3de,0x3ea,0x3e7,0x3e7,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,
+0x489,0x12ff,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,0x489,
+0x489,0x489,0x12ff,0x1857,0x1857,0xf9c,0x47a,0x483,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,
+0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0x4c5,0xba3,
+0xba3,0xdb0,0xdb0,0x8b5,0xdad,0x13da,0x13da,0x13da,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,
+0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,
+0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4c8,0x4ce,0x4ce,0x4ce,0x1137,0x1137,0x1137,0x1137,0x1137,
+0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,
+0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,0x4cb,
+0x4cb,0x4cb,0x1134,0x1134,0x1134,0x1134,0x1134,0x1134,0x4d1,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,
+0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4ce,0x4da,0x4d4,0x4da,0x4d4,
+0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,
+0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4d4,0x4d4,
+0x4d4,0x4d4,0x4d7,0x9a2,0xfc9,0xfc9,0xfcc,0xfc9,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,
+0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,0x4da,0x4d4,
+0x4da,0x4d4,0xfcc,0xfc9,0xfcc,0xfc9,0xfcc,0xfc9,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,0x4e6,
+0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x4e9,0x6a5,0x6a5,0x6a8,0x504,0x6b4,0x6b1,0x6b1,0x6ae,
+0x52e,0x52e,0x4ec,0x4ec,0x4ec,0x4ec,0x4ec,0xb34,0x6b7,0x510,0x6cf,0x6d2,0x525,0x6b7,0x513,0x513,
+0x504,0x51f,0x51f,0x6a5,0x52b,0x528,0x6ab,0x4fe,0x4f5,0x4f5,0x4f8,0x4f8,0x4f8,0x4f8,0x4f8,0x4fb,
+0x4f8,0x4f8,0x4f8,0x4ef,0x537,0x534,0x531,0x531,0x6c3,0x519,0x516,0x6c0,0x6bd,0x6ba,0x6cc,0x507,
+0x6c9,0x6c9,0x51c,0x51f,0x6c6,0x6c6,0x51c,0x51f,0x501,0x504,0x504,0x504,0x522,0x50d,0x50a,0xbb8,
+0xad7,0xad7,0xad4,0xad4,0xad4,0xad4,0xbaf,0xbaf,0xbaf,0xbaf,0xbb5,0xcdb,0xcd8,0xdbc,0xdbf,0xbb2,
+0xdbf,0xdbf,0xdbf,0xdbf,0xdbc,0xdbf,0xdbf,0xbac,0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x55b,0x558,
+0x55e,0x73e,0x55b,0x9a5,0x9c6,0xada,0xada,0xada,0xbbe,0xbbe,0xdc5,0xdc5,0xdc5,0xdc5,0x1140,0x1143,
+0x1143,0x1314,0x14a6,0x14d0,0x14d3,0x14d3,0x16da,0x185a,0x56a,0x56a,0x582,0x6e4,0x567,0x6de,0x56a,0x57f,
+0x567,0x6e4,0x579,0x582,0x582,0x582,0x579,0x579,0x582,0x582,0x582,0x6ea,0x567,0x582,0x6e7,0x567,
+0x576,0x582,0x582,0x582,0x582,0x582,0x567,0x567,0x56d,0x6de,0x6e1,0x567,0x582,0x567,0x6ed,0x567,
+0x582,0x570,0x588,0x6f0,0x582,0x582,0x573,0x579,0x582,0x582,0x585,0x582,0x579,0x57c,0x57c,0x57c,
+0x57c,0xae3,0xae0,0xcde,0xdce,0xbd3,0xbd6,0xbd6,0xbd0,0xbcd,0xbcd,0xbcd,0xbcd,0xbd6,0xbd3,0xbd3,
+0xbd3,0xbd3,0xbca,0xbcd,0xdcb,0xedc,0xedf,0xfd2,0x1146,0x1146,0x1146,0x6f6,0x6f3,0x58b,0x58e,0x58e,
+0x58e,0x58e,0x58e,0x6f3,0x6f6,0x6f6,0x6f3,0x58e,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,0x6fc,
+0x6fc,0x6fc,0x6fc,0x6fc,0x597,0x597,0x597,0x597,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,0x6f9,
+0x6f9,0x6f9,0x591,0x591,0x591,0x591,0x591,0x591,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,
+0x59a,0x59d,0x59d,0x59d,0x59d,0x59d,0x5a0,0x59a,0x59d,0x59d,0x59a,0x59a,0x59a,0x59a,0x59d,0x59d,
+0x6ff,0x6ff,0x59a,0x59a,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,
+0x59d,0x5a0,0x5a0,0x5a0,0x59d,0x59d,0x702,0x59d,0x702,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,0x59d,
+0x59a,0x59d,0x59a,0x59a,0x59a,0x59a,0x59a,0x59a,0x59d,0x59d,0x59a,0x6ff,0x59a,0x59a,0x59a,0xae9,
+0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xae9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,0xbd9,
+0xbd9,0xbd9,0xbd9,0xbd9,0x705,0x5a3,0x705,0x705,0x5a6,0x5a3,0x5a3,0x705,0x705,0x5a6,0x5a3,0x705,
+0x5a6,0x5a3,0x5a3,0x705,0x5a3,0x705,0x5b2,0x5af,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,
+0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705,0x5a6,0x705,0x5a6,0x705,0x705,0x705,0x705,0x705,
+0x70b,0x5a9,0x705,0x5a9,0x5a9,0x5a3,0x5a3,0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a3,
+0x705,0x705,0x5a3,0x5a3,0x5a3,0x5a6,0x5a3,0x5a3,0x5a6,0x5a3,0x5a3,0x5a6,0x705,0x5a6,0x5a3,0x5a3,
+0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x708,0x705,0x5a6,0x5a3,0x705,0x705,0x705,0x705,0x5a3,0x5a3,0x705,0x705,
+0x5a3,0x5a6,0x708,0x708,0x5a6,0x5a6,0x5a3,0x5a3,0x5a6,0x5a6,0x5a3,0x5a3,0x5a6,0x5a6,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x705,0x705,0x5a6,0x5a6,0x705,0x705,0x5a6,0x5a6,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x705,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,
+0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,
+0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a3,0x5a6,0x5a6,0x5a6,0x5a6,0x5a3,0x5ac,
+0x5a3,0x5a3,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,
+0x5b5,0xaec,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5be,0x5bb,0x5be,0x5bb,0x5b5,0x5b5,0x5b5,0x5b5,
+0x5b5,0x5b5,0x70e,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x7fe,0x7fe,0x5b5,0x5b5,0x5b5,0x5b5,
+0x5b8,0x5b8,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x804,0x801,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,
+0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,
+0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0x5b5,0xaec,
+0xbe2,0xaec,0xaec,0xaec,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,
+0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,0x5c1,
+0x5c1,0x5c1,0x5c1,0x5c1,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x5c7,0xc3f,
+0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,0xc3f,
+0xc3f,0xc3f,0xc3f,0xd4d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,
+0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x5ca,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,0x5cd,
+0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,
+0x5cd,0x5cd,0x5cd,0x5cd,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,
+0x71d,0x71d,0x71d,0x71d,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,0x720,
+0x720,0x720,0x720,0x720,0x5d0,0x5d0,0x720,0x720,0x720,0x720,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,0xbe5,
+0xbe5,0xbe5,0xbe5,0xbe5,0x726,0x726,0x5d3,0x723,0x723,0x723,0x723,0x723,0x723,0x723,0x5d3,0x5d3,
+0x5d3,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x726,0x726,0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3,0x5d3,0x5d3,
+0x726,0x726,0x5d6,0x5d6,0x726,0x726,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x726,0x723,0x5d3,0x5d6,0x726,
+0x5d3,0x5d3,0x723,0x726,0x726,0x726,0x5d6,0x5d6,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,
+0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x5d3,0x726,0x723,0x726,0x723,0x5d3,0x5d6,0x5d6,0x5d6,0x5d6,0x5d6,
+0x5d6,0x5d3,0x5d3,0x723,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xaf2,0xbe8,0xbe8,0xbe8,0xbe8,
+0xbe8,0xc57,0xc57,0xbe8,0x5dc,0x5dc,0x5dc,0x5dc,0x5d9,0x72f,0x72f,0x5d9,0x5d9,0x729,0x5d9,0x5d9,
+0x5d9,0x5d9,0x729,0x729,0x5d9,0x5d9,0x5d9,0x5d9,0xd56,0xd56,0xbeb,0xbeb,0xdd7,0xaf5,0x5dc,0x5dc,
+0x72c,0x5df,0x72c,0x5dc,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,
+0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5dc,0x5dc,0x5dc,
+0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x5d9,0x72f,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x807,0x807,0x807,0x807,
+0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x807,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,0x5d9,
+0x5d9,0x5d9,0x5d9,0x5d9,0x72f,0x72f,0x5e2,0x72f,0x729,0x729,0x5d9,0x729,0x72c,0x729,0x729,0x5d9,
+0x729,0x72f,0x5e2,0x72f,0xaf5,0xaf5,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,
+0xbee,0xbee,0xdd4,0xe8b,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,
+0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e5,0x5e8,0x139b,0x139b,0x139b,0x5e8,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x14d9,0x5ee,0x5ee,0x5ee,0x5ee,0x139b,0x5e8,0x5e8,0x5ee,0x5ee,0x139e,0x139e,
+0x5f4,0x5f4,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x735,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x139b,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,
+0x139b,0x139b,0x5e8,0x1299,0x5e8,0x5e8,0x5e8,0x5f1,0x5f1,0x5f1,0x5f1,0x1320,0x1320,0x5e8,0x5eb,0x5eb,
+0x5ee,0x5e8,0x5e8,0x5e8,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,0xbf4,0xbf1,
+0xbf4,0xbf1,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x732,0x5e8,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x5e8,0x5e8,0x5e8,
+0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x5e8,0x139b,0x615,0x615,0x615,0x615,
+0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,
+0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x60c,0x60c,0x60c,0x60c,0x60c,0x60c,
+0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,
+0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0xb46,0xb46,0xb46,0xb46,
+0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0x615,0x615,0x95a,0x615,
+0x615,0x615,0x615,0x615,0x615,0x615,0x60c,0x60c,0xbf7,0xd7a,0x1b0f,0x1b0f,0x612,0x618,0x615,0x60f,
+0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,
+0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,0x60f,
+0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,
+0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,
+0x612,0x618,0x615,0x60f,0x612,0x618,0x615,0x60f,0x615,0x60f,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,
+0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x1323,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x612,0x618,
+0x612,0x618,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,0x615,0x60f,
+0x612,0x615,0x60f,0x612,0x615,0x60f,0x612,0x618,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,
+0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,
+0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,
+0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,
+0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612,0x612,0x612,0x612,
+0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x60f,0x615,0x918,0x91b,0x1b0f,0x1b0f,0x1b0f,0x1b0f,
+0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x1b0f,0x612,0x60f,0x612,0x612,
+0x612,0x612,0x612,0x612,0x60f,0x612,0x60f,0x60f,0x612,0x612,0x60f,0x60f,0x612,0x612,0x60f,0x612,
+0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x612,
+0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,
+0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,0x60f,
+0x612,0x612,0x60f,0x60f,0x612,0x60f,0x612,0x60f,0x60f,0x60f,0x60f,0x60f,0x612,0x612,0x612,0x612,
+0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,
+0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x612,0x618,
+0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,
+0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,
+0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,0x618,
+0x618,0x618,0x618,0x618,0x618,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,0x615,
+0x61b,0x61b,0x61b,0x61b,0xfde,0xfde,0xfde,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x14dc,0x16e0,0x16e0,
+0x864,0x86a,0x86a,0x876,0x876,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,0x85e,0x867,
+0x62a,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x62a,
+0x624,0x627,0x62d,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,
+0x62d,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,
+0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,
+0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x62d,0x62a,0x624,0x627,0x714,0x714,0x714,0x714,
+0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,0x714,
+0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,
+0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,0x711,
+0x711,0x711,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,0x71a,
+0x71a,0x71a,0x71a,0x71a,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,0x717,
+0x717,0x717,0x717,0x717,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,
+0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,0x71d,
+0x71d,0x71d,0x71d,0x71d,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,
+0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,0x738,
+0x738,0x738,0x738,0x738,0xc45,0x8c7,0x8c1,0x8be,0x8c4,0x8bb,0x74d,0x750,0x750,0x750,0x750,0x750,
+0x750,0x750,0x750,0x750,0x8cd,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,
+0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,
+0x74d,0x74d,0x74d,0x74d,0x74d,0x74d,0x8ca,0x8ca,0x753,0x8dc,0x8df,0x8e5,0x80a,0x816,0x8fa,0x813,
+0x8d3,0x8d0,0x8d3,0x8d0,0x8d9,0x8d6,0x8d9,0x8d6,0x8d3,0x8d0,0x810,0x8e5,0x8d3,0x8d0,0x8d3,0x8d0,
+0x8d3,0x8d0,0x8d3,0x8d0,0x8eb,0x8f1,0x8ee,0x8ee,0x759,0x795,0x795,0x795,0x795,0x795,0x795,0x78f,
+0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,0x78f,
+0x78f,0x78f,0x78f,0x75c,0x777,0x756,0x77d,0x780,0x77a,0x792,0x792,0x792,0x792,0x792,0x792,0x78c,
+0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,0x78c,
+0x78c,0x78c,0x78c,0x75c,0x777,0x756,0x777,0xc48,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,
+0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,
+0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x7f8,0x1293,0x1293,0x1293,0x1293,0x1293,0x7fb,
+0x810,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x813,0x933,0x933,0x933,0x933,0x819,0x819,
+0x8e8,0x8f7,0x8f7,0x8f7,0x8f7,0x8f4,0x80d,0x8e2,0xb19,0xb19,0xb19,0xc5a,0xc78,0xc75,0xb37,0x8b8,
+0x81f,0x81c,0x81f,0x822,0x81c,0x81f,0x81c,0x81f,0x81c,0x81f,0x81c,0x81c,0x81c,0x81c,0x81c,0x81c,
+0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81f,0x81f,0x81c,0x81c,
+0xc7b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x82b,0x82e,0x82b,0x82e,0x82b,
+0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,
+0x82e,0x82b,0x82e,0x831,0x82b,0x82e,0x82b,0x82e,0x82b,0x82e,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,
+0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82e,0x82e,0x82b,0x82b,
+0x82b,0x82b,0x82b,0x831,0x82b,0x831,0x82b,0x831,0x82b,0x82b,0x82b,0x82b,0x82b,0x82b,0x831,0x82b,
+0x82b,0x82b,0x82b,0x82b,0x82e,0x831,0x831,0x82e,0x82e,0x82e,0x82e,0x900,0x903,0x834,0x837,0xc63,
0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,
-0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x1a46,
-0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,
-0x903,0x840,0x840,0x840,0x840,0x840,0x840,0xd50,0xd50,0xd50,0xd50,0x906,0x906,0x906,0x906,0x906,
-0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,
-0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,0x840,
-0x840,0x840,0xd50,0xd50,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,
-0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,0x843,
-0x843,0x843,0x843,0x843,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x846,0x846,0x846,0x846,
-0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,
-0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0x846,0xe7f,0xe7f,
-0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,0xe7f,
-0xe7f,0xe7f,0xe7f,0xe7f,0x10ef,0x10ef,0x10ef,0x10ef,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,
+0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,
+0x840,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,
+0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x83d,0x849,0x849,0x849,0x849,
0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,
-0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x84c,0x84c,0x849,0x84c,0x849,0x84c,
-0x84c,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x84c,0x849,0x84c,0x849,0x84c,
-0x84c,0x849,0x849,0x84c,0x84c,0x84c,0x849,0x849,0x849,0x849,0x1485,0x1485,0xc5a,0xc5a,0xc5a,0xc5a,
-0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0x8fd,0x8fd,0x8fd,0x8fd,
-0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,
-0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x8fd,0x12c0,0x12c0,0x12c0,0x12c0,
-0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0x1269,0xd47,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,
-0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,
-0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,
-0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0x900,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,
-0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0xc54,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,
-0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,0x903,
-0x903,0x903,0x903,0x903,0x903,0x903,0x903,0xd50,0x98a,0x96c,0x96c,0x96c,0x96c,0x966,0x96c,0x96c,
-0x97e,0x96c,0x96c,0x969,0x975,0x97b,0x97b,0x97b,0x97b,0x97b,0x97e,0x966,0x972,0x966,0x966,0x966,
-0x95d,0x95d,0x966,0x966,0x966,0x966,0x966,0x966,0x981,0x981,0x981,0x981,0x981,0x981,0x981,0x981,
-0x981,0x981,0x966,0x966,0x966,0x966,0x966,0x966,0x966,0x966,0x966,0x966,0x969,0x95d,0x966,0x95d,
-0x966,0x95d,0x978,0x96f,0x978,0x96f,0x987,0x987,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,
-0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,
-0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x996,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,
-0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,
-0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x999,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,
-0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,
-0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x99c,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,
-0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,
-0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x99f,0x99f,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,
-0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,
-0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a2,0x9a2,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,
-0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,
-0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a5,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,
+0x849,0x849,0x849,0x849,0x849,0x849,0x849,0x849,0xd5f,0xd5f,0xe8e,0x843,0x90c,0x90c,0x90c,0x90c,
+0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0xd59,0xd59,0xd59,0xd59,0x84c,0x84c,0x84c,0x84c,
+0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,
+0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x84c,0x1a58,0x912,0x912,0x912,0x912,
+0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x84f,0x84f,0x84f,
+0x84f,0x84f,0x84f,0xd62,0xd62,0xd62,0xd62,0x915,0x915,0x915,0x915,0x915,0x84f,0x84f,0x84f,0x84f,
+0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,
+0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0x84f,0xd62,0xd62,
+0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,
+0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,0x852,
+0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,
+0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,
+0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0x855,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,
+0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,0xe91,
+0x1104,0x1104,0x1104,0x1104,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,
+0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x858,
+0x858,0x858,0x858,0x858,0x858,0x858,0x85b,0x85b,0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x858,
+0x858,0x858,0x858,0x858,0x858,0x858,0x858,0x85b,0x858,0x85b,0x858,0x85b,0x85b,0x858,0x858,0x85b,
+0x85b,0x85b,0x858,0x858,0x858,0x858,0x1497,0x1497,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,
+0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,
+0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,
+0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x90c,0x12d2,0x12d2,0x12d2,0x12d2,0x127b,0x127b,0x127b,0x127b,
+0x127b,0x127b,0x127b,0x127b,0xd59,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,
+0xc66,0xc66,0xc66,0xc66,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,
+0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,0x90f,
+0x90f,0x90f,0x90f,0x90f,0x90f,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,0xc66,
+0xc66,0xc66,0xc66,0xc66,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,
+0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,0x912,
+0x912,0x912,0x912,0xd62,0x99c,0x97e,0x97e,0x97e,0x97e,0x978,0x97e,0x97e,0x990,0x97e,0x97e,0x97b,
+0x987,0x98d,0x98d,0x98d,0x98d,0x98d,0x990,0x978,0x984,0x978,0x978,0x978,0x96c,0x96c,0x978,0x978,
+0x978,0x978,0x978,0x978,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x993,0x978,0x978,
+0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x978,0x97b,0x96c,0x978,0x96c,0x978,0x96c,0x98a,0x981,
+0x98a,0x981,0x999,0x999,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,
0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,
-0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9a8,0x9ab,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,
+0x9a8,0x9a8,0x9a8,0x9a8,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,
+0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,0x9ab,
+0x9ab,0x9ab,0x9ab,0x9ab,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,
0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,
-0x9ae,0x9ae,0x9ae,0x9ae,0x9ab,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,
-0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,0x9ae,
-0xa3b,0xa3b,0xfb1,0xa3b,0xa3b,0xa3b,0xa3e,0xa3b,0xfb1,0xa3b,0xa3b,0xfa8,0xa35,0xa29,0xa29,0xa29,
-0xa29,0xa38,0xa29,0xf99,0xf99,0xf99,0xa29,0xa2c,0xa35,0xa2f,0xf9f,0xfab,0xfab,0xf99,0xf99,0xfb1,
-0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xb2b,0xa41,0xa41,0xa32,0xa32,0xa32,0xa32,
-0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa38,0xa38,0xa29,0xa29,0xfb1,0xfb1,0xfb1,0xfb1,0xf99,0xf99,
-0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
-0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,0xa3b,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xda7,0xa50,0xa50,0xa50,0xa50,
-0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa50,0xa56,0xa56,0xa56,0xa56,
-0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,
-0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa56,0xa5c,0xa5c,0xa5c,0xa5c,
-0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa59,0xa5f,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,
-0xa5c,0xa5c,0xa5c,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1128,0x1125,0xa5c,0xa5c,0xa5c,
-0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,
-0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,0xa5c,
-0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,
-0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,0xa71,
-0xa95,0xa95,0xa95,0xa98,0xa98,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,
-0xa95,0xa95,0xa95,0xa95,0xa7d,0xa7d,0xa92,0xa74,0xa74,0xa74,0xa74,0xa74,0xa74,0xa74,0xa92,0xa92,
-0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,
-0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,0xa95,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xaa1,0xaa1,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab9,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,
-0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xab6,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,
-0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,0xada,
-0xada,0xada,0xada,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,
-0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,
-0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xae6,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,
+0x9ae,0x9ae,0x9ae,0x9ae,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,
+0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,
+0x9b7,0x9b7,0x9b1,0x9b1,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,
+0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,
+0x9ba,0x9ba,0x9b4,0x9b4,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,
+0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,0x9b7,
+0x9b7,0x9b7,0x9b7,0x9b7,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,
+0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,0x9ba,
+0x9ba,0x9ba,0x9ba,0x9ba,0x9bd,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,
+0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,
+0x9bd,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,
+0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0x9c0,0xa4d,0xa4d,0xfc3,0xa4d,
+0xa4d,0xa4d,0xa50,0xa4d,0xfc3,0xa4d,0xa4d,0xfba,0xa47,0xa3b,0xa3b,0xa3b,0xa3b,0xa4a,0xa3b,0xfab,
+0xfab,0xfab,0xa3b,0xa3e,0xa47,0xa41,0xfb1,0xfbd,0xfbd,0xfab,0xfab,0xfc3,0xb3d,0xb3d,0xb3d,0xb3d,
+0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xb3d,0xa53,0xa53,0xa44,0xa44,0xa44,0xa44,0xa4d,0xa4d,0xa4d,0xa4d,
+0xa4d,0xa4d,0xa4a,0xa4a,0xa3b,0xa3b,0xfc3,0xfc3,0xfc3,0xfc3,0xfab,0xfab,0xa4d,0xa4d,0xa4d,0xa4d,
+0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,
+0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa4d,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xdb9,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,
+0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa62,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,
+0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,
+0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa68,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,
+0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6b,0xa71,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0x113d,
+0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113d,0x113a,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,
+0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,
+0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa6e,0xa83,0xa83,0xa83,0xa83,
+0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,
+0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xa83,0xaa7,0xaa7,0xaa7,0xaaa,
+0xaaa,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,
+0xa8f,0xa8f,0xaa4,0xa86,0xa86,0xa86,0xa86,0xa86,0xa86,0xa86,0xaa4,0xaa4,0xaa7,0xaa7,0xaa7,0xaa7,
+0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,
+0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xaa7,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xab3,0xab3,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xacb,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,0xac8,
+0xac8,0xac8,0xac8,0xac8,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,
+0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xaec,0xbe2,
+0xbe2,0xbe2,0xbe2,0xbe2,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,
0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,
-0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xaf8,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,
-0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,
-0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xafe,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,
+0xaf8,0xaf8,0xaf8,0xaf8,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,
0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,0xb0a,
-0x138f,0x138f,0x138f,0x1ac1,0x1ac1,0x1ac1,0x1ac1,0x1ac1,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,
-0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,
-0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0xb0d,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,
-0x1ac4,0x1ac4,0x1ac4,0x1ac4,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
-0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb13,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
+0xb0a,0xb0a,0xb0a,0xb0a,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,
-0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb10,0xb16,0xb16,0xc57,0xc57,
-0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,
-0xc57,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb16,0xb3a,0xb3a,0xb3a,0xb3a,
-0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,
-0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0xb3a,0x14cd,0xb43,0xb43,0xb43,0xb43,
-0xb43,0xb43,0xcdb,0xcdb,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,
-0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xb40,0xcd8,0xcd8,
-0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,
-0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,
-0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,0xb43,
-0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,
-0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,0xb46,
-0xb55,0xb55,0xb55,0xb55,0xb55,0xb4c,0xb58,0xb5e,0xb5e,0xb5e,0xb52,0xb52,0xb52,0xb5b,0xb4f,0xb4f,
-0xb4f,0xb4f,0xb4f,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb49,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb55,0xb55,0xb5e,0xb5e,0xb5e,0xb52,0xb52,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,0xb5e,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb5e,0xb5e,0xb5e,0xb5e,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb52,0xb52,0xb52,
+0xb10,0xb10,0xb10,0xb10,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,
+0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0xb1c,0x13a1,0x13a1,0x13a1,0x1ad3,
+0x1ad3,0x1ad3,0x1ad3,0x1ad3,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,
+0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,
+0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0xb1f,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,0x1ad6,
+0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,
+0xb22,0xb22,0xb22,0xb22,0xb22,0xb25,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,
+0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,
+0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb22,0xb28,0xb28,0xc69,0xc69,0xb28,0xb28,0xb28,0xb28,
+0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xc69,0xb28,0xb28,0xb28,
+0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb28,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,
+0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,
+0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0xb4c,0x14df,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xced,0xced,
0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,
-0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0x16d1,0x16d1,0xb6a,0xb61,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb61,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb61,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb61,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb61,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
+0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xb52,0xcea,0xcea,0xd38,0xd38,0xd38,0xd38,
+0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xb55,0xb55,0xb55,0xb55,
+0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,
+0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb55,0xb58,0xb58,0xb58,0xb58,
+0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,
+0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb58,0xb67,0xb67,0xb67,0xb67,
+0xb67,0xb5e,0xb6a,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb6d,0xb61,0xb61,0xb61,0xb61,0xb61,0xb5b,
+0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb5b,0xb70,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64,
0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb67,0xb67,
+0xb70,0xb70,0xb70,0xb64,0xb64,0xb70,0xb70,0xb70,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64,
0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,
-0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb6a,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,
-0xb67,0xb67,0xb67,0xb67,0xb6a,0xb6a,0xb6a,0xb6a,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,
-0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,
-0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb6d,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,
-0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,
-0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0xb73,0x1aca,0x1aca,0x1aca,0x1aca,0x1aca,
-0x1aca,0x1aca,0x1b96,0x1b96,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,
+0xb64,0xb64,0xb70,0xb70,0xb70,0xb70,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xb67,0xb67,0xb67,0xb67,0xb67,0xb67,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,
+0xb64,0xb64,0xb64,0xb64,0xb64,0xb64,0x16e3,0x16e3,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb73,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb76,0xb76,0xb76,0xb76,
0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,
-0xb76,0xb76,0xb76,0xb76,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,
-0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbd0,0xbcd,0xbd0,0xbcd,0xbcd,0xbcd,0xbcd,
-0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xbcd,0xccf,0xcd2,0xdbf,0xdbf,0xdbf,
-0xdbf,0xdbf,0xdbf,0xdbf,0xdbf,0xdbf,0xdbf,0xdbf,0xed6,0xed6,0xed6,0xed6,0xbdc,0xbdc,0xbdc,0xbdc,
-0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xbdc,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xcd5,0xdc2,0xe76,
-0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xfc6,0x1260,0x1260,0xdcb,0xdcb,0xdcb,0xdcb,
-0xdcb,0xdd1,0xdce,0xee8,0xee8,0xee8,0xee8,0x13ce,0xfd8,0x13ce,0x131a,0x131a,0xc0f,0xc0f,0xc0f,0xc0f,
-0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc0f,0xc3c,0xc39,
-0xc3c,0xc39,0xc3c,0xc39,0x10e9,0x10e6,0xfde,0xfdb,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,
-0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc12,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,
-0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,
-0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc15,0xc18,0xc18,0xc18,0xc1e,0xc1b,0xc42,0xc3f,0xc1e,
-0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,0xc1b,0xc1e,
-0xc1b,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,
-0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,
-0xc18,0xc18,0xc18,0xc18,0xc1e,0xc1b,0xc1e,0xc1b,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,
-0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,0xc18,
-0xc18,0xc18,0xc18,0xc18,0xc1e,0xc1b,0xc18,0xc18,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,
-0xc21,0xc21,0xc21,0xc21,0xc27,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,
-0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,
-0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc27,0xc27,0xc27,0xc21,0xc21,0xc21,0xc21,0xc21,
-0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,
-0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc24,0xc21,0xc21,0xc21,0xc5a,0xc5a,0xc5a,0xc5a,
-0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,
-0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xc5a,0xcd5,0xd41,0xdc2,0xdc2,
-0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xe76,0xe76,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xdc2,0xed9,0xfc6,
-0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0xfc6,0x1284,0x1284,0x1263,0xcf9,0xcf9,0xcf9,0xcf9,
-0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,
-0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xcf9,0xd08,0xd08,0xd08,0xd08,
-0xd08,0xd08,0xcff,0xcff,0xcff,0xcff,0xcff,0xcfc,0xd11,0xd11,0xd11,0xd0b,0xd11,0xd11,0xd11,0xd11,
-0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd0b,0xd11,0xd11,0xd11,0xd11,0xd05,0xd05,0xd0e,0xd0e,
-0xd0e,0xd0e,0xd02,0xd02,0xd02,0xd02,0xd02,0xd08,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,
-0xdd7,0xdd7,0xdd7,0xdd7,0xdd4,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xdd7,0xd11,0xd11,0xd11,0xd11,
-0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd0b,0xd11,0xd11,0xd11,0xd11,0xd11,
-0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd11,0xd05,0xd05,0xd05,0xd08,0xd08,0xd08,0xd08,
-0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,
-0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd08,0xd14,0xd14,0xd14,0xd14,
-0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xd14,0xdda,0xdda,0xdda,0xdda,0xdda,0xdda,
-0xeeb,0xeeb,0xeeb,0xeeb,0xeeb,0xeeb,0xeeb,0x10f2,0x10f2,0xfe1,0xfe1,0xfe1,0xd17,0xd17,0xd17,0xd17,
-0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,
-0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd17,0xd1d,0xd1d,0xd1d,0xd1d,
-0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,
-0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd1d,0xd26,0xd26,0xd26,0xd26,
-0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,
-0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd32,0xd32,0xd32,0xd32,
-0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,
-0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd32,0xd3e,0xd3e,0xd3e,0xd3e,
-0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,
-0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xd3e,0xde0,0xde0,0xde0,0xde0,
-0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,
-0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde0,0xde6,0xde6,0xde6,0xde6,
-0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,
-0xde6,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde3,0xde6,0xde6,0xde6,0xde6,
-0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,
-0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xde6,0xea6,0xea6,0xdf8,0xdf8,
-0xeee,0xeee,0xeee,0xeee,0xeee,0xeee,0xeee,0xfed,0xfed,0xfed,0xfed,0xfed,0xfea,0xfea,0xfea,0xfea,
-0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xfea,0xe07,0xe04,0xe07,0xe04,
-0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,
-0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe07,0xe04,0xe13,0xe13,0xe13,0xe13,
-0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,
-0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe13,0xe19,0xe19,0xe19,0xe19,
-0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0x1b0c,0xe16,0xe16,0xe16,0xe16,
-0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,
-0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0xe16,0x1b09,0xe19,0xe19,0xe19,0xe19,
-0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,
-0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xe19,0xea0,0xea0,0xea0,0xea0,
-0xea0,0xea0,0xea0,0xea0,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,0xe31,
-0xe31,0xe31,0xe31,0xef1,0xef1,0xef1,0xef1,0xff0,0xff0,0xff0,0xff0,0xff0,0xe3a,0xe3a,0xe3a,0xe3a,
-0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,
-0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe3a,0xe43,0xe43,0xe43,0xe43,
-0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,
-0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe4c,0xe4c,0xe4c,0xe4c,
+0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb76,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb7c,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,0xb79,
+0xb7c,0xb7c,0xb7c,0xb7c,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,
+0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,0xb7f,
+0xb7f,0xb7f,0xb7f,0xb7f,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,
+0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,
+0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0xb85,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1ba8,0x1ba8,
+0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,
+0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,0xb88,
+0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,
+0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbe2,0xbdf,0xbe2,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,
+0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xbdf,0xce1,0xce4,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,0xdd1,
+0xdd1,0xdd1,0xdd1,0xdd1,0xee8,0xee8,0xee8,0xee8,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,0xbee,
+0xbee,0xbee,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xce7,0xdd4,0xe88,0xdd4,0xdd4,0xdd4,0xdd4,
+0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xfd8,0x1272,0x1272,0xddd,0xddd,0xddd,0xddd,0xddd,0xde3,0xde0,0xefa,
+0xefa,0xefa,0xefa,0x13e0,0xfea,0x13e0,0x132c,0x132c,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,
+0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc21,0xc4e,0xc4b,0xc4e,0xc4b,0xc4e,0xc4b,
+0x10fe,0x10fb,0xff0,0xfed,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,0xc24,
+0xc24,0xc24,0xc24,0xc24,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,
+0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,0xc27,
+0xc27,0xc27,0xc27,0xc27,0xc2a,0xc2a,0xc2a,0xc30,0xc2d,0xc54,0xc51,0xc30,0xc2d,0xc30,0xc2d,0xc30,
+0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc30,0xc2d,0xc2a,0xc2a,0xc2a,
+0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,
+0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,
+0xc30,0xc2d,0xc30,0xc2d,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,
+0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,0xc2a,
+0xc30,0xc2d,0xc2a,0xc2a,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,
+0xc39,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,
+0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,
+0xc33,0xc33,0xc33,0xc33,0xc39,0xc39,0xc39,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,
+0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,0xc33,
+0xc33,0xc33,0xc33,0xc33,0xc36,0xc33,0xc33,0xc33,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,
+0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,
+0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xc6c,0xce7,0xd53,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,
+0xdd4,0xdd4,0xe88,0xe88,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xdd4,0xeeb,0xfd8,0xfd8,0xfd8,0xfd8,0xfd8,
+0xfd8,0xfd8,0xfd8,0xfd8,0xfd8,0x1296,0x1296,0x1275,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,
+0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,
+0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd0b,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd11,0xd11,
+0xd11,0xd11,0xd11,0xd0e,0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,
+0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd17,0xd17,0xd20,0xd20,0xd20,0xd20,0xd14,0xd14,
+0xd14,0xd14,0xd14,0xd1a,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,
+0xde6,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xde9,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,
+0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd1d,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,0xd23,
+0xd23,0xd23,0xd23,0xd23,0xd23,0xd17,0xd17,0xd17,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,
+0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,
+0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd1a,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,
+0xd26,0xd26,0xd26,0xd26,0xd26,0xd26,0xdec,0xdec,0xdec,0xdec,0xdec,0xdec,0xefd,0xefd,0xefd,0xefd,
+0xefd,0xefd,0xefd,0x1107,0x1107,0xff3,0xff3,0xff3,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,
+0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,
+0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd29,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,
+0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd2f,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,
+0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,
+0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd38,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,
+0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,
+0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd44,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,
+0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,
+0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xd50,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,
+0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,
+0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf2,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,
+0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf5,0xdf5,0xdf5,
+0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf5,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,
+0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,
+0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xdf8,0xeb8,0xeb8,0xe0a,0xe0a,0xf00,0xf00,0xf00,0xf00,
+0xf00,0xf00,0xf00,0xfff,0xfff,0x1002,0xfff,0xfff,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,
+0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,
+0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,
+0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe19,0xe16,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,
+0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,
+0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe25,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,
+0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0x1b1e,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,
+0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0xe28,0x1b1b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,
+0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,
+0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xe2b,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,0xeb2,
+0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xe43,0xf03,
+0xf03,0xf03,0xf03,0x1005,0x1005,0x1005,0x1005,0x1005,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,
0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,
-0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe46,0xe49,0xe49,0xe49,0xe49,
-0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,
-0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe49,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe55,0xe55,0xe55,0xe55,
-0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe52,0xe52,0xe52,0xe52,0xe52,0xe52,
-0xe52,0xe52,0xe4f,0xe58,0xffc,0xff6,0x1005,0xff3,0xe55,0xe55,0xff3,0xff3,0xe67,0xe67,0xe5b,0xe67,
-0xe67,0xe67,0xe5e,0xe67,0xe67,0xe67,0xe67,0xe5b,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,
-0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe6a,0xe6a,0xe6a,0xe6a,
-0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,
-0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe6a,0xe82,0xe82,0xe82,0xe82,
-0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,
-0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xe82,0xea3,0xea3,0xea3,0xea3,
-0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0xea3,0x10fb,0x10fb,0x10fb,0x10fb,
-0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0x10fb,0xed6,0xed6,0xed6,0xed3,
-0xed3,0xed3,0xed3,0xed3,0x1134,0x1380,0x1380,0x1380,0x1380,0x1305,0x1305,0x1305,0x1383,0x1308,0x1308,0x1383,
-0x14c4,0x14c4,0x14c4,0x14c4,0x14c4,0x14c4,0x14c4,0x1785,0x1785,0x1785,0x1785,0x184b,0xeeb,0xeeb,0xeeb,0xeeb,
-0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe1,0xfe4,0xfe4,0xfe4,0xfe4,
-0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfea,0xfea,0xfea,0xfea,
-0xfea,0xfea,0xfea,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,0x14df,
-0x14df,0x14e2,0x1854,0x1854,0x18d5,0x1854,0x1bb4,0x178b,0x131d,0x113d,0xeee,0xeee,0xf0c,0xf0c,0xf0c,0xf0c,
-0xf1e,0xf27,0xf2a,0xf27,0xf2a,0xf27,0xf2a,0xf27,0xf2a,0xf27,0xf2a,0xf27,0xf27,0xf27,0xf2a,0xf27,
-0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,0xf27,
-0xf27,0xf27,0xf27,0xf27,0xf0f,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf0c,0xf21,0xf0c,0xf21,0xf1e,0xf1e,
-0xf33,0xf30,0xf33,0xf33,0xf33,0xf30,0xf30,0xf33,0xf30,0xf33,0xf30,0xf33,0xf30,0x1017,0x1017,0x1017,
-0x1152,0x100e,0x1017,0x100e,0xf30,0xf33,0xf30,0xf30,0x100e,0x100e,0x100e,0x100e,0x1011,0x1014,0x1152,0x1152,
-0xf36,0xf36,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,
-0x1020,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,
-0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,
-0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,0xf3c,
-0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,
-0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,0xf4b,
-0xf4b,0xf4b,0xf4b,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,0x1500,
-0x1500,0x1500,0x1500,0x1500,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,
-0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,0xf51,
-0xf51,0xf51,0xf51,0xf51,0xf99,0xfb1,0xfa8,0xfae,0xfae,0xfb1,0xfb1,0xfa8,0xfa8,0xfae,0xfae,0xfae,
-0xfae,0xfae,0xfb1,0xfb1,0xfb1,0xf99,0xf99,0xf99,0xf99,0xfb1,0xfb1,0xfb1,0xfb1,0xfb1,0xfb1,0xfb1,
-0xfb1,0xfb1,0xfb1,0xfb1,0xfb1,0xfb1,0xf99,0xfa8,0xfab,0xf99,0xf99,0xfae,0xfae,0xfae,0xfae,0xfae,
-0xfae,0xf9c,0xfb1,0xfae,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0xfa5,0x111c,0x111c,
-0x1119,0x1116,0xfa2,0xfa2,0xfc9,0xfc9,0xfc9,0xfc9,0x1284,0x1284,0x1263,0x1263,0x1263,0x1260,0x1260,0x1260,
-0x1260,0x1263,0x1386,0x1263,0x1263,0x1263,0x1260,0x1263,0x1284,0x1260,0x1260,0x1260,0x1263,0x1263,0x1260,0x1260,
-0x1263,0x1260,0x1260,0x1263,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,0xfe1,0xfe1,0xfe4,0xfe4,0xfe4,0xfe4,0xfe4,
-0xfe4,0x14d9,0x14d9,0x14d9,0x10f2,0xfe1,0xfe1,0xfe1,0xfe1,0x1290,0x126c,0x126c,0x126c,0x126c,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x1002,0x1002,0xfff,0xff9,0xfff,0xff9,0xfff,0xff9,0xfff,0xff9,0xff6,0xff6,
-0xff6,0xff6,0x100b,0x1008,0xff6,0x114f,0x13da,0x13dd,0x13dd,0x13da,0x13da,0x13da,0x13da,0x13da,0x13e0,0x13e0,
-0x14f4,0x14e8,0x14e8,0x14e5,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x101d,0x101a,0x101a,0x1029,
-0x1020,0x1329,0x1326,0x16da,0x1329,0x1326,0x13e9,0x13e6,0x14f7,0x14f7,0x14fd,0x14f7,0x14fd,0x14f7,0x14fd,0x14f7,
-0x14fd,0x14f7,0x14fd,0x14f7,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,
-0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,0x1029,0x1020,
-0x1029,0x1020,0x1029,0x1020,0x1023,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1020,0x1029,0x1020,0x1029,
-0x1020,0x1029,0x1029,0x1020,0x102c,0x102c,0x1032,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,
-0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,0x1038,
-0x1038,0x1038,0x1038,0x1038,0x1038,0x1032,0x102c,0x102c,0x102c,0x102c,0x1032,0x1032,0x102c,0x102c,0x1035,0x13f2,
-0x13ef,0x13ef,0x1038,0x1038,0x102f,0x102f,0x102f,0x102f,0x102f,0x102f,0x102f,0x102f,0x102f,0x102f,0x13f5,0x13f5,
-0x13f5,0x13f5,0x13f5,0x13f5,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,
+0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe4c,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,
+0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,
+0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe55,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,
+0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,
+0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe58,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,
+0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,0xe5b,
+0xe5b,0xe5b,0xe5b,0xe5e,0xe5e,0xe5e,0xe5e,0xe5e,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,
+0xe67,0xe67,0xe67,0xe67,0xe67,0xe67,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe64,0xe61,0xe6a,
+0x1011,0x100b,0x101a,0x1008,0xe67,0xe67,0x1008,0x1008,0xe79,0xe79,0xe6d,0xe79,0xe79,0xe79,0xe70,0xe79,
+0xe79,0xe79,0xe79,0xe6d,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,
+0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe79,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,
+0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,
+0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe7c,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,
+0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,
+0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xe94,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,
+0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0xeb5,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,
+0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0x1110,0xee8,0xee8,0xee8,0xee5,0xee5,0xee5,0xee5,0xee5,
+0x1149,0x1392,0x1392,0x1392,0x1392,0x1317,0x1317,0x1317,0x1395,0x131a,0x131a,0x1395,0x14d6,0x14d6,0x14d6,0x14d6,
+0x14d6,0x14d6,0x14d6,0x1797,0x1797,0x1797,0x1797,0x185d,0xefd,0xefd,0xefd,0xefd,0xff3,0xff3,0xff3,0xff3,
+0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff3,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,
+0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0xffc,0x14f1,
+0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f1,0x14f4,0x1866,0x1866,
+0x18e7,0x1866,0x1bc6,0x179d,0x132f,0x1152,0xf00,0xf00,0xf1e,0xf1e,0xf1e,0xf1e,0xf30,0xf39,0xf3c,0xf39,
+0xf3c,0xf39,0xf3c,0xf39,0xf3c,0xf39,0xf3c,0xf39,0xf39,0xf39,0xf3c,0xf39,0xf39,0xf39,0xf39,0xf39,
+0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,0xf39,
+0xf21,0xf1e,0xf1e,0xf1e,0xf1e,0xf1e,0xf1e,0xf33,0xf1e,0xf33,0xf30,0xf30,0xf45,0xf42,0xf45,0xf45,
+0xf45,0xf42,0xf42,0xf45,0xf42,0xf45,0xf42,0xf45,0xf42,0x102c,0x102c,0x102c,0x1167,0x1023,0x102c,0x1023,
+0xf42,0xf45,0xf42,0xf42,0x1023,0x1023,0x1023,0x1023,0x1026,0x1029,0x1167,0x1167,0xf48,0xf48,0x103e,0x1035,
+0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x1035,0x1035,0x103e,0x1035,
+0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0xf4e,0xf4e,0xf4e,0xf4e,
+0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,
+0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf4e,0xf5d,0xf5d,0xf5d,0xf5d,
+0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,
+0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0xf5d,0x1512,
+0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,0x1512,
+0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,
+0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,0xf63,
+0xfab,0xfc3,0xfba,0xfc0,0xfc0,0xfc3,0xfc3,0xfba,0xfba,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfc3,0xfc3,
+0xfc3,0xfab,0xfab,0xfab,0xfab,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,0xfc3,
+0xfc3,0xfc3,0xfab,0xfba,0xfbd,0xfab,0xfab,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfc0,0xfae,0xfc3,0xfc0,
+0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0xfb7,0x1131,0x1131,0x112e,0x112b,0xfb4,0xfb4,
+0xfdb,0xfdb,0xfdb,0xfdb,0x1296,0x1296,0x1275,0x1275,0x1275,0x1272,0x1272,0x1272,0x1272,0x1275,0x1398,0x1275,
+0x1275,0x1275,0x1272,0x1275,0x1296,0x1272,0x1272,0x1272,0x1275,0x1275,0x1272,0x1272,0x1275,0x1272,0x1272,0x1275,
+0xff6,0xff6,0xff6,0xff6,0xff6,0xff3,0xff3,0xff6,0xff6,0xff6,0xff6,0xff6,0xff6,0x14eb,0x14eb,0x14eb,
+0x1107,0xff3,0xff3,0xff3,0xff3,0x12a2,0x127e,0x127e,0x127e,0x127e,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,
+0x1017,0x1017,0x1014,0x100e,0x1014,0x100e,0x1014,0x100e,0x1014,0x100e,0x100b,0x100b,0x100b,0x100b,0x1020,0x101d,
+0x100b,0x1164,0x13ec,0x13ef,0x13ef,0x13ec,0x13ec,0x13ec,0x13ec,0x13ec,0x13f2,0x13f2,0x1506,0x14fa,0x14fa,0x14f7,
+0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x1032,0x102f,0x102f,0x103e,0x1035,0x133b,0x1338,0x16ec,
+0x133b,0x1338,0x13fb,0x13f8,0x1509,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509,0x150f,0x1509,
+0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,
+0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x1035,
+0x1038,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x1035,0x103e,0x1035,0x103e,0x1035,0x103e,0x103e,0x1035,
+0x1041,0x1041,0x1047,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,
0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,0x104d,
-0x104d,0x104d,0x104d,0x104d,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,
-0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1056,0x1059,0x1059,0x1059,0x105c,
-0x1059,0x1059,0x105f,0x105f,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,
+0x104d,0x1047,0x1041,0x1041,0x1041,0x1041,0x1047,0x1047,0x1041,0x1041,0x104a,0x1404,0x1401,0x1401,0x104d,0x104d,
+0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1044,0x1407,0x1407,0x1407,0x1407,0x1407,0x1407,
+0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,
0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,0x1062,
-0x1062,0x1062,0x1062,0x1062,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,
-0x106e,0x1065,0x1074,0x1071,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,
0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,
-0x106b,0x106b,0x106b,0x106b,0x132f,0x132c,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,
-0x1086,0x1080,0x1083,0x1104,0x1077,0x1077,0x1077,0x107d,0x13f8,0x13f8,0x13f8,0x13f8,0x13f8,0x13f8,0x13f8,0x13f8,
-0x107a,0x107a,0x107d,0x1089,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,
-0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,0x1086,0x1080,
-0x1086,0x1080,0x1086,0x1080,0x150c,0x1509,0x150c,0x1509,0x150f,0x150f,0x16e3,0x13f8,0x1092,0x1092,0x1095,0x1095,
-0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,
-0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1095,0x1092,0x1092,0x1092,0x1092,
-0x1092,0x1092,0x1092,0x1092,0x1092,0x1092,0x1092,0x1092,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x109b,0x109b,
-0x109b,0x109b,0x109b,0x109e,0x109e,0x109e,0x10f8,0x10a7,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,
-0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10a1,0x10a1,0x10a1,0x10a1,0x10a1,0x10a1,0x10a1,0x10a1,
-0x10a1,0x10a1,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,
-0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10a4,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,
-0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,
-0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10c5,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,
-0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,
-0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10d7,0x10e0,0x10e0,0x10e0,0x10e0,0x10f5,0x10e0,0x10e0,0x10e0,
-0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,
-0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e0,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
-0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,
-0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10e3,0x10ef,0x10ef,0x10ef,0x10ef,0x128a,0x128a,0x128a,0x128a,
-0x128a,0x128a,0x128a,0x128a,0x1482,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x18b4,0x18b4,
-0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,
-0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x1164,0x115b,0x115b,
-0x115e,0x115e,0x1164,0x115b,0x115b,0x115b,0x115b,0x115b,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,
-0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,
-0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x116a,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,
-0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,
-0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1185,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,
-0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,
-0x1191,0x1191,0x1191,0x1191,0x1191,0x1191,0x118e,0x1194,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,
-0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,
-0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a0,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,
-0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x12d5,0x11ac,0x12d8,0x11ac,0x11ac,0x11ac,0x11ac,
-0x11a9,0x11a9,0x11a9,0x11ac,0x16e6,0x16e9,0x1911,0x190e,0x11af,0x11af,0x11af,0x11be,0x11c4,0x11c4,0x11c4,0x11c4,
-0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,
-0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11c4,0x11b2,0x11be,0x11be,0x11af,0x11af,
-0x11af,0x11af,0x11be,0x11be,0x11af,0x11af,0x11be,0x11be,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,
-0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d3,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11d0,0x11ca,
-0x11ca,0x11ca,0x11d0,0x11cd,0x1515,0x1518,0x151b,0x151b,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
-0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11d6,0x11e2,0x11d6,0x11d6,0x11d6,0x11eb,0x11eb,0x11d6,
-0x11d6,0x11eb,0x11e2,0x11eb,0x11eb,0x11e2,0x11d6,0x11d9,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
-0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,
-0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11e2,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,
-0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,
-0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x11fd,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,
-0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,0x1215,
-0x1215,0x1215,0x1215,0x1215,0x1215,0x1212,0x1212,0x1212,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,
-0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,
-0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x121e,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,
-0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,
-0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x122d,0x1233,0x1233,0x1242,0x1245,0x1245,0x1245,0x1245,0x1245,
-0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,
-0x1245,0x1245,0x1248,0x1245,0x1248,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,0x1245,
-0x1245,0x1245,0x1245,0x1248,0x1245,0x1245,0x1245,0x1245,0x1242,0x1242,0x1242,0x1236,0x1236,0x1236,0x1236,0x1242,
-0x1242,0x123c,0x1239,0x123f,0x123f,0x124e,0x124b,0x124b,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,
-0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,
-0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1257,0x1257,0x1257,0x1254,0x1254,0x1254,0x1251,0x1251,
-0x1251,0x1251,0x1254,0x1251,0x1251,0x1251,0x1257,0x1254,0x1257,0x1254,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,
-0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,0x1251,
-0x1251,0x1251,0x1251,0x1251,0x1251,0x1257,0x1254,0x1254,0x1251,0x1251,0x1251,0x1251,0x1272,0x1272,0x1272,0x1272,
-0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1275,0x1275,0x1275,0x125a,0x1917,0x137d,0x127e,0x137d,0x137d,
-0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x127e,0x137d,0x127e,0x1263,0x1263,0x130b,0x1260,
-0x130b,0x130b,0x130b,0x130b,0x1260,0x1260,0x1284,0x1260,0x1260,0x1260,0x1260,0x1260,0x1260,0x1263,0x1284,0x1284,
-0x1263,0x1284,0x1260,0x1263,0x1263,0x1266,0x1284,0x1260,0x1260,0x1284,0x1263,0x1263,0x137a,0x137a,0x137a,0x137a,
-0x137a,0x137a,0x137a,0x137a,0x137a,0x137a,0x126f,0x126f,0x126f,0x126f,0x1392,0x1374,0x1278,0x1392,0x1392,0x1392,
-0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1392,0x1815,0x1815,0x1815,0x1815,0x1815,0x1272,0x1272,0x1272,0x1272,
-0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x151e,0x151e,0x1a64,0x1a64,0x1a64,0x1272,0x1272,0x1272,0x1272,
-0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x1272,0x137d,0x137d,0x127e,0x137d,
-0x137d,0x137d,0x127e,0x137d,0x137d,0x137d,0x1278,0x1278,0x1278,0x1278,0x1278,0x1377,0x137a,0x137a,0x137a,0x137a,
-0x137a,0x137a,0x137a,0x127b,0x137a,0x137a,0x137a,0x137a,0x137a,0x137a,0x137a,0x127b,0x137a,0x137a,0x137a,0x137a,
-0x137a,0x137a,0x137a,0x137a,0x137a,0x137a,0x13fb,0x13fb,0x19c2,0x1a64,0x1a64,0x1a64,0x137a,0x137a,0x137a,0x137a,
-0x137a,0x137a,0x137a,0x137a,0x137a,0x127b,0x137a,0x127b,0x127b,0x137a,0x137a,0x127b,0x129f,0x129f,0x129f,0x129f,
-0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,
-0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x129f,0x1329,0x1326,0x1329,0x1326,
-0x1329,0x1326,0x1329,0x1326,0x1329,0x1326,0x13e9,0x14fd,0x14fd,0x14fd,0x1791,0x1905,0x14fd,0x14fd,0x16dd,0x16dd,
-0x16dd,0x16d7,0x16dd,0x16d7,0x1908,0x1905,0x19bf,0x19bc,0x19bf,0x19bc,0x19bf,0x19bc,0x134d,0x134d,0x134d,0x134d,
-0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,
-0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x134d,0x1362,0x1353,0x1362,0x1365,
-0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,
-0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1353,0x1353,0x1353,0x1353,
-0x1353,0x1353,0x1353,0x1353,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,
-0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,0x136b,
-0x136b,0x136b,0x136b,0x136b,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,
-0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,0x1371,
-0x1371,0x1371,0x1371,0x1371,0x139b,0x1398,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
-0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
-0x18ba,0x18ba,0x18ba,0x18ba,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a1,0x13a1,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a1,0x13a4,0x13a4,0x13a4,0x13a1,0x13a4,0x13a1,0x13a4,0x13a1,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a7,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a1,0x13a4,0x13a1,0x13a1,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,
-0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x13a1,0x1527,0x1527,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x1767,0x1767,0x1767,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x1767,0x1767,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a7,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x1527,0x1527,0x152a,0x152a,0x13a4,0x13a4,0x13a7,0x13a7,0x13a7,0x1692,0x13a4,0x13a7,
-0x13a4,0x13a4,0x13a7,0x152d,0x152d,0x152a,0x152a,0x1767,0x1767,0x1767,0x1767,0x1767,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x152a,0x152a,0x1692,0x152a,0x152a,0x152a,
-0x1767,0x1767,0x1767,0x176a,0x176a,0x176a,0x176a,0x176a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x13a4,0x152a,0x13a7,0x13a7,0x13a4,0x13a4,0x13a7,0x13a7,
-0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,
-0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a7,0x13a4,0x13a4,0x13a4,
-0x13a7,0x13a4,0x13a4,0x13a4,0x13a4,0x13a7,0x13a7,0x13a7,0x13a4,0x13a7,0x13a7,0x13a7,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a7,0x13a4,0x13a7,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x1692,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x152a,0x1767,0x13fe,0x13fe,0x13fe,0x13fe,0x1527,0x1527,0x1527,0x1527,
-0x1527,0x1527,0x152a,0x1767,0x1767,0x1767,0x1767,0x16ec,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,
-0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152d,0x152d,0x152a,0x152a,0x152a,0x152a,0x181e,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x1527,0x1527,0x1527,0x1527,0x1527,0x1527,0x152a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x1488,0x13aa,0x13aa,0x13aa,
-0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x1488,0x13aa,0x13aa,
-0x13aa,0x1488,0x13aa,0x1488,0x13aa,0x1488,0x13aa,0x1488,0x13aa,0x13aa,0x13aa,0x1488,0x13aa,0x13aa,0x13aa,0x13aa,
-0x13aa,0x13aa,0x1488,0x1488,0x13aa,0x13aa,0x13aa,0x13aa,0x1488,0x13aa,0x1488,0x1488,0x13aa,0x13aa,0x13aa,0x13aa,
-0x1488,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x13aa,0x1698,0x1698,0x176d,
-0x176d,0x13ad,0x13ad,0x13ad,0x13aa,0x13aa,0x13aa,0x13ad,0x13ad,0x13ad,0x13ad,0x13ad,0x1617,0x1617,0x1617,0x1617,
-0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x13b0,0x13b0,0x13b0,0x13b0,
-0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,
-0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b3,
-0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,
-0x13b3,0x13b3,0x13b3,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b0,0x13b6,0x13b6,0x13b6,0x13b6,
+0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106b,0x106e,0x106e,0x106e,0x1071,0x106e,0x106e,0x1074,0x1074,
+0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,
+0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,0x1077,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1083,0x107a,0x1089,0x1086,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,0x1080,
+0x1341,0x133e,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x1098,0x1119,
+0x108c,0x108c,0x108c,0x1092,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x140a,0x108f,0x108f,0x1092,0x109e,
+0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,
+0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,0x109b,0x1095,
+0x151e,0x151b,0x151e,0x151b,0x1521,0x1521,0x16f5,0x140a,0x10a7,0x10a7,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,
+0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,
+0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10aa,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,0x10a7,
+0x10a7,0x10a7,0x10a7,0x10a7,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b0,0x10b0,0x10b0,0x10b0,0x10b0,0x10b3,
+0x10b3,0x10b3,0x110d,0x10bc,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,0x10cb,
+0x10cb,0x10cb,0x10cb,0x10cb,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b6,0x10b9,0x10b9,
+0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,0x10b9,
+0x10b9,0x10b9,0x10b9,0x10b9,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,
+0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,0x10da,
+0x10da,0x10da,0x10da,0x10da,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,
+0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,0x10ec,
+0x10ec,0x10ec,0x10ec,0x10ec,0x10f5,0x10f5,0x10f5,0x10f5,0x110a,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,
+0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,0x10f5,
+0x10f5,0x10f5,0x10f5,0x10f5,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,
+0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,0x10f8,
+0x10f8,0x10f8,0x10f8,0x10f8,0x1104,0x1104,0x1104,0x1104,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c,0x129c,
+0x1494,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,
+0x18c6,0x18c6,0x18c6,0x18c6,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,
+0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1179,0x1170,0x1170,0x1173,0x1173,0x1179,0x1170,
+0x1170,0x1170,0x1170,0x1170,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,
+0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,0x117f,
+0x117f,0x117f,0x117f,0x117f,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,
+0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,0x119a,
+0x119a,0x119a,0x119a,0x119a,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,
+0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,0x11a6,
+0x11a6,0x11a6,0x11a3,0x11a9,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,
+0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,0x11b5,
+0x11b5,0x11b5,0x11b5,0x11b5,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,
+0x11bb,0x11bb,0x11bb,0x11bb,0x11bb,0x12e7,0x11c1,0x12ea,0x11c1,0x11c1,0x11c1,0x11c1,0x11be,0x11be,0x11be,0x11c1,
+0x16f8,0x16fb,0x1923,0x1920,0x11c4,0x11c4,0x11c4,0x11d3,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,
+0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,
+0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11d9,0x11c7,0x11d3,0x11d3,0x11c4,0x11c4,0x11c4,0x11c4,0x11d3,0x11d3,
+0x11c4,0x11c4,0x11d3,0x11d3,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,
+0x11e5,0x11e5,0x11e5,0x11e5,0x11e8,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11e5,0x11df,0x11df,0x11df,0x11e5,0x11e2,
+0x1527,0x152a,0x152d,0x152d,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,
+0x11f7,0x11f7,0x11f7,0x11f7,0x11eb,0x11f7,0x11eb,0x11eb,0x11eb,0x1200,0x1200,0x11eb,0x11eb,0x1200,0x11f7,0x1200,
+0x1200,0x11f7,0x11eb,0x11ee,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,
+0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,0x11f7,
+0x11f7,0x11f7,0x11f7,0x11f7,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,
+0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,0x1212,
+0x1212,0x1212,0x1212,0x1212,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,
+0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,0x122a,
+0x122a,0x1227,0x1227,0x1227,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,
+0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,0x1233,
+0x1233,0x1233,0x1233,0x1233,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,
+0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,0x1242,
+0x1242,0x1242,0x1242,0x1242,0x1248,0x1248,0x1254,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,
+0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x125a,0x1257,
+0x125a,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x1257,0x125a,
+0x1257,0x1257,0x1257,0x1257,0x1254,0x1254,0x1254,0x1248,0x1248,0x1248,0x1248,0x1254,0x1254,0x124e,0x124b,0x1251,
+0x1251,0x1260,0x125d,0x125d,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,
+0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,
+0x1263,0x1263,0x1263,0x1263,0x1269,0x1269,0x1269,0x1266,0x1266,0x1266,0x1263,0x1263,0x1263,0x1263,0x1266,0x1263,
+0x1263,0x1263,0x1269,0x1266,0x1269,0x1266,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,
+0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,
+0x1263,0x1269,0x1266,0x1266,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,0x1263,
+0x1263,0x1263,0x1263,0x1bcf,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f5,0x19f8,0x19f2,0x1be1,0x1be1,0x1be1,
+0x1be4,0x1bde,0x1be4,0x1bde,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1287,
+0x1287,0x1287,0x126c,0x1929,0x138f,0x1290,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,0x138f,
+0x138f,0x1290,0x138f,0x1290,0x1275,0x1275,0x131d,0x1272,0x131d,0x131d,0x131d,0x131d,0x1272,0x1272,0x1296,0x1272,
+0x1272,0x1272,0x1272,0x1272,0x1272,0x1275,0x1296,0x1296,0x1275,0x1296,0x1272,0x1275,0x1275,0x1278,0x1296,0x1272,
+0x1272,0x1296,0x1275,0x1275,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x1281,0x1281,
+0x1281,0x1281,0x13a4,0x1386,0x128a,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x13a4,0x1827,
+0x1827,0x1827,0x1827,0x1827,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1530,
+0x1530,0x1a76,0x1a76,0x1a76,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,0x1284,
+0x1284,0x1284,0x1284,0x1284,0x138f,0x138f,0x1290,0x138f,0x138f,0x138f,0x1290,0x138f,0x138f,0x138f,0x128a,0x128a,
+0x128a,0x128a,0x128a,0x1389,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x128d,0x138c,0x138c,0x138c,0x138c,
+0x138c,0x138c,0x138c,0x128d,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x140d,0x140d,
+0x19d4,0x1a76,0x1a76,0x1a76,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x138c,0x128d,0x138c,0x128d,
+0x128d,0x138c,0x138c,0x128d,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,
+0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,0x12b1,
+0x12b1,0x12b1,0x12b1,0x12b1,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x133b,0x1338,0x13fb,0x150f,
+0x150f,0x150f,0x17a3,0x1917,0x150f,0x150f,0x16ef,0x16ef,0x16ef,0x16e9,0x16ef,0x16e9,0x191a,0x1917,0x19d1,0x19ce,
+0x19d1,0x19ce,0x19d1,0x19ce,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,
+0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,0x135f,
+0x135f,0x135f,0x135f,0x135f,0x1374,0x1365,0x1374,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,
+0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,0x1377,
+0x1377,0x1377,0x1377,0x1377,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x1365,0x137d,0x137d,0x137d,0x137d,
+0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,
+0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x137d,0x1383,0x1383,0x1383,0x1383,
+0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,
+0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x1383,0x13ad,0x13aa,0x18cc,0x18cc,
+0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,
+0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b3,0x13b6,
+0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b6,0x13b3,0x13b3,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3,
+0x13b3,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,
+0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x13b3,0x1539,0x1539,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x1779,0x1779,0x1779,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x1779,0x1779,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x153c,0x153c,
+0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x16a4,0x13b6,0x13b9,0x13b6,0x13b6,0x13b9,0x153f,0x153f,0x153c,0x153c,0x1779,
+0x1779,0x1779,0x1779,0x1779,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x153c,0x153c,0x153c,0x16a4,0x153c,0x153c,0x153c,0x1779,0x1779,0x1779,0x177c,0x177c,0x177c,0x177c,0x177c,
0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
-0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x179a,0x179a,0x1797,0x16ef,
-0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1401,0x1401,0x1401,0x1401,0x1401,0x1401,0x1404,0x1404,0x1404,0x1404,
-0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1404,0x1533,0x1407,0x1536,0x1407,0x1407,
-0x1407,0x1407,0x1407,0x1407,0x1407,0x1407,0x1407,0x1407,0x1407,0x1536,0x1536,0x1536,0x1536,0x1536,0x1536,0x16f2,
-0x16f2,0x1b39,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x17a0,0x1a67,0x1a67,0x1410,0x1410,0x1410,0x1422,
-0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,
-0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x1422,0x143d,0x143d,0x143d,0x143d,
-0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,
-0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x143d,0x1443,0x1443,0x1443,0x1443,
-0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,
-0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x1443,0x19c8,0x1446,0x1446,0x1446,0x1446,
-0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,
-0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x1446,0x144c,0x144c,0x1458,0x145e,
-0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,
-0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,0x1458,
-0x1458,0x1458,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x144c,0x1458,0x145b,0x145e,0x1461,0x1461,
-0x145e,0x1464,0x1464,0x144f,0x1452,0x16f8,0x16fb,0x16fb,0x16fb,0x153c,0x1a70,0x1a6d,0x1455,0x1455,0x1455,0x1455,
-0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1539,0x1701,0x1704,0x16fe,0x1707,0x1707,0x147f,0x147f,0x147f,0x147f,
-0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,
-0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x147f,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x18ed,0x18ed,0x18ed,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,
-0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x19b6,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x14d9,0x1851,0x18ed,
-0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x1527,0x1527,0x1527,0x1527,0x1527,0x1527,0x1527,0x1527,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152d,0x152a,0x152a,0x152a,0x152a,0x1695,0x1695,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x181b,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,0x152a,
-0x152a,0x152a,0x152a,0x152a,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,
-0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,0x154b,
-0x154b,0x154b,0x154b,0x154b,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,
+0x13b6,0x153c,0x13b9,0x13b9,0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,
+0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,
+0x13b9,0x13b9,0x13b9,0x13b9,0x13b9,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b9,0x13b9,
+0x13b6,0x13b9,0x13b9,0x13b9,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b9,0x13b6,0x13b9,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x16a4,0x13b6,0x13b6,0x13b6,0x13b6,0x153c,0x153c,0x1779,
+0x1410,0x1410,0x1410,0x1410,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x153c,0x1779,0x1779,0x1779,0x1779,0x16fe,
+0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,0x13b6,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153f,0x153f,0x153c,0x153c,
+0x153c,0x153c,0x1830,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x153c,0x13b6,
+0x13b6,0x13b6,0x13b6,0x13b6,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,
+0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x149a,0x13bc,0x149a,0x13bc,0x149a,
+0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,
+0x149a,0x13bc,0x149a,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x149a,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,
+0x13bc,0x13bc,0x13bc,0x13bc,0x13bc,0x16aa,0x16aa,0x177f,0x177f,0x13bf,0x13bf,0x13bf,0x13bc,0x13bc,0x13bc,0x13bf,
+0x13bf,0x13bf,0x13bf,0x13bf,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,
+0x1629,0x1629,0x1629,0x1629,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,
+0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,
+0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,
+0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,0x13c5,0x13c5,0x13c5,0x13c2,0x13c2,0x13c2,0x13c2,0x13c2,
+0x13c2,0x13c2,0x13c2,0x13c2,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,
+0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,0x13c8,
+0x13c8,0x13c8,0x13c8,0x13c8,0x17ac,0x17ac,0x17a9,0x1701,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1413,0x1413,
+0x1413,0x1413,0x1413,0x1413,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,0x1416,
+0x1416,0x1416,0x1416,0x1545,0x1419,0x1548,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,0x1419,
+0x1419,0x1548,0x1548,0x1548,0x1548,0x1548,0x1548,0x1704,0x1704,0x1b4b,0x17b2,0x17b2,0x17b2,0x17b2,0x17b2,0x17b2,
+0x17b2,0x17b2,0x1a79,0x1a79,0x1422,0x1422,0x1422,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,
+0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,0x1434,
+0x1434,0x1434,0x1434,0x1434,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,
+0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,0x144f,
+0x144f,0x144f,0x144f,0x144f,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,
+0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,0x1455,
+0x1455,0x1455,0x1455,0x19da,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,
+0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,0x1458,
+0x1458,0x1458,0x1458,0x1458,0x145e,0x145e,0x146a,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,
+0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,
+0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x1470,0x146a,0x146a,0x146a,0x145e,0x145e,0x145e,0x145e,0x145e,0x145e,
+0x145e,0x145e,0x145e,0x146a,0x146d,0x1470,0x1473,0x1473,0x1470,0x1476,0x1476,0x1461,0x1464,0x170a,0x170d,0x170d,
+0x170d,0x154e,0x1a82,0x1a7f,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x1467,0x154b,0x1713,
+0x1716,0x1710,0x1719,0x1719,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,
+0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,0x1491,
+0x1491,0x1491,0x1491,0x1491,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,
+0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x18ff,0x18ff,
+0x18ff,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x19c8,0x14eb,0x14eb,
+0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x14eb,0x1863,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,
+0x18ff,0x18ff,0x18ff,0x18ff,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,0x1539,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x153f,0x153c,0x153c,0x153c,0x153c,0x16a7,0x16a7,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x182d,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,
+0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x153c,0x155d,0x155d,0x155d,0x155d,
0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,
-0x155d,0x155d,0x155d,0x155d,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,
-0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,0x1563,
-0x1563,0x1563,0x1563,0x1563,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,
-0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,0x1566,
-0x1566,0x1566,0x1566,0x1566,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,
-0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,0x15a5,
-0x15a5,0x15a5,0x15a5,0x1596,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,
-0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15ae,0x15a8,
-0x15b1,0x15b1,0x15b1,0x15b1,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,0x15b4,
-0x15b4,0x15b4,0x15b4,0x15b4,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15c6,0x15cf,0x15cf,0x15cf,
-0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,0x15cf,
-0x15cf,0x15cf,0x15cf,0x15cf,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,
-0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,0x15d8,
-0x15d8,0x15d8,0x15d8,0x15d8,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,
-0x15ea,0x15ea,0x15ea,0x15ea,0x15e7,0x15e7,0x15e7,0x15db,0x15db,0x15db,0x15db,0x15db,0x15db,0x15db,0x15db,0x15e7,
-0x15e7,0x15db,0x15e7,0x15de,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,
+0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x155d,0x156f,0x156f,0x156f,0x156f,
+0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,
+0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x156f,0x1575,0x1575,0x1575,0x1575,
+0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,
+0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1575,0x1578,0x1578,0x1578,0x1578,
+0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,
+0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x1578,0x15a2,0x15a2,0x15a2,0x15a2,
+0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x15a2,0x159c,0x159c,0x159c,0x1590,0x1590,0x1590,0x159c,0x159c,
+0x1590,0x159f,0x1593,0x1590,0x15a5,0x15a5,0x1599,0x15a5,0x15a5,0x1596,0x17b5,0x1bdb,0x15b7,0x15b7,0x15b7,0x15b7,
+0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,
+0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15b7,0x15a8,0x15c0,0x15c0,0x15c0,0x15c0,
+0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,
+0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15c0,0x15ba,0x15c3,0x15c3,0x15c3,0x15c3,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,
+0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15c6,0x15e1,0x15e1,0x15e1,0x15e1,
+0x15e1,0x15e1,0x15e1,0x15e1,0x15d8,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,
+0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15e1,0x15ea,0x15ea,0x15ea,0x15ea,
0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,
-0x15ea,0x15ea,0x15ea,0x15ea,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,
-0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,0x160e,
-0x160e,0x160b,0x160b,0x160b,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,
-0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x1617,0x161d,0x161d,0x161d,0x161a,0x161a,0x161a,
-0x1617,0x1617,0x1617,0x1617,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,
-0x162c,0x162c,0x162c,0x162c,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1632,0x1632,0x1626,0x1623,0x1623,
-0x1623,0x1623,0x1623,0x1623,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,
-0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,0x162c,
-0x162c,0x162c,0x162c,0x162c,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,
-0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1638,0x1635,0x1635,0x1635,0x1635,0x1635,
-0x1635,0x1635,0x1635,0x1635,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,
-0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,0x163b,
-0x163b,0x163b,0x163b,0x163b,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,
-0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,0x165f,
-0x165f,0x165f,0x165f,0x165f,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,0x1668,
-0x1668,0x1668,0x1668,0x1668,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,
-0x1680,0x1680,0x1680,0x1680,0x166b,0x167a,0x167a,0x166b,0x166b,0x166b,0x166b,0x166b,0x166b,0x167a,0x166b,0x167d,
-0x167d,0x166b,0x167d,0x166b,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,
-0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,0x1680,
-0x1680,0x1680,0x1680,0x1680,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,
-0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,0x1689,
-0x1689,0x1689,0x1689,0x1689,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,
-0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,0x168f,
-0x168f,0x168f,0x168f,0x168f,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,
-0x16d4,0x16d4,0x16d4,0x16d4,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,0x18ed,
-0x18ed,0x18ed,0x18ed,0x19b6,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,
-0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,0x16f5,
-0x16f5,0x16f5,0x16f5,0x16f5,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,
-0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,
-0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x173a,0x1737,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,
-0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x1734,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,
-0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,
-0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x173d,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,
-0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,
-0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1740,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,
+0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15ea,0x15fc,0x15fc,0x15fc,0x15fc,
+0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15f9,0x15f9,0x15f9,0x15ed,
+0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15ed,0x15f9,0x15f9,0x15ed,0x15f9,0x15f0,0x15fc,0x15fc,0x15fc,0x15fc,
+0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,
+0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x15fc,0x1620,0x1620,0x1620,0x1620,
+0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,
+0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x1620,0x161d,0x161d,0x161d,0x1629,0x1629,0x1629,0x1629,
+0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,0x1629,
+0x1629,0x1629,0x162f,0x162f,0x162f,0x162c,0x162c,0x162c,0x1629,0x1629,0x1629,0x1629,0x163e,0x163e,0x163e,0x163e,
+0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x1632,0x1632,0x1632,0x1632,
+0x1632,0x1632,0x1632,0x1644,0x1644,0x1638,0x1635,0x1635,0x1635,0x1635,0x1635,0x1635,0x163e,0x163e,0x163e,0x163e,
+0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,
+0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x163e,0x164a,0x164a,0x164a,0x164a,
+0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,0x164a,
+0x164a,0x164a,0x164a,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x1647,0x164d,0x164d,0x164d,0x164d,
+0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,
+0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x164d,0x1671,0x1671,0x1671,0x1671,
+0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,
+0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x1671,0x167a,0x167a,0x167a,0x167a,
+0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,
+0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x167a,0x1692,0x1692,0x1692,0x1692,
+0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x167d,0x168c,0x168c,0x167d,
+0x167d,0x167d,0x167d,0x167d,0x167d,0x168c,0x167d,0x168f,0x168f,0x167d,0x168f,0x167d,0x1692,0x1692,0x1692,0x1692,
+0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,
+0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x1692,0x169b,0x169b,0x169b,0x169b,
+0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,
+0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x169b,0x16a1,0x16a1,0x16a1,0x16a1,
+0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,
+0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x16a1,0x18ff,0x18ff,0x18ff,0x18ff,
+0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x16e6,0x16e6,0x16e6,0x16e6,0x18ff,0x18ff,0x18ff,0x18ff,
+0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x18ff,0x19c8,0x1707,0x1707,0x1707,0x1707,
+0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,
+0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1707,0x1746,0x1746,0x1746,0x1746,
+0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,
+0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x174c,0x1749,
+0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,0x1746,
+0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,
+0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,0x174f,
0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,
-0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,
-0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,
-0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1755,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,
-0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,
-0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x175b,0x175b,0x175b,0x175b,0x1758,
-0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x1758,0x175b,0x175b,0x175b,
-0x175b,0x175b,0x175b,0x175b,0x175b,0x1758,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,
-0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,
-0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x175b,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,
-0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,
-0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x1773,0x185d,0x185d,0x185d,0x185d,0x185d,0x185d,0x185d,0x185d,
-0x185d,0x185d,0x185d,0x185d,0x1ad3,0x1a28,0x1a28,0x1a2b,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,0x1776,
-0x1779,0x1827,0x1827,0x1827,0x1827,0x1827,0x1827,0x18c3,0x1776,0x1776,0x1776,0x1776,0x1776,0x1824,0x1824,0x1824,
-0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,
-0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x1776,0x19a1,0x19a1,0x1a28,0x1a28,0x1a28,0x1a28,0x1a28,
-0x1a28,0x1a28,0x1a28,0x1ad0,0x1ba2,0x1a2b,0x1a2b,0x1a2b,0x18c0,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,
-0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c3,0x18c0,0x18c0,0x1a67,0x1a67,0x1a67,0x1a67,0x1a67,0x1a67,0x1a67,0x1a67,
-0x1b39,0x1b3c,0x1b36,0x1b36,0x1b36,0x1b36,0x1b36,0x1b36,0x1b36,0x1b36,0x1b36,0x191a,0x179d,0x179d,0x179d,0x179d,
-0x179d,0x179d,0x179d,0x179d,0x179d,0x179d,0x179d,0x179d,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1827,0x1824,
-0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x1827,0x18c3,0x18c3,0x1827,0x1827,0x1827,0x1827,0x1827,
-0x1827,0x1827,0x1824,0x17a6,0x1827,0x1827,0x1827,0x1a28,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x17a6,0x1824,
-0x1824,0x1824,0x1824,0x1824,0x18c0,0x19a1,0x19a1,0x19a1,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,
-0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x1824,0x18c0,0x17bb,0x17bb,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,
-0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,
-0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17b8,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,
-0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,
-0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x17bb,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,
-0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1806,0x1806,0x1806,
-0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x17f1,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,
-0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,
-0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x1809,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,
-0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,
-0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x182d,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,
-0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,
-0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1830,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,
-0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1adc,0x1887,0x1887,0x1887,0x1887,0x19da,0x19da,0x188a,0x188a,
-0x188a,0x188a,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1872,0x1884,
-0x1875,0x1878,0x187b,0x188d,0x188d,0x192c,0x187e,0x187e,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,
-0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,
-0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x1887,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,
-0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x1893,0x1899,0x1896,0x1896,0x1896,
-0x1896,0x18a5,0x18ab,0x1896,0x1896,0x1896,0x1896,0x18a2,0x18a8,0x1896,0x1896,0x1896,0x1896,0x1896,0x1896,0x1896,
-0x1896,0x1896,0x1896,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,
-0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,0x18b4,
-0x18b4,0x18b4,0x18b4,0x199b,0x199b,0x199b,0x199b,0x199b,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,
-0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1ac7,0x1b93,0x1b93,0x1b93,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
+0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,0x1752,
+0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,
+0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,0x1764,
+0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,
+0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,0x1767,
+0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,
+0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,
+0x176a,0x176a,0x176a,0x176d,0x176d,0x176d,0x176d,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,0x176a,
+0x176a,0x176a,0x176a,0x176a,0x176a,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176a,0x176d,0x176d,
+0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,
+0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,0x176d,
+0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,
+0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,0x1785,
+0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x186f,0x1ae5,0x1a3a,0x1a3a,0x1a3d,
+0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x1788,0x178b,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x18d5,
+0x1788,0x1788,0x1788,0x1788,0x1788,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,
+0x1836,0x1836,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,
+0x1788,0x19b3,0x19b3,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1ae2,0x1bb4,0x1a3d,0x1a3d,0x1a3d,
+0x18d2,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d5,0x18d2,0x18d2,
+0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1a79,0x1b4b,0x1b4e,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,0x1b48,
+0x1b48,0x1b48,0x1b48,0x192c,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,0x17af,
+0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1839,0x1836,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,
+0x1839,0x18d5,0x18d5,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x1839,0x1836,0x17b8,0x1839,0x1839,0x1839,0x1a3a,
+0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x17b8,0x1836,0x1836,0x1836,0x1836,0x1836,0x18d2,0x19b3,0x19b3,0x19b3,
+0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x1836,0x18d2,
+0x17cd,0x17cd,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,
+0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,0x17ca,
+0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,
+0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,0x17cd,
+0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,
+0x181b,0x181b,0x181b,0x181b,0x181b,0x1818,0x1818,0x1818,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,0x1803,
+0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,
+0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,0x181b,
+0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,
+0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,0x183f,
+0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,
+0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,0x1842,
+0x1842,0x1842,0x1842,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,0x1aee,
+0x1899,0x1899,0x1899,0x1899,0x19ec,0x19ec,0x189c,0x189c,0x189c,0x189c,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,
+0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1884,0x1896,0x1887,0x188a,0x188d,0x189f,0x189f,0x193e,0x1890,0x1890,
+0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,
+0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,0x1899,
+0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
+0x18ba,0x18ba,0x18ba,0x18a5,0x18ab,0x18a8,0x18a8,0x18a8,0x18a8,0x18b7,0x18bd,0x18a8,0x18a8,0x18a8,0x18a8,0x18b4,
+0x18ba,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18a8,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,
-0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18ba,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,
-0x18c0,0x18c0,0x18c0,0x18c0,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x1a28,0x1ad0,0x19a1,0x19a1,0x19a1,0x19a1,0x1ad3,
-0x1ad0,0x1ba2,0x19a1,0x1a28,0x19a1,0x19a1,0x19a1,0x19a1,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x18c0,0x19a1,
-0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,
-0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,
-0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,
-0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18c9,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,
+0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x18c6,0x19ad,0x19ad,0x19ad,0x19ad,0x19ad,
+0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ad9,0x1ba5,0x1ba5,0x1ba5,
0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,
-0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x1ba5,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,
-0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,
-0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x18cf,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,
-0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,
-0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x1941,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,
-0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,
-0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x195c,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,
-0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,
-0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x1962,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,
-0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,
-0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x197d,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,
-0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,
-0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1980,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,
-0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,0x1989,
-0x1989,0x1989,0x1989,0x1989,0x1989,0x1986,0x1986,0x1986,0x19a1,0x19a1,0x19a1,0x1ad0,0x1ad0,0x1a28,0x1a28,0x1a28,
-0x1a28,0x1a28,0x1a28,0x1ad0,0x1ad0,0x1ad0,0x1a28,0x1a28,0x19a1,0x19a1,0x19a1,0x19a1,0x19a1,0x19a4,0x19a4,0x19a1,
-0x19a4,0x19a4,0x1a28,0x1a2b,0x1a28,0x1a28,0x1a28,0x1a28,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,
-0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,
-0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x19dd,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,
-0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,
-0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a04,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,
-0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a43,0x1a43,0x1a0d,0x1a43,0x1a0d,0x1a0d,0x1a0d,0x1a0d,
-0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a0d,0x1a13,0x1a13,0x1a13,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,
+0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,0x18cc,
+0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3,
+0x19b3,0x1a3a,0x1ae2,0x19b3,0x19b3,0x19b3,0x19b3,0x1ae5,0x1ae2,0x1bb4,0x19b3,0x1a3a,0x19b3,0x19b3,0x19b3,0x19b3,
+0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x18d2,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,
+0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,
+0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,
+0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,0x18db,
+0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,
+0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x18de,0x1bb7,
+0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,
+0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,0x18e1,
+0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,
+0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,0x1953,
+0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,
+0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,0x196e,
+0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,
+0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,0x1974,
+0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,
+0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,0x198f,
+0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,
+0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,0x1992,
+0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,
+0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x199b,0x1998,0x1998,0x1998,
+0x19b3,0x19b3,0x19b3,0x1ae2,0x1ae2,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1a3a,0x1ae2,0x1ae2,0x1ae2,0x1a3a,0x1a3a,
+0x19b3,0x19b3,0x19b3,0x19b3,0x19b3,0x19b6,0x19b6,0x19b3,0x19b6,0x19b6,0x1a3a,0x1a3d,0x1a3a,0x1a3a,0x1a3a,0x1a3a,
+0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,
+0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,0x19ef,
+0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,
+0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,0x1a16,
0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,
-0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,
-0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,
-0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1ab2,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,
-0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,
-0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1abe,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,
-0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,
-0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae2,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,
-0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,
-0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1ae5,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,
-0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,
-0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b5a,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
-0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,
-0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b7b,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
+0x1a55,0x1a55,0x1a1f,0x1a55,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a1f,0x1a25,0x1a25,0x1a25,
+0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,
+0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,0x1a31,
+0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,
+0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,0x1ac4,
+0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,
+0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,0x1ad0,
+0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,
+0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,0x1af4,
+0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,
+0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,0x1af7,
+0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,
+0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,0x1b6c,
+0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,
-0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b8d,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,
-0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,
-0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0x1b90,0,0,0,0
+0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,
+0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,0x1b9f,
+0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,
+0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,0x1ba2,
+0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,0x1bfc,
+0x1bfc,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,0x1bf9,
+0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,
+0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,0x1c3b,
+0,0,0,0
};
static const UTrie2 propsVectorsTrie={
propsVectorsTrie_index,
- propsVectorsTrie_index+5188,
+ propsVectorsTrie_index+5348,
NULL,
- 5188,
- 26872,
+ 5348,
+ 27344,
0xa40,
- 0x14c4,
+ 0x1564,
0x0,
0x0,
0x110000,
- 0x7d38,
- NULL, 0, FALSE, FALSE, 0, NULL
+ 0x7fb0,
+ NULL, 0, false, false, 0, NULL
};
-static const uint32_t propsVectors[7095]={
+static const uint32_t propsVectors[7230]={
0x67,0,0,0x67,0,0xe00000,0x67,0x80000,0x20,0x867,0,0,0xa67,0,0,0xb67,
0,0,0xd67,0,0,0xe67,0,0,0x1067,0,0,0x1167,0,0,0x1267,0,
0,0x1367,0,0,0x1467,0,0,0x1567,0,0,0x1667,0,0,0x1767,0,0,
@@ -3493,429 +3554,437 @@ static const uint32_t propsVectors[7095]={
0,0xad67,0,0,0xae67,0,0,0xaf67,0,0,0xb167,0,0,0xb267,0,0,
0xb467,0,0,0xb567,0,0,0xb767,0,0,0xb867,0,0,0xb967,0,0,0xba67,
0,0,0xbc67,0,0,0xbd67,0,0,0xbe67,0,0,0xbf67,0,0,0xc067,0,
-0,0xc167,0,0,0xc267,0,0,0xc367,0,0xe00000,0xc467,0,0xe00000,0xc667,0,0,
-0xc767,0,0,0xc867,0,0,0xc967,0,0,0xca67,0,0,0xcc67,0,0xe00000,0xcf67,
-0,0xe00000,0xd067,0,0xe00000,0xd367,0,0,0xd467,0,0,0xd567,0,0,0xd667,0,
-0,0xd867,0,0,0xda67,0,0,0xdb67,0,0,0xdc67,0,0,0xdd67,0,0,
-0xde67,0,0,0xdf67,0,0,0xe067,0,0,0xe167,0,0,0xe267,0,0,0xe367,
-0,0xe00000,0xe467,0,0,0xe567,0,0,0xe667,0,0,0xe767,0,0,0xe867,0,
-0,0xe967,0,0,0xea67,0,0,0xeb67,0,0,0xec67,0,0,0xed67,0,0,
-0xee67,0,0,0xef67,0,0,0xf167,0,0,0xf367,0,0,0xf567,0,0,0xf667,
-0,0,0xf767,0,0,0xf867,0,0,0xf967,0,0,0xfa67,0,0xe00000,0xfb67,0,
-0,0xfc67,0,0,0xfd67,0,0,0xfe67,0,0,0x10167,0,0,0x10267,0,0,
-0x10367,0,0,0x10467,0,0,0x10667,0,0,0x10767,0,0,0x10867,0,0,0x10967,
-0,0,0x10a67,0,0,0x10b67,0,0,0x10c67,0,0,0x10d67,0,0,0x10e67,0,
-0,0x10f67,0,0,0x11067,0,0,0x11367,0,0,0x11467,0,0,0x11567,0,0,
-0x11667,0,0,0x11767,0,0,0x11867,0,0,0x11967,0,0xe00000,0x11a67,0,0,0x11b67,
-0,0,0x11c67,0,0,0x11d67,0,0,0x11e67,0,0,0x11f67,0,0,0x12067,0,
-0,0x12167,0,0,0x12267,0,0,0x12367,0,0,0x12467,0,0,0x12567,0,0,
-0x12667,0,0,0x12767,0,0,0x12867,0,0,0x12967,0,0,0x12a67,0,0xe00000,0x12b67,
-0,0,0x12c67,0,0,0x12d67,0,0,0x12f67,0,0,0x13067,0,0,0x13167,0,
-0,0x13267,0,0,0x13367,0,0,0x13467,0,0,0x13567,0,0,0x13667,0,0,
-0x13767,0,0,0x13867,0,0,0x13967,0,0,0x13a67,0,0,0x13b67,0,0,0x13c67,
-0,0,0x13d67,0,0,0x13f67,0,0,0x14067,0,0,0xa0067,0,0xe00000,0xa4f67,0,
-0xe00000,0xa5f67,0,0xe00000,0xac567,0,0xe00000,0xad167,0,0xe00000,0xb0067,0,0xe00000,0xb1267,0,0xe00000,
-0xb2e67,0,0xe00000,0x11000100,0,0x900020,0x11000100,0x40000001,0x440020,0x11000100,0x40000001,0x643020,0x11000100,0x40000001,0xa5a040,0x11000100,
-0x40000001,0x116a8a0,0x11000200,0,0x900020,0x11000200,0x4000001,0xc4000b,0x11000200,0x7c00100,0x220402,0x11000200,0x24000000,0x200000,0x11000200,0x24000008,
-0x1710000,0x11000200,0x40000001,0x1d3b020,0x11000219,0x7c00100,0x220401,0x11000219,0x7c00100,0x250401,0x11000319,0x7c00100,0x220401,0x11000319,0x7c00100,0x220402,
-0x11000319,0x7c00100,0x250400,0x11000319,0x7c00100,0x250401,0x11000419,0x7c00100,0x220400,0x11000419,0x7c00100,0x220401,0x11000419,0x7c00100,0x220402,0x11000419,
-0x7c00100,0x230400,0x11000419,0x7c00100,0x250400,0x11000419,0x7c00100,0x250401,0x11000419,0x7c00100,0x250402,0x11000519,0x7c00100,0x220400,0x11000519,0x7c00100,
-0x230400,0x11000600,0x4000400,0x200002,0x11000600,0x4000400,0x200400,0x11000600,0x7c00500,0x220400,0x11000600,0x7c00500,0x230400,0x11000600,0x7c00500,0x530400,
-0x11000600,0x7c00d00,0x230400,0x11000619,0x7c00500,0x22040f,0x11000800,0x4000010,0x1001401,0x11000800,0x4000400,0x200001,0x11000800,0x6800010,0x201001,0x11000800,
-0x7c00500,0x230401,0x11000807,0x7c00100,0x220400,0x11000807,0x7c00100,0x250400,0x1100080e,0x4000400,0x200000,0x1100080e,0x4000400,0x200002,0x1100080e,0x7000500,
-0x220402,0x1100080e,0x7c00100,0x220400,0x1100080e,0x7c00100,0x220401,0x1100080e,0x7c00100,0x220402,0x1100080e,0x7c00100,0x250400,0x1100080e,0x7c00100,0x250401,
-0x1100080e,0x7c00120,0x220402,0x1100080e,0x7c00120,0x250402,0x11000908,0x4000000,0x200000,0x11000908,0x7c00100,0x220400,0x11000908,0x7c00100,0x220401,0x11000908,
-0x7c00100,0x250400,0x11000908,0x7c00100,0x250401,0x11000a03,0x4000000,0x200400,0x11000a03,0x4000000,0x201000,0x11000a03,0x4000000,0x270000,0x11000a03,0x7c00100,
-0x220400,0x11000a03,0x7c00100,0x220402,0x11000a03,0x7c00100,0x250400,0x11000a03,0x7c00500,0x230400,0x11000a03,0xc000010,0x1049400,0x11000b13,0x2802500,0x962460,
-0x11000b13,0x4000000,0x200000,0x11000b13,0x4000000,0x201000,0x11000b13,0x4000000,0x230400,0x11000b13,0x4000002,0x400000,0x11000b13,0x4000010,0x200000,0x11000b13,
-0x7c00100,0x2633800,0x11000c00,0x80000000,0x218960,0x11000c02,0x2802100,0x962460,0x11000c02,0x2802400,0x962460,0x11000c02,0x4000000,0x200000,0x11000c02,0x4000000,
-0x1329400,0x11000c02,0x4000000,0x1329800,0x11000c02,0x4000000,0x1500000,0x11000c02,0x6800000,0x1329800,0x11000c02,0x7c00100,0x230400,0x11000c02,0x7c00100,0x230401,
-0x11000c02,0x7c00100,0x230402,0x11000c02,0x7c00500,0x230400,0x11000c02,0x7d00100,0x230400,0x11000f01,0x2802400,0x962460,0x11000f0a,0x2802100,0x962460,0x11000f0a,
-0x2802400,0x962460,0x11000f0a,0x2806400,0x962460,0x11000f0a,0x4000000,0x200000,0x11000f0a,0x6800100,0x962540,0x11000f0a,0x7c00100,0x230400,0x11000f0a,0x7c00100,
-0x230401,0x11001004,0x2802100,0x962460,0x11001004,0x2802400,0x962460,0x11001004,0x2806400,0x962460,0x11001004,0x4000000,0x200000,0x11001004,0x4000000,0x1500000,
-0x11001004,0x6800100,0x962540,0x11001004,0x6800100,0x962541,0x11001004,0x7c00100,0x230400,0x11001004,0x7c00100,0x230401,0x11001110,0x2802100,0x962460,0x11001110,
-0x2802400,0x962460,0x11001110,0x2806400,0x962460,0x11001110,0x6800100,0x962540,0x11001110,0x7c00100,0x230400,0x11001110,0x7c00100,0x230401,0x1100120f,0x2802100,
-0x962460,0x1100120f,0x2802400,0x962460,0x1100120f,0x2806400,0x962460,0x1100120f,0x6800100,0x962540,0x1100120f,0x7c00100,0x230400,0x1100131f,0x2802100,0x962460,
-0x1100131f,0x2802400,0x962460,0x1100131f,0x2806400,0x962460,0x1100131f,0x4000000,0x200000,0x1100131f,0x6800000,0x1329800,0x1100131f,0x6800100,0x962540,0x1100131f,
-0x6800100,0x962541,0x1100131f,0x7c00100,0x230400,0x1100131f,0x7c00100,0x230401,0x11001423,0x2802100,0x962460,0x11001423,0x2806400,0x962460,0x11001423,0x6800100,
-0x962540,0x11001423,0x6800100,0x962541,0x11001423,0x7c00100,0x230400,0x11001423,0x7c00100,0x230401,0x11001524,0x2802100,0x962460,0x11001524,0x2802100,0x962461,
-0x11001524,0x2806400,0x962460,0x11001524,0x6800000,0x1329800,0x11001524,0x6800100,0x962540,0x11001524,0x7c00100,0x230400,0x11001615,0x2802100,0x962460,0x11001615,
-0x2806400,0x962460,0x11001615,0x6800100,0x962540,0x11001615,0x6800100,0x962541,0x11001615,0x7c00100,0x230400,0x1100171a,0x2802100,0x962460,0x1100171a,0x2806400,
-0x962460,0x1100171a,0x6800000,0x1329800,0x1100171a,0x6800100,0x962540,0x1100171a,0x6800100,0x962541,0x1100171a,0x7c00100,0x230400,0x11001900,0x4000000,0x1600000,
-0x11001926,0x2802100,0x1862460,0x11001926,0x2802400,0x1862460,0x11001926,0x2806100,0x1862460,0x11001926,0x4000000,0x200000,0x11001926,0x4000010,0x400000,0x11001926,
-0x6800000,0x1329800,0x11001926,0x7800100,0x1830142,0x11001926,0x7c00100,0x1830000,0x11001926,0x7c00900,0x1830000,0x11001926,0x7e00100,0x1830000,0x11001a18,0x2802100,
-0x1862460,0x11001a18,0x2802400,0x1862460,0x11001a18,0x6800000,0x1329800,0x11001a18,0x7800100,0x1830142,0x11001a18,0x7c00100,0x1830000,0x11001a18,0x7c00100,0x1830002,
-0x11001a18,0x7c00900,0x1830000,0x11001a18,0x7e00100,0x1830000,0x11001d0c,0x7c00100,0x230400,0x11001d0c,0x7c00100,0x250400,0x11001e12,0x7c00100,0x2230500,0x11001e12,
-0x7c00100,0x2330520,0x11001e12,0x7c80100,0x2330520,0x11002619,0x7c00100,0x220401,0x11002619,0x7c00100,0x220402,0x11002619,0x7c00100,0x250401,0x1100270e,0x4000400,
-0x200001,0x1100270e,0x4000400,0x200002,0x1100270e,0x4000400,0x500001,0x1100270e,0x7c00100,0x220401,0x1100270e,0x7c00100,0x250401,0x11002800,0x80000,0x918820,
-0x11002800,0x80000,0x1c18020,0x11002800,0x180000,0x918820,0x11002800,0x4000001,0x445801,0x11002800,0x4000001,0x445802,0x11002800,0x4000001,0xc4000b,0x11002800,
-0x6800000,0x201c00,0x11002800,0x6800020,0x201c00,0x11002800,0x24000000,0x200000,0x11002800,0x24000000,0x200002,0x11002800,0x24000000,0x810000,0x11002800,0x24000000,
-0x1410000,0x11002800,0x24000000,0x1500000,0x11002800,0x24000000,0x1500002,0x11002800,0x24000002,0x400000,0x11002800,0x24000006,0xc0000b,0x11002800,0x24000008,0x1410000,
-0x11002800,0x24000008,0x1710000,0x11002800,0x24000020,0x1001400,0x11002800,0x24000020,0x1500002,0x11002800,0x2c000010,0x1248000,0x11002800,0x2c000010,0x1248002,0x11002800,
-0x40000001,0x63b020,0x11002800,0x40080000,0x918820,0x11002801,0x80000,0x2a65620,0x11002801,0x82000,0x962460,0x11002900,0x4000000,0x20000e,0x11002900,0x4000000,
-0x20000f,0x11002900,0x4000020,0x20000e,0x11002900,0x4000020,0x20000f,0x11002900,0x4000020,0x81000e,0x11002900,0x4000020,0x81000f,0x11002900,0x4000020,0x141000e,
-0x11002900,0x4000020,0x141000f,0x11002900,0x4000022,0x20000e,0x11002900,0x4000022,0x20000f,0x11002a00,0x4000000,0x1500000,0x11002a00,0x4000000,0x1600000,0x11002a00,
-0x4000000,0x1600002,0x11002b01,0x2000,0x962460,0x11002b01,0x2802020,0x962460,0x11002c00,0x4000000,0x200000,0x11002c00,0x4000000,0x200002,0x11002c00,0x4000000,
-0x20000f,0x11002c00,0x4000020,0x200000,0x11002c00,0x7c00000,0x200000,0x11002c00,0x7c00020,0x200000,0x11002c00,0x7c00120,0x220405,0x11002c00,0x7c00120,0x230402,
-0x11002c00,0x7c00120,0x250402,0x11002c00,0x7c00120,0x250405,0x11002c19,0x7c00100,0x250400,0x11002c19,0x7c00100,0x250401,0x11002d00,0x4000000,0x100006,0x11002d00,
-0x4000000,0x200006,0x11002d19,0x7c00100,0x220402,0x11002d19,0x7c00100,0x230400,0x11002d19,0x7c00100,0x250402,0x11002e00,0x24000000,0x200000,0x11002e00,0x24000020,
-0x200000,0x11002e00,0x24000020,0x200001,0x11002f00,0x24000020,0x200000,0x11002f00,0x24000020,0x200001,0x11002f00,0x24000020,0x200002,0x11002f00,0x24000020,0xf00000,
-0x11002f00,0x24000020,0x1600000,0x11002f00,0x24000022,0x1600000,0x11003000,0x24000000,0x200000,0x11003000,0x24000020,0x200000,0x11003000,0x24000020,0x810000,0x11003000,
-0x24000020,0x1410000,0x11003100,0x24000000,0x200000,0x11003200,0x24000000,0x200000,0x11003300,0x4000000,0x100003,0x11003400,0x24000000,0x100000,0x11003400,0x24000000,
-0x200000,0x11003500,0x24000000,0x200000,0x11003600,0x24000000,0x200000,0x11003600,0x24000020,0x200000,0x11003700,0x24000000,0x200000,0x11003700,0x24000000,0xe00000,
-0x11003700,0x24000000,0x2800000,0x11003700,0x24000020,0x200000,0x11003800,0x4000000,0x100000,0x11003800,0x24000000,0x200000,0x11003800,0x24000000,0xb00000,0x11003800,
-0x24000000,0xe00000,0x11003800,0x24000000,0x1710000,0x11003800,0x24000000,0x2800000,0x11005003,0x7c00100,0x220402,0x11005013,0x2802500,0x962460,0x11005013,0x4000020,
-0x200005,0x11005013,0x7c00100,0x2633801,0x11005013,0x7c00100,0x2633802,0x11005013,0x7c00100,0x2633805,0x11005019,0x7c00100,0x220402,0x11005102,0x7000100,0x230408,
-0x11005102,0x7c00100,0x230404,0x11005102,0x7c00100,0x230407,0x11005102,0x7c00100,0x230408,0x11005102,0x7c00100,0x230409,0x11005201,0x2802400,0x962460,0x11005500,
-0x80000,0x1e18820,0x11005502,0x7000100,0x230408,0x11005502,0x7c00100,0x230404,0x11005502,0x7c00100,0x230407,0x11005502,0x7c00100,0x230408,0x11005502,0x7c00100,
-0x230409,0x11005667,0x1000,0,0x11020200,0x80004,0x418820,0x11020200,0x4000000,0x100006,0x11020200,0x4000000,0x10000f,0x11020200,0x4000400,0x100002,
-0x11020200,0x4000400,0x500002,0x11020200,0x6800c00,0x101000,0x11020200,0x24000000,0x100000,0x11020200,0x24000000,0x200000,0x11020200,0x24000000,0x1400000,0x11020200,
-0x24000000,0x1500000,0x11020200,0x24000000,0x1600000,0x11020200,0x24000020,0x100000,0x11020200,0x24000020,0x1600000,0x11020219,0x7c00100,0x12040f,0x11020219,0x7c00100,
-0x220400,0x11020219,0x7c00100,0x220401,0x11020219,0x7c00100,0x250400,0x11020319,0x7c00100,0x220400,0x11020319,0x7c00100,0x220401,0x11020319,0x7c00100,0x220402,
-0x11020319,0x7c00100,0x250400,0x11020319,0x7c00100,0x250402,0x11020319,0x7d00100,0x220402,0x11020419,0x7c00100,0x220401,0x11020519,0x7c00100,0x220400,0x11020600,
-0x4000400,0x100002,0x11020600,0x4000400,0x200400,0x11020600,0x7c00500,0x130400,0x11020600,0x7c00d00,0x130400,0x11020701,0x2802400,0x962460,0x11020701,0x2802400,
-0x962461,0x11020701,0x2802400,0xc62460,0x1102080e,0x7c00100,0x220400,0x1102080e,0x7c00100,0x250400,0x11020908,0x7c00100,0x220400,0x11020908,0x7c00100,0x220401,
-0x11020908,0x7c00100,0x250400,0x11020908,0x7c00100,0x250401,0x11022800,0x24000000,0x100000,0x11022800,0x24000000,0x200000,0x11022800,0x24000000,0x200002,0x11022800,
-0x24000000,0x401000,0x11022800,0x24000000,0xf00002,0x11022800,0x24000000,0xf0ac02,0x11022800,0x24000000,0x1500000,0x11022800,0x24000002,0x100000,0x11022800,0x24000002,
-0x370000,0x11022800,0x24000002,0x470000,0x11022800,0x24000006,0x400000,0x11022800,0x24000008,0x1710000,0x11022800,0x24000008,0x1712c00,0x11022800,0x24000020,0x100000,
-0x11022800,0x24000020,0x1500000,0x11022800,0x24000020,0x1500002,0x11022900,0x4000000,0x10000e,0x11022900,0x4000000,0x10000f,0x11022919,0x7c00100,0x12040f,0x11022c00,
-0x4000000,0x100002,0x11022c00,0x4000000,0x10000f,0x11022c00,0x4000000,0x1500002,0x11022c00,0x4000000,0x1600002,0x11022c00,0x7c00120,0x120405,0x11022c0e,0x7c00100,
-0x250401,0x11022c19,0x7c00100,0x150401,0x11022d00,0x4000000,0x100006,0x11022d00,0x4000000,0x200006,0x11022d19,0x7c00100,0x120402,0x11022d19,0x7c00100,0x150402,
-0x11022e00,0x24000000,0x200000,0x11022e00,0x24000020,0x100000,0x11022f00,0x24000020,0x100000,0x11022f00,0x24000020,0x100001,0x11022f00,0x24000020,0x100002,0x11023000,
-0x24000000,0x100000,0x11023300,0x4000000,0x100002,0x11023300,0x4000000,0x100003,0x11023300,0x4000100,0x120403,0x11023300,0x4000100,0x150403,0x11023400,0x24000000,
-0x100000,0x11023500,0x24000000,0x100000,0x11023600,0x24000000,0x100000,0x11023600,0x24000020,0x100000,0x11023700,0x24000000,0x100000,0x11023700,0x24000000,0xe00000,
-0x11023700,0x24000020,0x100000,0x11023800,0x4000000,0x100000,0x11023800,0x24000000,0x200000,0x11024e67,0,0,0x11025600,0x4000000,0x100000,0x11042a00,
-0x4000000,0x1600000,0x11045700,0x4000000,0x20000a,0x11045700,0x4000020,0x20000a,0x11045712,0x7c00100,0xe3040a,0x11045712,0x7c80100,0xe3040a,0x11045716,0x7c00100,
-0xe30c0a,0x11045716,0x7c00100,0x2530c0a,0x11063d00,0x4000001,0x445811,0x11065700,0x4000000,0x810011,0x11065700,0x4000000,0xe00011,0x11065700,0x4000000,0x1410011,
-0x11065700,0x4000000,0x1500011,0x11065700,0x4000000,0x1600011,0x11065700,0x4000006,0xe70011,0x11065700,0x4000008,0xe00011,0x11065700,0x4000008,0xe02c11,0x11065700,
-0x4000010,0x871411,0x11065700,0x4000010,0x1201411,0x11065700,0x4000010,0x1271011,0x11065700,0x4000020,0xe00011,0x11065700,0x4000400,0xe00011,0x11065700,0x4000420,
-0xe00011,0x11065700,0x6800000,0xe01c11,0x11065700,0x6800040,0xe29811,0x11065700,0xc000010,0x80ac11,0x11065700,0xc000010,0xb48011,0x11065719,0x7c00100,0xe20411,
-0x11065719,0x7c00100,0xe50411,0x11065719,0x7c00140,0xe20411,0x11065719,0x7c00140,0xe50411,0x11080100,0x6800000,0x201c00,0x11080100,0x68000c0,0x1329800,0x11080100,
-0x24000000,0x200000,0x11080100,0x24000000,0x810000,0x11080100,0x24000000,0x1410000,0x11080100,0x24000000,0x1500000,0x11080100,0x24000000,0x1600000,0x11080100,0x24000000,
-0x1b00000,0x11080100,0x24000000,0x2410000,0x11080100,0x24000006,0xd70000,0x11080100,0x24000008,0x1713c00,0x11080100,0x24000008,0x1714000,0x11080100,0x24000010,0x1001400,
-0x11080100,0x24000010,0x1071000,0x11080100,0x24000010,0x1071400,0x11080100,0x24000020,0x200000,0x11080100,0x24000020,0x400000,0x11080100,0x24000020,0x1600000,0x11080100,
-0x24000400,0x200000,0x11080100,0x24000420,0x200000,0x11080100,0x2c000010,0xb48000,0x11080100,0x2c000010,0x100ac00,0x11080100,0x44000001,0x1a45800,0x11080119,0x7c00100,
-0x220400,0x11080119,0x7c00100,0x250400,0x11080119,0x7c001c0,0x220400,0x11080119,0x7c001c0,0x250400,0x11080200,0x4000400,0x200002,0x11080200,0x24000000,0x200000,
-0x11080200,0x24000000,0x1500000,0x11080200,0x24000000,0x1600000,0x11080200,0x24000020,0x200000,0x110a1e12,0x7c00100,0x2130480,0x110a1e12,0x7c80100,0x2130480,0x110a3000,
-0x24000000,0xe00000,0x110a3000,0x24100000,0x810001,0x110a3000,0x24100000,0x1410001,0x110a3700,0x24000000,0x200000,0x110a3d00,0x4000000,0xe00000,0x110a3d00,0x4000000,
-0xe00002,0x110a3d00,0x24000000,0xe00000,0x110a3d11,0x7c00300,0xe30000,0x110a3d11,0x7c00900,0x1230400,0x110a3d12,0x2802400,0x962460,0x110a3e14,0x7c00100,0xe30000,
-0x110a3e14,0x7c00100,0xe30001,0x110a3e14,0x7c00100,0x2530000,0x110a3e14,0x7c00900,0x1230000,0x110a3e14,0x7c00900,0x1230001,0x110a3f16,0x7c00100,0xe30c00,0x110a3f16,
-0x7c00100,0xe30c01,0x110a3f16,0x7c00100,0x2530c00,0x110a3f16,0x7c00900,0x1230c00,0x110a3f16,0x7c00900,0x1230c01,0x110a4005,0x7c00100,0xe30400,0x110a4112,0x7c00100,
-0xe30402,0x110a4112,0x7c80100,0xe30402,0x110a4400,0x4000000,0xe00000,0x110a4412,0x4000000,0xe00002,0x110a4412,0x4000000,0xe00003,0x110a4416,0x4000000,0xe00c03,
-0x110a4500,0x4000000,0xe0000d,0x110a4516,0x4000000,0xe00c0d,0x110a4711,0x7c40300,0xe30000,0x110a4f11,0x7c00300,0xe30001,0x110a4f11,0x7c40300,0xe30000,0x110a5300,
-0x4000000,0x810010,0x110a5300,0x4000000,0xe00002,0x110a5300,0x4000000,0xe00010,0x110a5300,0x4000000,0x1410010,0x110a5300,0x4000002,0xe70010,0x110a5300,0x4000008,
-0x810010,0x110a5300,0x4000008,0x1410010,0x110a5300,0x6800000,0xe01c02,0x110a5300,0x6800000,0xe01c10,0x110a5400,0x4000000,0x81000c,0x110a5400,0x4000000,0xe0000c,
-0x110a5400,0x4000000,0x141000c,0x110a5400,0x4000000,0x150000c,0x110a5400,0x4000000,0x160000c,0x110a5400,0x4000002,0xe7000c,0x110a5400,0x4000010,0x87140c,0x110a5400,
-0x4000010,0xe7000c,0x110a5400,0x4000010,0x120140c,0x110a5400,0x4000010,0x127100c,0x110a5400,0x4000020,0xe0000c,0x110a5400,0x4000026,0xe7000c,0x110a5400,0xc000010,
-0x80ac0c,0x110a5400,0xc000010,0xb4800c,0x11400c0c,0x4000010,0xb00000,0x11400c0c,0x4000010,0x1071400,0x11400c17,0xc000010,0xb48000,0x11400c1e,0x7c00900,0x230400,
-0x11400f4b,0xc000010,0x448000,0x11400f5f,0xc000010,0x448000,0x11401d94,0x4000000,0x200000,0x11403dca,0x4000000,0xe00000,0x114457bf,0x4000004,0x120000a,0x114457bf,
-0x4000008,0x81000a,0x114457bf,0x4000008,0x141000a,0x114457bf,0x4000010,0x87000a,0x114457bf,0xc000010,0x84800a,0x114457c8,0x3802500,0x126246a,0x114457c8,0x7c00d00,
-0x2530c0a,0x114a3dbf,0x24000000,0x810000,0x114a3dbf,0x24000000,0x1410000,0x114a3dbf,0x24000008,0x810000,0x114a3dbf,0x24000008,0x1410000,0x114a3dbf,0x24000010,0x870000,
-0x114a3dbf,0x2c000010,0x848000,0x114a3dc5,0x4000000,0xe00000,0x114a3dc5,0x24000000,0xe00000,0x114a3dc5,0x24000002,0xe00000,0x114a3dc5,0x24000002,0x1200000,0x114a3dc5,
-0x24000008,0x810000,0x114a3dc5,0x24000008,0x1410000,0x114a3dc8,0x7c00900,0x930c00,0x114a3dc8,0x7c00900,0xe30c00,0x114a3dca,0x7c00300,0xe30000,0x114a3ec8,0x7000400,
-0x1200c02,0x114a3fbf,0x4000004,0x1200000,0x114a3fc8,0x7c00d00,0x2530c00,0x114a42ca,0x4000000,0xe00000,0x114a42ca,0x4000000,0xe0000f,0x114a44ca,0x4000000,0xe00002,
-0x114a44ca,0x4000000,0xe00003,0x114a45ca,0x4000000,0xe00002,0x114a45ca,0x4000000,0xe0000d,0x11505103,0x24000000,0x810000,0x11505103,0x24000000,0x1410000,0x1180090a,
-0x2802400,0x962460,0x11800c27,0x2802100,0x962460,0x11800c27,0x2802500,0x962460,0x11800f32,0x2802400,0x962460,0x11800f3f,0x2802400,0x962460,0x11820700,0x2802400,
-0x962460,0x11820700,0x2802500,0x962460,0x118a3dcb,0x2802400,0x962460,0x118a3ec8,0x2802400,0x962460,0x11c00904,0x2802400,0x962460,0x11c00908,0x2802400,0x962460,
-0x11c00c2c,0x6800000,0x1329800,0x11c00c30,0xc000010,0xb48000,0x11c00f78,0x6800000,0x1329800,0x11c0107d,0x6800000,0x1329800,0x11c01181,0x6800000,0x1329800,0x11c01285,
-0x6800000,0x1329800,0x11c01489,0x4000000,0x200000,0x11c01489,0x6800000,0x1329800,0x11c0168d,0x6800000,0x1329800,0x11d05107,0x7c00100,0x230408,0x20000067,0x1000,
-0,0x20000b13,0x2802400,0x962460,0x20000b13,0x2802500,0x962460,0x20001b27,0x2802100,0x962460,0x20001b27,0x2802100,0x962461,0x20001b27,0x2802400,0x962460,
-0x20001b27,0x2806400,0x962460,0x20001b27,0x2902100,0x962462,0x20001b27,0x4000000,0x200000,0x20001b27,0x4000000,0x400000,0x20001b27,0x4000000,0x500000,0x20001b27,
-0x4000000,0x810000,0x20001b27,0x4000000,0xb00000,0x20001b27,0x4000000,0xc0000b,0x20001b27,0x4000000,0x1410000,0x20001b27,0x4000010,0xb00000,0x20001b27,0x4000010,
-0xc00000,0x20001b27,0x6800000,0x1329800,0x20001b27,0x6800100,0x462540,0x20001b27,0x6800400,0x962540,0x20001b27,0x7c00100,0x230400,0x20001b27,0x7c00100,0x230401,
-0x20002619,0x7c00100,0x220401,0x20002a00,0x4000000,0x1600000,0x20004b67,0,0x1900000,0x20004c67,0,0x1900000,0x20004d67,0,0x1900000,0x20006d67,
-0x1000,0,0x20006e67,0x1000,0,0x20026d67,0,0,0x20026e67,0,0,0x200a4a12,0x7c00100,0x1f304c1,0x200a4a12,0x7c00100,
-0x20304e1,0x21005600,0x4000000,0x700000,0x21022a00,0x4000000,0x1600000,0x30000419,0x7c00100,0x220400,0x30000419,0x7c00100,0x220401,0x30000419,0x7c00100,0x250400,
-0x30000419,0x7c00100,0x250401,0x30000519,0x7c00100,0x220400,0x30000600,0x4000400,0x200400,0x30000600,0x7c00500,0x230400,0x30000605,0x4000400,0x200400,0x3000080e,
-0x7c00100,0x220400,0x30000908,0x2000,0x962460,0x30000908,0x7c00100,0x220400,0x30000908,0x7c00100,0x220401,0x30000908,0x7c00100,0x250400,0x30000908,0x7c00100,
-0x250401,0x30000a03,0x4000006,0x400400,0x30000c02,0x4000000,0x200000,0x30000c02,0x7c00100,0x230400,0x30000d22,0x2802100,0x962460,0x30000d22,0x2802400,0x962460,
-0x30000d22,0x2802500,0x962460,0x30000d22,0x4000000,0x200000,0x30000d22,0x4000010,0x200000,0x30000d22,0x7c00100,0x230400,0x30000d22,0xc000010,0x248000,0x30000d22,
-0x80000000,0x218960,0x30000e25,0x2802500,0x962460,0x30000e25,0x7c00100,0x230400,0x30001821,0x2802100,0x962460,0x30001821,0x2806400,0x962460,0x30001821,0x4000000,
-0x200000,0x30001821,0x6800100,0x962540,0x30001821,0x6800100,0x962541,0x30001821,0x7c00100,0x230400,0x30001b27,0x2802100,0x962460,0x30001b27,0x2802400,0x962460,
-0x30001b27,0x4000000,0x200000,0x30001b27,0x4000000,0x400000,0x30001b27,0x7c00100,0x230400,0x30001c1c,0x2802100,0x1862460,0x30001c1c,0x2802400,0x1862460,0x30001c1c,
-0x2806400,0x1862460,0x30001c1c,0x4000000,0x200000,0x30001c1c,0x6800100,0x1862400,0x30001c1c,0x6800100,0x1862540,0x30001c1c,0x7c00100,0x1830000,0x30001c1c,0x7c00100,
-0x1830001,0x30001c1c,0xc000010,0x448000,0x30001f0b,0x4000000,0x200000,0x30001f0b,0x4000010,0x200000,0x30001f0b,0x4000010,0x400000,0x30001f0b,0x6800000,0x200000,
-0x30001f0b,0x7c00100,0x230400,0x30001f0b,0xc000010,0x248000,0x30002006,0x7c00100,0x250400,0x30002128,0x4000000,0x200000,0x30002128,0x7c00100,0x230400,0x30002128,
-0xc000010,0x248000,0x3000221d,0x4000000,0x810000,0x3000221d,0x4000000,0x1410000,0x3000221d,0x4000001,0x445800,0x3000221d,0x7c00100,0x230400,0x30002300,0x4000010,
-0x400000,0x30002320,0x7c00100,0x230400,0x30002417,0x2802100,0x1862460,0x30002417,0x2802400,0x1862460,0x30002417,0x2806400,0x1862460,0x30002417,0x2882000,0x1862460,
-0x30002417,0x4000000,0x200000,0x30002417,0x4000000,0x400000,0x30002417,0x4000000,0x1600000,0x30002417,0x4000010,0x400000,0x30002417,0x4000010,0x1200000,0x30002417,
-0x6800000,0x1329800,0x30002417,0x6800100,0x1862540,0x30002417,0x7c00100,0x1830000,0x30002417,0x7d00100,0x1830000,0x3000251b,0x80000,0xc18820,0x3000251b,0x2802100,
-0x962460,0x3000251b,0x3c02100,0x962460,0x3000251b,0x4000000,0x200000,0x3000251b,0x4000006,0x500000,0x3000251b,0x4000010,0x400000,0x3000251b,0x4000010,0xb70000,
-0x3000251b,0x4000800,0x200000,0x3000251b,0x6800000,0x1329800,0x3000251b,0x7c00100,0x230400,0x3000251b,0x7c00900,0x230400,0x3000251b,0xc000010,0xb48000,0x3000251b,
-0x12882000,0x962460,0x30002800,0x24000000,0x200000,0x30002800,0x2c000010,0x1248002,0x30002a00,0x4000000,0x1600000,0x30002b01,0x2000,0x962460,0x30002c00,0x4000000,
-0x200000,0x30002c00,0x7c00100,0x220405,0x30002d19,0x7c00100,0x250400,0x30002e00,0x24000000,0x200000,0x30003000,0x24000000,0x200000,0x30003100,0x24000000,0x200000,
-0x30003600,0x24000000,0x200000,0x30003700,0x24000000,0x200000,0x3000392e,0x24000000,0x200000,0x30005013,0x7c00100,0x2633801,0x30005600,0,0x918820,0x30020600,
-0x4000400,0x500400,0x30020701,0x2802400,0x962460,0x30020701,0x2802400,0xc62460,0x300a3a11,0x4020000,0xe00000,0x300a3a11,0x4020000,0xe00002,0x300a3b11,0x4020000,
-0xe00002,0x300a3c00,0x4008000,0xe00000,0x300a3c00,0x4010000,0xe00000,0x300a3d11,0x7c00300,0xe30002,0x300a4305,0x7c00100,0xe30400,0x300a4611,0x7c40300,0xe30000,
-0x300a4829,0x7c00100,0xe30400,0x300a4829,0x7c00900,0x1230400,0x300a4929,0x4000000,0xe00000,0x3040259a,0x4000010,0x400000,0x3040259a,0x4000010,0xb70000,0x3040259a,
-0xc000010,0xb48000,0x304028ba,0x4000001,0xc41c0b,0x304a3dca,0x4000000,0xe00000,0x30800c27,0x2802100,0x962460,0x30c01c92,0x6800000,0x1329800,0x3100080e,0x7c00120,
-0x220402,0x3100080e,0x7c00120,0x250402,0x31005167,0x1000,0,0x3100581e,0x4000000,0x200000,0x3100581e,0x7c00100,0x230400,0x3100590d,0x7c00100,0x230400,
-0x31005a09,0x7c00100,0x220400,0x31005a09,0x7c00100,0x250400,0x31005b00,0x4000000,0x200000,0x31005c00,0x80000,0x918820,0x31005c00,0x2802000,0x962460,0x31005c00,
-0x2802400,0x962460,0x31005c00,0x4000000,0x200000,0x31005c00,0x4000000,0x200001,0x31005c00,0x6800000,0x962540,0x31005c00,0x6800400,0x962540,0x31005c01,0x2802400,
-0x962460,0x31005d00,0x4000020,0x200005,0x31005d00,0x6800020,0x1329805,0x31005d00,0x7c00120,0x220405,0x31005d00,0x7c00120,0x250405,0x31006000,0x82000,0x962460,
-0x31006000,0x180000,0x918820,0x310a5e11,0x7c40300,0xe30000,0x310a5f11,0x7c00300,0xe30001,0x32000419,0x7c00100,0x250400,0x3200080e,0x4000020,0x200000,0x3200080e,
-0x7c00100,0x220400,0x3200080e,0x7c00100,0x250400,0x32000908,0x7c00100,0x220400,0x32000908,0x7c00100,0x250400,0x32000c02,0x7c00100,0x230400,0x32000e25,0x7c00100,
-0x230400,0x32001d0c,0x7c00100,0x230400,0x32002800,0x80000,0x1e18820,0x32002800,0x80020,0x218820,0x32002800,0x4000001,0x445802,0x32002800,0x24000000,0x200000,
-0x32002800,0x24000000,0x200002,0x32002800,0x24000020,0x200000,0x32002800,0x2c000010,0x1248002,0x32002919,0x7c00100,0x22040f,0x32002a00,0x4000000,0x1600000,0x32002b01,
-0x2000,0x962460,0x32002b01,0x2802000,0x962460,0x32002b01,0x2802020,0x962460,0x32002c00,0x4000000,0x200000,0x32002c00,0x4000020,0x200000,0x32002c00,0x4000020,
-0x200005,0x32002c00,0x7c00120,0x220405,0x32002c00,0x7c00120,0x250405,0x32002e00,0x24000020,0x200000,0x32002f00,0x24000020,0x200000,0x32003000,0x24000000,0x200000,
-0x32003000,0x24000020,0x200000,0x32003500,0x24000000,0x200000,0x32003600,0x24000020,0x200000,0x32003700,0x24000000,0x100000,0x32003700,0x24000000,0x200000,0x32003800,
-0x24000000,0x810000,0x32003800,0x24000000,0x1410000,0x32005102,0x4000000,0x1500008,0x32005502,0x7c00100,0x230400,0x32006108,0x7c00100,0x220400,0x32006108,0x7c00100,
-0x250400,0x3200622a,0x2802100,0x962460,0x3200622a,0x2806400,0x962460,0x3200622a,0x7c00100,0x230400,0x3200632b,0x2802100,0x962460,0x3200632b,0x6804000,0x962540,
-0x3200632b,0x7c00100,0x230400,0x3200642c,0x2802100,0x962460,0x3200642c,0x7c00100,0x230400,0x3200652d,0x2802100,0x962460,0x3200652d,0x7c00100,0x230400,0x32006600,
-0x24000020,0x200000,0x32006700,0x24000020,0x200000,0x32006800,0x24000020,0x200000,0x32006900,0x24000020,0x200000,0x32006900,0x24000020,0x810000,0x32006900,0x24000020,
-0x1410000,0x32006a00,0x24000020,0x200000,0x32006a00,0x24000020,0x200001,0x32006a00,0x24000020,0x200002,0x32020701,0x2882000,0xc62460,0x32023300,0x4000000,0x100000,
-0x32026c01,0x12882000,0x962460,0x32065700,0x4000000,0x810011,0x32065700,0x4000000,0x1410011,0x32086600,0x24000020,0x810000,0x32086600,0x24000020,0x1410000,0x32086900,
-0x24000020,0x810000,0x32086900,0x24000020,0x1410000,0x320a3600,0x24000020,0x200000,0x320a3d11,0x7c00100,0x1230400,0x320a3e14,0x7c00100,0xe30010,0x320a3e14,0x7c00100,
-0x2530000,0x320a3f16,0x7c00100,0xe30c10,0x320a4400,0x4000000,0xe00003,0x320a4929,0x4000000,0xe00000,0x320a4f11,0x7c00300,0xe30001,0x320a6b16,0x7c00100,0x2530c00,
-0x32406396,0xc000010,0x448000,0x324a3dcd,0x4000000,0xe00000,0x324a3dcd,0x7c00100,0x1230400,0x324a3fc8,0x4000002,0x1200c00,0x324a53c5,0x24000000,0xe00000,0x32820701,
-0x2802000,0x962460,0x40000419,0x7c00100,0x220400,0x40000519,0x7c00100,0x220400,0x40000600,0x4000400,0x200400,0x4000080e,0x7c00100,0x220400,0x4000080e,0x7c00100,
-0x250400,0x4000080e,0x7c00100,0x250402,0x40000c02,0x2802100,0x962460,0x40000c02,0x2802400,0x962460,0x40000c02,0x2802500,0x962460,0x40000c02,0x4000000,0x200000,
-0x40000c02,0x4000000,0x1071400,0x40000c02,0x7c00100,0x230400,0x40000c02,0x80000000,0x218960,0x40000d22,0x7c00100,0x230400,0x40000f0a,0x7c00100,0x230400,0x40001004,
-0x7c00100,0x230400,0x40001110,0x2802100,0x962460,0x40001110,0x6800100,0x962540,0x4000120f,0x2802100,0x962460,0x4000120f,0x4000000,0x1600000,0x4000120f,0x7c00100,
-0x230400,0x4000131f,0x7c00100,0x230400,0x40001423,0x4000000,0x200000,0x40001423,0x4000000,0x1600000,0x40001615,0x2802400,0x962460,0x40001615,0x7c00100,0x230400,
-0x40002417,0x2802400,0x1862460,0x40002417,0x4000000,0x200000,0x40002800,0x6800000,0x201c00,0x40002800,0x24000002,0x200000,0x40002c00,0x4000000,0x200002,0x40003000,
-0x24000000,0x200000,0x40003000,0x24000020,0x200000,0x40003700,0x24000000,0x200000,0x40005a09,0x7c00100,0x220400,0x40005a09,0x7c00100,0x250400,0x40005d00,0x7c00120,
-0x220405,0x40006f30,0x2802100,0x962460,0x40006f30,0x2802400,0x962460,0x40006f30,0x4000000,0x200000,0x40006f30,0x6800000,0x1329800,0x40006f30,0x6800100,0x962540,
-0x40006f30,0x7c00100,0x230400,0x40006f30,0xc000010,0xb48000,0x40007034,0x7c00100,0x1830000,0x40007117,0x4000000,0x200000,0x40007208,0x7c00100,0x220400,0x4000720e,
-0x7c00100,0x220400,0x4000720e,0x7c00500,0x22040e,0x4000720e,0x7c00500,0x22040f,0x40007219,0x7c00100,0x220400,0x40007219,0x7c00500,0x220400,0x40007219,0x7c00500,
-0x22040e,0x40007219,0x7c00500,0x22040f,0x40007300,0x24000000,0x200000,0x40007400,0x4000000,0x200000,0x40007531,0x7c00100,0x230400,0x40007631,0x7c00100,0x230400,
-0x40007835,0x4000010,0x400000,0x40007835,0x7c00100,0x230400,0x40007933,0x7c00100,0x230400,0x40007a32,0x6800000,0x1329800,0x40007a32,0x7c00100,0x230400,0x40007b2f,
-0x7c00100,0x230400,0x40007c00,0x4000000,0x200000,0x40020701,0x2802400,0x962460,0x40020701,0x2802400,0xc62460,0x40023300,0x4000000,0x200000,0x40027d01,0x12882000,
-0x962460,0x400a3700,0x24000000,0x200000,0x400a3700,0x24000000,0xe00000,0x400a4400,0x4000000,0xe0000d,0x400a4412,0x4000000,0xe00002,0x400a4412,0x4000000,0xe00003,
-0x400a4500,0x4000000,0xe0000d,0x400a5300,0x4000000,0x810010,0x400a5300,0x4000000,0x1410010,0x40507709,0x4000000,0x200000,0x4050770c,0x4000000,0x400000,0x4050770f,
-0x4000000,0x200000,0x4050770f,0x4000000,0x400000,0x40c01489,0x4000000,0x200000,0x40d05107,0x4000000,0x200000,0x41000419,0x7c00100,0x220400,0x41000419,0x7c00100,
-0x250400,0x4100080e,0x7c00100,0x220400,0x4100080e,0x7c00100,0x250400,0x41000908,0x7c00100,0x220400,0x41000908,0x7c00100,0x250400,0x41000b13,0x2802000,0x962460,
-0x41000b13,0x2802100,0x962460,0x41000b13,0x4000000,0xb00000,0x41000c02,0x2802100,0x962460,0x41000c02,0x4000000,0x1500000,0x41000c02,0xc000010,0xb48000,0x41000f0a,
-0x7c00100,0x230400,0x41001004,0x7c00100,0x230400,0x41001423,0x7c00100,0x230400,0x41001b27,0x4000000,0x500000,0x41001d0c,0x7c00100,0x230400,0x41001d0c,0x7c00100,
-0x23040f,0x41001f0b,0x2802400,0x962460,0x41001f0b,0x4000000,0x200000,0x41001f0b,0x7c00100,0x230400,0x41002800,0x24000000,0x200000,0x41002800,0x24000000,0x400000,
-0x41002919,0x7c00100,0x22040e,0x41002a00,0x4000000,0x1600000,0x41002b01,0x2802020,0x962460,0x41002c00,0x4000000,0x200000,0x41002c00,0x7c00120,0x220405,0x41003000,
-0x24000000,0x200000,0x41003700,0x24000000,0x200000,0x41003700,0x24000000,0xe00000,0x41005d00,0x7c00120,0x220405,0x41006600,0x24000020,0x200000,0x41006600,0x24000020,
-0x810000,0x41006600,0x24000020,0x1410000,0x41007208,0x7c00100,0x22040f,0x41007219,0x7c00100,0x220400,0x41007300,0x24000000,0x200000,0x41007e0e,0x2802000,0x962460,
-0x41007e0e,0x4000000,0x200000,0x41007f0e,0x4000000,0x200000,0x41007f0e,0x7c00100,0x230400,0x41008002,0x7c00100,0x230400,0x41008137,0x2802100,0x962460,0x41008137,
-0x4000000,0x200000,0x41008137,0x6800100,0x962540,0x41008137,0x7c00100,0x230400,0x41008301,0x2802000,0x962460,0x41008407,0x4000000,0x200000,0x41008407,0x4000000,
-0x400000,0x41008407,0x4000000,0xb00000,0x41008407,0x7c00100,0x220400,0x41008407,0x7c00100,0x250400,0x4100850b,0x7c00100,0x230400,0x4100860b,0x4000000,0x200000,
-0x4100860b,0x7c00100,0x230400,0x4100870c,0x7c00100,0x220400,0x41008838,0x7c00100,0x220400,0x41008838,0x7c00100,0x250400,0x41008939,0x2802000,0x962460,0x41008939,
-0x2802100,0x962460,0x41008939,0x2806000,0x962460,0x41008939,0x4000000,0x200000,0x41008939,0x4000000,0x400000,0x41008939,0x7c00100,0x230400,0x41008939,0xc000010,
-0x448000,0x41008a00,0x4000400,0x200400,0x41008b3b,0x4000000,0x1800000,0x41008b3b,0x6800000,0x1329800,0x41008b3b,0x7c00100,0x1830000,0x41008b3b,0x7e00100,0x1830000,
-0x41008c3d,0x4000010,0x400000,0x41008c3d,0x7c00100,0x230400,0x41008d0e,0x7c00100,0x22040f,0x41008d19,0x7c00100,0x220400,0x41008d19,0x7c00100,0x22040f,0x41008e00,
-0x24000000,0x200000,0x41008e00,0x24000000,0x400000,0x41008e00,0x24000000,0x1710000,0x41008e00,0x24000006,0x400000,0x41008f3a,0x2802100,0x962460,0x41008f3a,0x2806000,
-0x962460,0x41008f3a,0x4000000,0x200000,0x41008f3a,0x6800100,0x962540,0x41008f3a,0x7c00100,0x230400,0x4100903c,0x7c00100,0x230400,0x4100903c,0x7c00100,0x23040f,
-0x41020701,0x2802000,0x962460,0x41020701,0x2802000,0xc62460,0x410a3700,0x24000000,0x200000,0x410a3700,0x24000000,0xe00000,0x410a4412,0x4000000,0xe00003,0x410a4711,
-0x7c40300,0xe30000,0x410a4f11,0x7c00300,0xe30001,0x410a9100,0x4000000,0x800010,0x410a9100,0x4000000,0x810010,0x410a9100,0x4000000,0x870010,0x410a9100,0x4000000,
-0xb00010,0x410a9100,0x4000000,0xf00010,0x410a9100,0x4000000,0x1001410,0x410a9100,0x4000000,0x1071010,0x410a9100,0x4000000,0x1071410,0x410a9100,0x4000000,0x1410010,
-0x41408ad0,0x4000400,0x200000,0x414a82ca,0x4000000,0xe00000,0x41808300,0x2802000,0x962460,0x41c01489,0x6800000,0x1329800,0x50000419,0x7c00100,0x220400,0x50000419,
-0x7c00100,0x250400,0x5000080e,0x7c00100,0x220400,0x50000908,0x7c00100,0x220400,0x50000908,0x7c00100,0x250400,0x50000b13,0x2802500,0x962460,0x50000f0a,0x7c00100,
-0x230400,0x50001615,0x2802100,0x962460,0x50001615,0x7c00100,0x230400,0x50002b01,0x2802020,0x962460,0x50002c00,0x4000000,0x200000,0x50002c19,0x7c00100,0x220400,
-0x50002d19,0x7c00100,0x220400,0x50003000,0x24000000,0x200000,0x50003000,0x24000020,0x200000,0x50003700,0x24000000,0x200000,0x50005d00,0x7c00120,0x220405,0x50005d00,
-0x7c00120,0x250405,0x50006108,0x7c00100,0x220400,0x50006108,0x7c00100,0x250400,0x50006600,0x24000020,0x200000,0x50007300,0x24000000,0x200000,0x50008301,0x2802400,
-0x962460,0x50008a00,0x7c00500,0x230400,0x50009257,0x2802400,0x962460,0x50009257,0x4000000,0x200000,0x50009257,0x4000010,0x1071400,0x50009257,0x6800000,0x1329800,
-0x50009257,0x7c00100,0x230400,0x50009257,0x7c00500,0x230400,0x50009257,0x7c00900,0x230400,0x50009257,0xc000010,0xb48000,0x5000933e,0x2802100,0x962460,0x5000933e,
-0x2802400,0x962460,0x5000933e,0x4000000,0x200000,0x5000933e,0x4000000,0x400000,0x5000933e,0x4000010,0x400000,0x5000933e,0x6800000,0x1329800,0x5000933e,0x6800100,
-0x962540,0x5000933e,0x6800100,0x962541,0x5000933e,0x6804400,0x962540,0x5000933e,0x7c00100,0x230400,0x5000933e,0x7c00100,0x230401,0x5000933e,0xc000010,0x448000,
-0x50009419,0x7c00100,0x220400,0x50009419,0x7c00100,0x250400,0x50009500,0x4000400,0x200400,0x5000965a,0x4000000,0x500000,0x5000965a,0x7c00100,0x230400,0x5000965a,
-0xc000010,0xb48000,0x5000975b,0x4000000,0x200000,0x5000975b,0x4000010,0x400000,0x5000975b,0x7c00100,0x230400,0x50009865,0x7c00100,0x230400,0x50009965,0x4000010,
-0x400000,0x50009965,0x7c00100,0x230400,0x50409aca,0x4000000,0x200000,0x5100080e,0x7c00100,0x220400,0x5100080e,0x7c00100,0x250400,0x51000c02,0x2802100,0x962460,
-0x51000c02,0x4000000,0x1500000,0x51000c02,0x4000020,0x200000,0x51000c02,0x7c00100,0x230400,0x51000f0a,0x7c00100,0x230400,0x51000f0a,0x7c00500,0x230400,0x51001110,
-0x2802100,0x962460,0x5100131f,0x2802100,0x962460,0x51001423,0x7c00100,0x230400,0x51001524,0x2802100,0x962460,0x51001524,0x4000000,0x200000,0x51001524,0x7c00100,
-0x230400,0x5100171a,0x2802100,0x962460,0x5100171a,0x4000000,0x200000,0x5100171a,0x4000000,0x1500000,0x5100171a,0x7c00100,0x230400,0x51001b27,0x4000000,0x200000,
-0x51001b27,0x4000000,0x400000,0x51001b27,0x4000000,0x500000,0x51001b27,0x7c00100,0x230400,0x51001c1c,0x2802100,0x1862460,0x51001c1c,0x2802500,0x1862460,0x51001c1c,
-0x2806400,0x1862460,0x51001c1c,0x4000000,0x1800000,0x51001c1c,0x6800000,0x1329800,0x51001c1c,0x6800100,0x1862400,0x51001c1c,0x6800100,0x1862540,0x51001c1c,0x6800500,
-0x1862400,0x51001c1c,0x7c00100,0x1830000,0x5100251b,0x7c00100,0x230400,0x51002619,0x7c00100,0x220400,0x51002619,0x7c00100,0x250400,0x51002800,0x80020,0x218820,
-0x51002c00,0x4000000,0x200000,0x51002d19,0x7c00100,0x230400,0x51003700,0x24000000,0x200000,0x51003700,0x24000000,0xe00000,0x51005201,0x2802400,0x962460,0x51005c00,
-0x4000000,0x200000,0x51006108,0x7c00100,0x220400,0x51006108,0x7c00100,0x250400,0x51006600,0x24000020,0x200000,0x51006600,0x24000020,0x810000,0x51006600,0x24000020,
-0x1410000,0x51007300,0x24000000,0x200000,0x51007300,0x24000020,0x200000,0x51008002,0x7c00100,0x230400,0x51008301,0x2802000,0x962460,0x51008301,0x2802400,0x962460,
-0x51008a00,0x7c00500,0x230400,0x51008e00,0x24000000,0x200000,0x51008e00,0x24000000,0x400000,0x51008e00,0x24000000,0x810000,0x51008e00,0x24000000,0x1400000,0x51008e00,
-0x24000000,0x1410000,0x51008e00,0x24000000,0x1710000,0x51008e00,0x24000002,0x200000,0x51008e00,0x24000500,0x230400,0x51008e00,0x2c000010,0xb48000,0x51009419,0x7c00100,
-0x220400,0x51009419,0x7c00100,0x22040e,0x51009419,0x7c00100,0x22040f,0x51009419,0x7c00100,0x250400,0x51009500,0x4000400,0x200400,0x51009500,0x7c00500,0x230400,
-0x51009519,0x7c00100,0x220400,0x51009519,0x7c00100,0x22040f,0x51009519,0x7c00100,0x230400,0x51009519,0x7c00100,0x250400,0x51009b71,0x2802100,0x962460,0x51009b71,
-0x6800000,0x1329800,0x51009b71,0x6800100,0x962540,0x51009b71,0x6804400,0x962540,0x51009b71,0x7c00100,0x230400,0x51009c52,0x2802100,0x962460,0x51009c52,0x2802400,
-0x962460,0x51009c52,0x2802d00,0x962460,0x51009c52,0x4000010,0x400000,0x51009c52,0x6800000,0x1329800,0x51009c52,0x6800100,0x962540,0x51009c52,0x7c00100,0x230400,
-0x51009c52,0xc000010,0x448000,0x51009d6d,0x6800000,0x1329800,0x51009d6d,0x7c00100,0x230400,0x51009d6d,0x7c00500,0x230400,0x51009d6d,0x7c00d00,0x230400,0x51009d6d,
-0xc000010,0x448000,0x51009e08,0x2802100,0x962460,0x51009f63,0x4000010,0x400000,0x51009f63,0x6800000,0x1329800,0x51009f63,0x7c00100,0x230400,0x51009f63,0x7c00900,
-0x230400,0x51009f63,0xc000010,0x448000,0x51009f63,0xc000010,0xb48000,0x5100a008,0x2000,0x962460,0x5100a008,0x2802400,0x962460,0x5100a008,0x4000000,0x200000,
-0x5100a008,0x7c00100,0x220400,0x5100a008,0x7c00100,0x230400,0x5100a008,0x7c00100,0x250400,0x5100a008,0x7c00500,0x230400,0x5100a16f,0x2806400,0x962460,0x5100a16f,
-0x6800000,0x1329800,0x5100a16f,0x6800100,0x962540,0x5100a16f,0x7c00100,0x230400,0x5100a16f,0xc000010,0x448000,0x5100a24f,0x2802100,0x962460,0x5100a24f,0x2802400,
-0x962460,0x5100a24f,0x6800000,0x1329800,0x5100a24f,0x7c00100,0x230400,0x5100a24f,0xc000010,0x448000,0x5100a36e,0x2802100,0x962460,0x5100a36e,0x4000000,0x200000,
-0x5100a36e,0x6800100,0x962540,0x5100a36e,0x6804400,0x962540,0x5100a36e,0x7c00100,0x230400,0x5100a442,0x2802100,0x962460,0x5100a442,0x4000000,0x200000,0x5100a442,
-0x6800000,0x1329800,0x5100a442,0x6800100,0x962540,0x5100a442,0x7c00100,0x230400,0x5100a442,0xc000010,0x448000,0x5100a500,0x4000000,0x200000,0x5100a600,0x4000000,
-0x200000,0x5100a601,0x2802000,0x962460,0x5100a76b,0x7c00100,0x230400,0x5100a868,0x7c00100,0x230400,0x5100a96c,0x4000000,0x200000,0x5100a96c,0x7c00100,0x230400,
-0x5100aa00,0x4000000,0xe00000,0x5100ab00,0x4000000,0xe00000,0x51086600,0x24000020,0x810000,0x51086600,0x24000020,0x1410000,0x510a4005,0x7c00100,0xe30400,0x510a4711,
-0x7c40300,0xe30000,0x510a7300,0x24000000,0x200000,0x510aaa00,0x4000000,0xe00000,0x5140a2fe,0x4000400,0x400000,0x514a82ca,0x4000000,0xe00000,0x51802bbc,0x2802000,
-0x962460,0x51c00908,0x2802400,0x962460,0x51c0a008,0x2802400,0x962460,0x52000f0a,0x2802100,0x962460,0x52000f0a,0x6800100,0x962540,0x52000f0a,0x7c00100,0x230400,
-0x52001004,0x4000000,0x1600000,0x52001b00,0x4000000,0x200000,0x52001c1c,0x2802100,0x1862460,0x52001c1c,0x6800100,0x1862400,0x52001c1c,0x6800500,0x1862400,0x52001e12,
-0x7c00100,0x2230500,0x52001e12,0x7c00100,0x2330520,0x52002128,0x4000002,0x400000,0x52002128,0x7c00100,0x230400,0x52002a00,0x4000000,0x1500000,0x52002a00,0x4000000,
-0x1600000,0x52002d00,0x4000000,0x200006,0x52003000,0x24000000,0x200000,0x52006108,0x7c00100,0x220400,0x52006108,0x7c00100,0x250400,0x52008301,0x2802400,0x962460,
-0x52008407,0x2802400,0x962460,0x52008407,0x7c00100,0x220400,0x52008407,0x7c00100,0x250400,0x52008b3b,0x6800000,0x1800000,0x52008b3b,0x7c00100,0x1830000,0x52008e00,
-0x24000000,0x400000,0x52009419,0x7c00100,0x250400,0x5200975b,0x4000000,0x200000,0x5200ac7e,0x2802000,0x962460,0x5200ac7e,0x2802100,0x962460,0x5200ac7e,0x2802400,
-0x962460,0x5200ac7e,0x4000010,0x200000,0x5200ac7e,0x7c00100,0x230400,0x5200ac7e,0xc000010,0x248000,0x5200ad28,0x7c00100,0x230400,0x5200ae6a,0x2802100,0x1862460,
-0x5200ae6a,0x2802400,0x962460,0x5200ae6a,0x2802400,0x1862460,0x5200ae6a,0x2806000,0x1862460,0x5200ae6a,0x4000000,0x1800000,0x5200ae6a,0x6800000,0x1329800,0x5200ae6a,
-0x6800100,0x1862400,0x5200ae6a,0x6800100,0x1862540,0x5200ae6a,0x7c00100,0x1830000,0x5200ae6a,0x7c00900,0x1830000,0x5200ae6a,0xc000010,0x1848000,0x5200b083,0x4000010,
-0x400000,0x5200b083,0x7c00100,0x230400,0x5200b083,0xc000010,0x448000,0x5200b182,0x2802400,0x962460,0x5200b182,0x4000000,0x200000,0x5200b182,0x4000010,0x400000,
-0x5200b182,0x7c00100,0x230400,0x5200b182,0xc000010,0x448000,0x5200b30a,0x2802400,0x962460,0x5200b30a,0x4000000,0x200000,0x5200b30a,0x7c00100,0x230400,0x5200b54e,
-0x2802100,0x962460,0x5200b54e,0x2802400,0x962460,0x5200b54e,0x4000000,0x200000,0x5200b54e,0x4000010,0x400000,0x5200b54e,0x6800000,0x1329800,0x5200b54e,0x6800100,
-0x962540,0x5200b54e,0x6804400,0x962540,0x5200b54e,0x7c00100,0x230400,0x5200b54e,0xc000010,0x448000,0x5200b61c,0x4000000,0x1800000,0x5200b61c,0x6800500,0x1862400,
-0x5200b61c,0x7c00100,0x1830000,0x5200b61c,0x7c00900,0x1830000,0x5200b77f,0x2802100,0x1862460,0x5200b77f,0x2802400,0x1862460,0x5200b77f,0x4000000,0x1800000,0x5200b77f,
-0x4000010,0x1800000,0x5200b77f,0x7c00100,0x1830000,0x5200b77f,0x7c00500,0x1830000,0x5200b77f,0x7c00900,0x1830000,0x5200b77f,0x7e00100,0x1830000,0x5200b873,0x2802100,
-0x962460,0x5200b873,0x2806400,0x962460,0x5200b873,0x6800000,0x1329800,0x5200b873,0x6800100,0x962540,0x5200b873,0x6800400,0x962540,0x5200b873,0x7c00100,0x230400,
-0x5200b873,0xc000010,0x448000,0x5200b912,0x7c00100,0x2230500,0x5200b912,0x7c00100,0x2330520,0x5200ba74,0x4000000,0x200000,0x5200ba74,0x4000010,0x400000,0x5200ba74,
-0x7c00100,0x230400,0x5200bb85,0x4000000,0x200000,0x5200bb85,0x7c00100,0x230400,0x5200bc75,0x4000000,0x400000,0x5200bc75,0x4000010,0x400000,0x5200bc75,0x7c00100,
-0x230400,0x5200bd7d,0x4000000,0x200000,0x5200bd7d,0x7c00100,0x230400,0x5200be7a,0x4000000,0x200000,0x5200be7a,0x7c00100,0x230400,0x5200bf58,0x7c00100,0x230400,
-0x5200c002,0x4000000,0x200000,0x5200c178,0x2802000,0x962460,0x5200c178,0x2802100,0x962460,0x5200c178,0x2802400,0x962460,0x5200c178,0x2806400,0x962460,0x5200c178,
-0x4000000,0x200000,0x5200c178,0x6800100,0x962540,0x5200c178,0x7c00100,0x230400,0x5200c178,0x7c00100,0x230401,0x5200c178,0xc000010,0x448000,0x5200c178,0x80000000,
-0x218960,0x5200c247,0x7c00100,0x230400,0x5200c247,0x7c00100,0x830400,0x5200c247,0x7c00100,0x1430400,0x5200c300,0x4000000,0x200003,0x52022d00,0x4000000,0x100006,
-0x52023700,0x24000000,0x100000,0x52023700,0x24000000,0xe00000,0x52023700,0x24000000,0x2800000,0x52024400,0x4000000,0x100000,0x52027300,0x24000000,0x100000,0x5202c300,
-0x4000000,0x100000,0x5202c300,0x4000000,0x100002,0x5202c300,0x4000000,0x100003,0x5202c300,0x4000000,0x10000d,0x5202c300,0x4000100,0x150400,0x5202c300,0x4000100,
-0x15040d,0x520a1e12,0x7c00100,0x2130480,0x520a3700,0x24000000,0xe00000,0x520a3800,0x24000000,0x100000,0x520a4711,0x7c40300,0xe30000,0x520a4f11,0x7c00300,0xe30001,
-0x520a7300,0x24000000,0x100000,0x520ab412,0x7c00100,0x2130480,0x520ac400,0x4000000,0xe00002,0x520ac400,0x4000000,0xe0000d,0x520ac414,0x4000000,0xe0000d,0x520ac511,
-0x7c40300,0xe30000,0x5240af9c,0x7c00100,0x230400,0x5240afa1,0x4000400,0x200000,0x5240afa3,0x6800400,0x962540,0x5240afa3,0x7c00100,0x230400,0x5240afad,0x7c00100,
-0x230400,0x5240afaf,0x7c00100,0x230400,0x5240b2d2,0x4000000,0x200000,0x5240b2d2,0x4000000,0x1500000,0x5240b2dd,0x4000000,0x200000,0x5240b2eb,0x4000000,0x200000,
-0x524a44ca,0x4000000,0xe00003,0x5250b501,0x7c00900,0x230400,0x5280af9c,0x2802400,0x962460,0x5280af9d,0x2802400,0x962460,0x5280afa3,0x2802400,0x962460,0x5280afa5,
-0x2802400,0x962460,0x5280afa7,0x2802400,0x962460,0x52c0b3f8,0x2802400,0x962460,0x52c0b3fc,0x7c00100,0x230400,0x60000c02,0x2802100,0x962460,0x60000c02,0x7c00100,
-0x230400,0x60000f0a,0x2802100,0x962460,0x60000f0a,0x6800100,0x962540,0x60000f0a,0x7c00100,0x230400,0x6000131f,0x4000000,0x200000,0x6000171a,0x7c00100,0x230400,
-0x6000171a,0x7c00100,0x230560,0x60001b27,0x2802100,0x962460,0x60001b27,0x4000000,0xc00000,0x60001b27,0x7c00100,0x230400,0x60001f0b,0x2802400,0x962460,0x60002919,
-0x7c00100,0x22040e,0x60002a00,0x4000000,0x1600000,0x60003000,0x24000000,0x200000,0x60003000,0x24000000,0xe00000,0x60003700,0x24000000,0x200000,0x60003800,0x24000000,
-0x1710000,0x60005102,0x4000000,0x200000,0x60006108,0x7c00100,0x220400,0x60006108,0x7c00100,0x250400,0x60006600,0x24000020,0x200000,0x60008301,0x2802400,0x962460,
-0x6000903c,0x2806000,0x962460,0x6000903c,0x4000000,0x400000,0x60009519,0x7c00100,0x220400,0x60009519,0x7c00100,0x250400,0x6000a008,0x7c00100,0x220400,0x6000a008,
-0x7c00100,0x250400,0x6000c300,0x4000000,0x2703580,0x6000c654,0x2802000,0x962460,0x6000c654,0x4000010,0x200000,0x6000c654,0x7c00100,0x230400,0x6000c73f,0x2802000,
-0x962460,0x6000c73f,0x2802100,0x962460,0x6000c73f,0x4000000,0x200000,0x6000c73f,0x6800100,0x962540,0x6000c73f,0x6804000,0x962540,0x6000c73f,0x7c00100,0x230400,
-0x6000c80b,0x7c00100,0x230400,0x6000c941,0x2802100,0x962460,0x6000c941,0x2806400,0x962460,0x6000c941,0x4000000,0x200000,0x6000c941,0x4000010,0x200000,0x6000c941,
-0x6800000,0x1329800,0x6000c941,0x6800100,0x962540,0x6000c941,0x7c00100,0x230400,0x6000c941,0xc000010,0x448000,0x6000ca82,0x7c00100,0x230400,0x6000cc00,0x4000000,
-0xe00000,0x6000d000,0x4000000,0x200000,0x6002c300,0x4000000,0x100000,0x6002c300,0x4000000,0x10000d,0x6002c300,0x4000100,0x150400,0x6002c300,0x4000100,0x15040d,
-0x600a3000,0x24000000,0x200000,0x600a3000,0x24000000,0xe00000,0x600a3700,0x24000000,0x200000,0x600a3800,0x24000000,0x200000,0x600a3800,0x24000000,0x2800000,0x600a4305,
-0x7c00100,0xe30400,0x600ac300,0x4000000,0x100000,0x600ac400,0x4000000,0xe0000d,0x600acb14,0x7c00100,0xe30000,0x600acb16,0x7c00100,0xe30c00,0x600acc00,0x4000000,
-0xe00000,0x600acd00,0x4000000,0x200000,0x600acd00,0x4000000,0xe00000,0x600acd00,0x4000000,0x2800000,0x600ace00,0x4000000,0xe00000,0x600ace00,0x4000000,0x2800000,
-0x600acf00,0x4000000,0xe00000,0x600acf00,0x4000000,0x2800000,0x600ad111,0x7c40300,0xe30000,0x604ac4ca,0x4000000,0xe00003,0x61000a03,0x4000000,0x1600000,0x61000c02,
-0x80000000,0x218960,0x6100120f,0x4000000,0x200000,0x61001a18,0x7c00100,0x1830000,0x61001d0c,0x7c00100,0x230400,0x61001d0c,0x7c00100,0x250400,0x61006600,0x24000020,
-0x200000,0x61008407,0x7c00100,0x220400,0x61008407,0x7c00100,0x250400,0x6100870c,0x7c00100,0x220400,0x61008e00,0x24000000,0x200000,0x61008e00,0x24000000,0x400000,
-0x61008e00,0x24000002,0x300000,0x6100903c,0x7c00100,0x230400,0x61009519,0x7c00100,0x220400,0x61009519,0x7c00100,0x250400,0x61009519,0x7c00500,0x22040f,0x61009b71,
-0x2802100,0x962460,0x61009b71,0x2806400,0x962460,0x61009b71,0x7c00100,0x230400,0x6100a008,0x2802100,0x962460,0x6100c300,0x4000000,0x20000f,0x6100cd00,0x4000000,
-0x200000,0x6100d202,0x2802400,0x962460,0x6100d202,0x2802500,0x962460,0x6100d202,0x7c00100,0x230400,0x6100d302,0x4000020,0x200000,0x6100d302,0x7c00120,0x230405,
-0x6100d476,0x2802100,0x962460,0x6100d476,0x2802100,0x962461,0x6100d476,0x2806400,0x962460,0x6100d476,0x4000000,0x400000,0x6100d476,0x6800000,0x1329800,0x6100d476,
-0x6800100,0x962540,0x6100d476,0x7c00100,0x230400,0x6100d476,0xc000010,0x448000,0x6100d573,0x2802100,0x962460,0x6100d573,0x2806400,0x962460,0x6100d573,0x6800100,
-0x962540,0x6100d573,0x7c00100,0x230400,0x6100d573,0x7c00900,0x230400,0x6100d573,0xc000010,0x448000,0x6100d68d,0x7c00100,0x230400,0x6100d756,0x7c00100,0x230400,
-0x6100d85c,0x2802500,0x962460,0x6100d85c,0x6800100,0x962540,0x6100d85c,0x7c00100,0x230400,0x6100d85c,0x7c00500,0x230400,0x6100d997,0x2802100,0x962460,0x6100d997,
-0x4000000,0x200000,0x6100d997,0x4000000,0x400000,0x6100d997,0x6800000,0x1329800,0x6100d997,0x6800100,0x962540,0x6100d997,0x6804400,0x962540,0x6100d997,0x7c00100,
-0x230400,0x6100d997,0x7c00100,0x230560,0x6100d997,0xc000010,0x448000,0x6100da98,0x6800000,0x1329800,0x6100da98,0x7c00100,0x230400,0x6100db71,0x4000000,0x200000,
-0x6100dc99,0x2802100,0x962460,0x6100dc99,0x2802400,0x962460,0x6100dc99,0x6800000,0x1329800,0x6100dc99,0x6800100,0x962540,0x6100dc99,0x6804400,0x962540,0x6100dc99,
-0x7c00100,0x230400,0x610a4711,0x7c40300,0xe30000,0x610a4f11,0x7c00300,0xe30001,0x610ace00,0x4000000,0xe00000,0x6140afa1,0x7c00100,0x230400,0x6140afa3,0x7c00100,
-0x230400,0x6180af9e,0x2802400,0x962460,0x62002a00,0x4000000,0x1600000,0x63002800,0x80000,0x918820,0x63c00c15,0x80000,0x918820,0x7000080e,0x7c00100,0x250400,
-0x70000a03,0x4000000,0x200000,0x70000c00,0x80000000,0x218960,0x70000f0a,0x7c00100,0x230400,0x70001004,0x7c00100,0x230400,0x70001524,0x2802100,0x962460,0x70001524,
-0x7c00100,0x230400,0x70001615,0x2802100,0x962460,0x7000171a,0x2802100,0x962460,0x70001821,0x6800000,0x1329800,0x70002320,0x7c00100,0x230400,0x70002a00,0x4000000,
-0x1500000,0x70002a00,0x4000000,0x1600000,0x70003000,0x24000000,0x200000,0x70003800,0x24000000,0xe00000,0x70005201,0x2802400,0x962460,0x7000581e,0x7c00100,0x230400,
-0x70006108,0x7c00100,0x220400,0x70006108,0x7c00100,0x250400,0x70006f30,0x7c00100,0x230400,0x70007300,0x24000000,0x200000,0x70007f0e,0x4000000,0x200000,0x70008301,
-0x2802100,0x962460,0x70008301,0x2802400,0x962460,0x70008e00,0x24000000,0x200000,0x70008e00,0x24000000,0x400000,0x70008e00,0x24000002,0x400000,0x70008e00,0x24000008,
-0x1410000,0x70008e00,0x24000010,0x400000,0x70008e00,0x2c000010,0x448000,0x70009519,0x7c00100,0x220400,0x70009519,0x7c00100,0x230400,0x70009519,0x7c00100,0x250400,
-0x70009865,0x7c00100,0x230400,0x70009965,0x4000010,0x400000,0x70009965,0x7c00100,0x230400,0x7000a008,0x7c00100,0x220400,0x7000a008,0x7c00100,0x250400,0x7000a008,
-0x7c00500,0x22040f,0x7000a50e,0x4000000,0x200000,0x7000b61c,0x2802500,0x1862460,0x7000b61c,0x6800500,0x1862400,0x7000b61c,0x7c00100,0x1830000,0x7000c300,0x4000000,
-0x100000,0x7000c941,0x2806000,0x962460,0x7000cc00,0x4000000,0xe00000,0x7000cd00,0x4000000,0x200000,0x7000cd00,0x4000000,0xe00000,0x7000cd00,0x4000000,0x2800000,
-0x7000cf00,0x4000000,0xe00000,0x7000d202,0x2802100,0x962460,0x7000d202,0x7c00100,0x230400,0x7000d997,0x7c00100,0x230400,0x7000d997,0xc000010,0x248000,0x7000dd86,
-0x2802400,0x962460,0x7000dd86,0x7c00100,0x230400,0x7000dd86,0xc000010,0x448000,0x7000de9f,0x4000000,0x200000,0x7000de9f,0x7c00100,0x230400,0x7000e001,0x2400,
-0x962460,0x7000e001,0x2802400,0x962460,0x7000e187,0x2802000,0x962460,0x7000e187,0x2802100,0x962460,0x7000e187,0x4000000,0x200000,0x7000e187,0x7c00100,0x230400,
-0x7000e187,0xc000010,0x448000,0x7000e288,0x7c00100,0x230400,0x7000e300,0x4000000,0x200000,0x7000e489,0x2802100,0x962460,0x7000e489,0x2802400,0x962460,0x7000e489,
-0x6800100,0x962540,0x7000e489,0x6800100,0x962541,0x7000e489,0x6804400,0x962540,0x7000e489,0x7c00100,0x230400,0x7000e489,0x7c00900,0x230400,0x7000e59d,0x2802100,
-0x962460,0x7000e59d,0x2802400,0x962460,0x7000e59d,0x4000000,0x200000,0x7000e59d,0x4000010,0x200000,0x7000e59d,0x6800100,0x962540,0x7000e59d,0x6804400,0x962540,
-0x7000e59d,0x7c00100,0x230400,0x7000e59d,0xc000010,0x448000,0x7000e691,0x2802100,0x962460,0x7000e691,0x2802400,0x962460,0x7000e691,0x2806400,0x962460,0x7000e691,
-0x6800000,0x1329800,0x7000e691,0x6800100,0x962540,0x7000e691,0x7c00100,0x230400,0x7000e700,0x4000400,0x200400,0x7000e70e,0x7c00100,0x220400,0x7000e719,0x7c00100,
-0x220400,0x7000e719,0x7c00500,0x22040f,0x7000e853,0x7c00100,0x230400,0x7000e9a0,0x2802400,0x962460,0x7000e9a0,0x4000000,0x200000,0x7000e9a0,0x4000000,0x500000,
-0x7000e9a0,0x7c00100,0x230400,0x7000ea79,0x2802400,0x962460,0x7000ea79,0x4000000,0x200000,0x7000ea79,0x4000000,0xf00000,0x7000ea79,0x4000010,0x400000,0x7000ea79,
-0x7c00100,0x230400,0x7000eb8c,0x2802400,0x962460,0x7000eb8c,0x4000000,0x200000,0x7000eb8c,0x7c00100,0x230400,0x7000eca3,0x2802100,0x962460,0x7000eca3,0x2806400,
-0x962460,0x7000eca3,0x4000000,0x200000,0x7000eca3,0x6800000,0x1329800,0x7000eca3,0x6800100,0x962540,0x7000eca3,0x7c00100,0x230400,0x7000eca3,0xc000010,0x448000,
-0x7000ed95,0x6800000,0x1329800,0x7000ed95,0x7c00100,0x230400,0x7000ed95,0xc000010,0x448000,0x7000ee1c,0x2802500,0x1862460,0x7000ee1c,0x6800000,0x1329800,0x7000ee1c,
-0x7c00100,0x1830000,0x7000ee1c,0x7c00900,0x1830000,0x7000ef8f,0x4000000,0x200000,0x7000ef8f,0x7c00100,0x230400,0x7000f08e,0x4000000,0x200000,0x7000f08e,0x7c00100,
-0x230400,0x7000f159,0x2802100,0x962460,0x7000f159,0x7c00100,0x230400,0x7000f200,0x4000000,0x200000,0x7000f200,0x4000000,0x1200000,0x7000f200,0x4000000,0x1710000,
-0x7000f34b,0x2802400,0x962460,0x7000f34b,0x4000000,0x200000,0x7000f34b,0x4000010,0x400000,0x7000f34b,0x6800000,0x1329800,0x7000f34b,0x7c00100,0x230400,0x7000f34b,
-0x7c00900,0x230400,0x7000f34b,0xc000010,0x448000,0x7000f490,0x4000000,0x200000,0x7000f490,0x7c00100,0x230400,0x7000f5a5,0x7c00100,0x230400,0x7000f67b,0x4000000,
-0x200000,0x7000f67b,0x4000010,0x200000,0x7000f67b,0x7c00100,0x230400,0x7000f8a6,0x2802100,0x962460,0x7000f8a6,0x2802400,0x962460,0x7000f8a6,0x2806400,0x962460,
-0x7000f8a6,0x4000000,0x500000,0x7000f8a6,0x4000010,0xb00000,0x7000f8a6,0x4000800,0x200000,0x7000f8a6,0x6800100,0x962540,0x7000f8a6,0x6800100,0x962541,0x7000f8a6,
-0x7c00100,0x230400,0x7000f8a6,0xc000010,0x448000,0x7000f921,0x4000000,0x200000,0x7000fa00,0x4000000,0x200000,0x7000fb9e,0x2802100,0x962460,0x7000fb9e,0x2802400,
-0x962460,0x7000fb9e,0x2806400,0x962460,0x7000fb9e,0x4000000,0x200000,0x7000fb9e,0x6800000,0x1329800,0x7000fb9e,0x6800100,0x962540,0x7000fb9e,0x6800100,0x962541,
-0x7000fb9e,0x7c00100,0x230400,0x7000fc92,0x4000000,0x200000,0x7000fc92,0x6800000,0x1329800,0x7000fc92,0x7c00100,0x220400,0x7000fc92,0x7c00100,0x230400,0x7000fc92,
-0x7c00100,0x250400,0x700acd00,0x4000000,0xe00000,0x700acd00,0x4000000,0x2800000,0x700ace00,0x4000000,0xe00000,0x700acf00,0x4000000,0xe00000,0x700acf00,0x4000000,
-0x2800000,0x7050df11,0x4000000,0x200000,0x7050f719,0x80000,0x918820,0x7080afa1,0x2802400,0x962460,0x7090df11,0x2802400,0x962460,0x70d0e417,0x2802100,0x962460,
-0x70d0e417,0x2802400,0x962460,0x70d0e417,0x6800100,0x962540,0x70d0ea15,0x4000010,0x400000,0x8000120f,0x7c00100,0x230400,0x80001524,0x7c00100,0x230400,0x8000171a,
-0x7c00100,0x230400,0x80002006,0x7c00100,0x220400,0x80002006,0x7c00100,0x250400,0x80002a00,0x4000000,0x1500000,0x80002d00,0x4000000,0x200000,0x80005208,0x2802400,
-0x962460,0x80005c00,0x4000000,0x200000,0x80007300,0x24000000,0x200000,0x80009519,0x7c00100,0x220400,0x80009519,0x7c00100,0x230400,0x80009519,0x7c00100,0x250400,
-0x80009865,0x7c00100,0x230400,0x8000a008,0x2802100,0x962460,0x8000b30a,0x4000000,0x500000,0x8000b30a,0x7c00100,0x230400,0x8000cd00,0x4000000,0xe00000,0x8000d202,
-0x2802500,0x962460,0x8000d202,0x7c00100,0x230400,0x8000d68d,0x4000000,0x200000,0x8000d997,0x2802000,0x962460,0x8000d997,0x2802400,0x962460,0x8000d997,0x4000000,
-0x400000,0x8000d997,0x4000000,0x500000,0x8000d997,0x7c00100,0x230400,0x8000d997,0xc000010,0x448000,0x8000e489,0x2802100,0x962460,0x8000e489,0x7c00100,0x230400,
-0x8000e719,0x7c00100,0x220400,0x8000f8a6,0x2802100,0x962460,0x8000f8a6,0x7c00100,0x230400,0x8000f8a6,0xc000010,0x448000,0x8000fda1,0x2802100,0x1862460,0x8000fda1,
-0x2806400,0x1862460,0x8000fda1,0x4000000,0x1800000,0x8000fda1,0x6800000,0x1329800,0x8000fda1,0x6800100,0x1862400,0x8000fda1,0x6800100,0x1862540,0x8000fda1,0x7c00100,
-0x1830000,0x8000fda1,0xc000010,0x448000,0x8000fe9c,0x7c00100,0x230400,0x8000fe9c,0x7c00100,0x830400,0x8000fe9c,0x7c00100,0x1430400,0x8000ff06,0x7c00100,0x220400,
-0x80010165,0x7c00100,0x230400,0x800102a2,0x4000000,0x200000,0x800102a2,0x7c00100,0x230400,0x800103a4,0x7c00100,0x230400,0x800103a4,0xc000010,0x448000,0x8001044c,
-0x4000000,0x200000,0x8001044c,0x7c00100,0x220400,0x8001044c,0x7c00100,0x250400,0x80010670,0x2802000,0x962460,0x80010670,0x4000000,0x200000,0x80010670,0x4000010,
-0x400000,0x80010670,0xc000010,0x448000,0x800a4711,0x7c40300,0xe30000,0x800acd00,0x4000000,0xe00000,0x800acd00,0x4000000,0x2902460,0x800ace00,0x4000000,0xe00000,
-0x800acf00,0x4000000,0xe00000,0x800b0011,0x7c40300,0xe30000,0x800b0500,0x4000000,0xe00000,0x800b0500,0x4000000,0x2800000,0x90001615,0x7c00100,0x230400,0x9000171a,
-0x4000000,0x200000,0x9000171a,0x7c00100,0x230400,0x90003000,0x24000000,0x200000,0x90007f0e,0x4000000,0x200000,0x90008301,0x2802400,0x962460,0x90008e00,0x24000000,
-0x400000,0x90009519,0x7c00100,0x250400,0x9000a16f,0x2802100,0x962460,0x9000d200,0x80000000,0x218960,0x9000d202,0x2802000,0x962460,0x9000d202,0x2802100,0x962460,
-0x9000d202,0x7c00100,0x230400,0x9000e59d,0x2802100,0x962460,0x90010500,0x4000000,0xe00000,0x900107a7,0x2802100,0x962460,0x900107a7,0x2802400,0x962460,0x900107a7,
-0x2802c00,0x962460,0x900107a7,0x4000000,0x1400000,0x900107a7,0x6800000,0x1329800,0x900107a7,0x7c00100,0x220400,0x900107a7,0x7c00100,0x250400,0x900108a8,0x2802100,
-0x962460,0x900108a8,0x2806400,0x962460,0x900108a8,0x4000000,0x200000,0x900108a8,0x4000000,0x400000,0x900108a8,0x4000010,0x400000,0x900108a8,0x6800000,0x1329800,
-0x900108a8,0x6800100,0x962540,0x900108a8,0x7c00100,0x230400,0x900108a8,0xc000010,0x448000,0x90010908,0x7c00100,0x220400,0x90010a38,0x2802100,0x962460,0x90010ca9,
-0x2802100,0x962460,0x90010ca9,0x4000000,0x500000,0x90010ca9,0x4000010,0xb00000,0x90010ca9,0x6800100,0x962540,0x90010ca9,0x7c00100,0x230400,0x90010d1b,0x4000000,
-0x500000,0x90010eaa,0x2802100,0x962460,0x90010eaa,0x2802400,0x962460,0x90010eaa,0x2806400,0x962460,0x90010eaa,0x4000000,0x200000,0x90010eaa,0x4000000,0x400000,
-0x90010eaa,0x4000010,0x400000,0x90010eaa,0x6800000,0x1329800,0x90010eaa,0x6800100,0x962540,0x90010eaa,0x7c00100,0x230400,0x90010eaa,0xc000010,0x448000,0x90010fab,
-0x7c00100,0x220400,0x90010fab,0x7c00100,0x250400,0x9002c300,0x4000000,0x100000,0x900ac400,0x4000000,0xe0000d,0x900acd00,0x4000000,0xe00000,0x900acd00,0x4000000,
-0x2800000,0x900acf00,0x4000000,0xe00000,0x900b0500,0x4000000,0xe00000,0x900b0500,0x4000000,0x2800000,0x900b0b9a,0x7c00900,0x1230400,0x900b109a,0x7c00300,0xe30000,
-0x900b119a,0x7c00300,0xe30000,0x90408e06,0x24000000,0x400000,0xa0001004,0x4000000,0x200000,0xa0001004,0x7c00100,0x230400,0xa000120f,0x2802100,0x962460,0xa000120f,
-0x2802400,0x962460,0xa000171a,0x2802100,0x962460,0xa000171a,0x2806400,0x962460,0xa0002a00,0x4000000,0x1600000,0xa0003000,0x24000000,0x200000,0xa000581e,0x7c00100,
-0x230400,0xa0007300,0x24000000,0x200000,0xa0008301,0x2802400,0x962460,0xa0008e00,0x24000000,0x400000,0xa000cf00,0x4000000,0xe00000,0xa0010500,0x4000000,0x200000,
-0xa00114af,0x2802100,0x962460,0xa00114af,0x2802400,0x962460,0xa00114af,0x2806400,0x962460,0xa00114af,0x6800000,0x1329800,0xa00114af,0x7c00100,0x230400,0xa00114af,
-0x7c00100,0x230560,0xa00116b0,0x2802100,0x962460,0xa00116b0,0x2802800,0x962460,0xa00116b0,0x2806400,0x962460,0xa00116b0,0x4000000,0x400000,0xa00116b0,0x4000000,
-0x500000,0xa00116b0,0x4000010,0x400000,0xa00116b0,0x6800100,0x962540,0xa00116b0,0x7c00100,0x230400,0xa00116b0,0x7c00100,0x230560,0xa00116b0,0xc000010,0x448000,
-0xa0011722,0x7c00100,0x230400,0xa00118b1,0x2802000,0x962460,0xa00118b1,0x2802100,0x962460,0xa00118b1,0x2806400,0x962460,0xa00118b1,0x4000000,0x200000,0xa00118b1,
-0x4000000,0x400000,0xa00118b1,0x4000000,0x500000,0xa00118b1,0x6800100,0x962540,0xa00118b1,0x7c00100,0x230400,0xa00118b1,0x7c00100,0x230560,0xa00118b1,0xc000010,
-0x448000,0xa00a4005,0x7c00100,0xe30400,0xa00a4711,0x7c40300,0xe30000,0xa00ac400,0x4000000,0xe00000,0xa00acb14,0x7c00100,0xe30000,0xa00acf00,0x4000000,0xe00000,
-0xa00b0500,0x4000000,0xe00000,0xa00b0500,0x4000000,0x2800000,0xa00b0b96,0x7c00900,0x1230400,0xa00b1211,0x7c40300,0xe30000,0xa00b1314,0x7c00100,0xe30000,0xa00b1596,
-0x7c00300,0xe30000,0xa040afb7,0x6800400,0x962540,0xa08083b8,0x2802400,0x962460,0xb0000a03,0x7c00100,0x220400,0xb0000b13,0x7c00100,0x2633800,0xb0001004,0x2802000,
-0x962460,0xb0001110,0x4000000,0x200000,0xb0001524,0x2802000,0x962460,0xb0001615,0x4000000,0x500000,0xb000251b,0x7c00100,0x230400,0xb0007300,0x24000000,0x200000,
-0xb0008939,0x4000000,0x200000,0xb0008939,0x7c00100,0x230400,0xb0008e00,0x24000000,0x200000,0xb0008e00,0x24000000,0x400000,0xb0008e00,0x24000010,0x400000,0xb0009257,
-0x2802000,0x962460,0xb0009257,0x4000000,0x1600000,0xb0009519,0x7c00100,0x220400,0xb0009519,0x7c00100,0x250400,0xb0009a00,0x4000000,0x200000,0xb000b30a,0x2802100,
-0x962460,0xb000b30a,0x7c00100,0x230400,0xb000c178,0x80000000,0x218960,0xb000c300,0x4000000,0x200000,0xb000d202,0x2802000,0x962460,0xb000d476,0x6800100,0x962540,
-0xb000d476,0x7c00100,0x230400,0xb000e300,0x4000000,0xe00000,0xb000fda1,0x7c00100,0x1830000,0xb0010eaa,0x2802000,0x962460,0xb00116b0,0x7c00100,0x230400,0xb0011900,
-0x4000000,0xe00000,0xb0011ab2,0x2802100,0x962460,0xb0011ab2,0x2802400,0x962460,0xb0011ab2,0x2806400,0x962460,0xb0011ab2,0x4000000,0x200000,0xb0011ab2,0x6800100,
-0x962540,0xb0011ab2,0x7c00100,0x230400,0xb0011b0c,0x7c00100,0x230400,0xb0011cb3,0x2802100,0x962460,0xb0011cb3,0x2806400,0x962460,0xb0011cb3,0x6800000,0x1329800,
-0xb0011cb3,0x6800100,0x962540,0xb0011cb3,0x7c00100,0x230400,0xb0011db6,0x2802500,0x962460,0xb0011db6,0x6800000,0x1329800,0xb0011db6,0x7c00100,0x230400,0xb0011db6,
-0x7c00500,0x230400,0xb0011e00,0x4000000,0x200000,0xb0011e00,0x4000000,0x1500000,0xb0011fb4,0x2802100,0x962460,0xb0011fb4,0x6800100,0x962540,0xb0011fb4,0x7c00100,
-0x230400,0xb0011fb4,0xc000010,0x248000,0xb0012000,0x4000000,0x200000,0xb00121b5,0x4000000,0x200000,0xb00121b5,0x4000010,0x400000,0xb00121b5,0x7c00100,0x220400,
-0xb00121b5,0x7c00100,0x250400,0xb00121b5,0xc000010,0x448000,0xb00122b8,0x4000000,0x200000,0xb00122b8,0x7c00100,0x230400,0xb00123b7,0x2802400,0x962460,0xb00123b7,
-0x4000000,0x200000,0xb00123b7,0x7c00100,0x230400,0xb00123b7,0xc000010,0x248000,0xb00a4005,0x7c00100,0xe30400,0xb00a4711,0x7c40300,0xe30000,0xb00acf00,0x4000000,
-0xe00000,0xb00b0500,0x4000000,0xe00000,0xb00b0500,0x4000000,0x2800000,0xb00b109a,0x7c00300,0xe30000,0xb080e487,0x2802000,0x962460,0xc0001524,0x4000000,0x500000,
-0xc0001a18,0x2806400,0x1862460,0xc0001a18,0x7c00100,0x1830000,0xc0007300,0x24000000,0x200000,0xc0008e00,0x24000010,0x400000,0xc0009519,0x7c00100,0x220400,0xc0009519,
-0x7c00100,0x250400,0xc000c300,0x4000000,0x20000f,0xc000d85c,0x2802100,0x962460,0xc000d85c,0x6800100,0x962540,0xc000d85c,0x7c00100,0x230400,0xc000dc99,0x7c00100,
-0x230400,0xc000e719,0x7c00100,0x220400,0xc00107a7,0x7c00100,0x230400,0xc0010eaa,0x7c00100,0x230400,0xc00116b0,0x7c00100,0x230560,0xc0011900,0x4000000,0x200000,
-0xc0012447,0,0x818820,0xc0012447,0,0xc18820,0xc0012447,0,0x1418820,0xc00125b9,0x7c00100,0x230400,0xc00126bb,0x2802100,0x962460,0xc00126bb,
-0x2806400,0x962460,0xc00126bb,0x4000000,0x500000,0xc00126bb,0x6800100,0x962540,0xc00126bb,0x7c00100,0x230400,0xc00127ba,0x2802400,0x962460,0xc00127ba,0x4000000,
-0x200000,0xc00127ba,0x6800000,0x1329800,0xc00127ba,0x7c00100,0x230400,0xc00127ba,0x7c00900,0x230400,0xc0012800,0x4000000,0x200000,0xc0012b23,0x4000000,0x200000,
-0xc0012b23,0x4000000,0x400000,0xc0012b23,0x4000000,0x1500000,0xc0012cbc,0x2802400,0x962460,0xc0012cbc,0x4000000,0x1600000,0xc0012cbc,0x6800000,0x1329800,0xc0012cbc,
-0x7c00100,0x230400,0xc00acf00,0x4000000,0xe00000,0xc00ae300,0x4000000,0xe00000,0xc00b0500,0x4000000,0xe00000,0xc00b0500,0x4000000,0x2800000,0xc00b0b11,0x4000000,
-0x1200000,0xc00b0b11,0x7c00900,0x1230400,0xc00b109a,0x7c00300,0xe30000,0xc00b2914,0x7c00100,0x2530000,0xc00b2916,0x7c00100,0x2530c00,0xc00b2a00,0x4000000,0xe00000,
-0xc040af5e,0x7c00100,0x230400,0xc0c12b89,0x4000000,0x200000,0xc14a44ca,0x4000000,0xe0000d,0xd000131f,0x2802c00,0x962460,0xd000171a,0x7c00100,0x230400,0xd0001821,
-0x2802100,0x962460,0xd0007300,0x24000000,0x200000,0xd0008e00,0x24000000,0x200000,0xd0008f3a,0x2806000,0x962460,0xd0009519,0x7c00100,0x220400,0xd0009519,0x7c00100,
-0x250400,0xd000a500,0x4000000,0x200000,0xd000c300,0x4000000,0xe00000,0xd000d202,0x7c00100,0x230400,0xd000d476,0x7c00100,0x230400,0xd000d997,0x2802100,0x962460,
-0xd000d997,0x6800100,0x962540,0xd000e001,0x2802100,0x962460,0xd000e700,0x4000400,0x200000,0xd000e719,0x7c00100,0x220400,0xd000e719,0x7c00500,0x23040f,0xd000fa00,
-0x4000000,0xe00000,0xd0010eaa,0x4000010,0x400000,0xd0010eaa,0x7c00100,0x230400,0xd0012dbd,0x4000000,0x200000,0xd0012dbd,0x7c00100,0x230400,0xd0012fbe,0x2802100,
-0x962460,0xd0012fbe,0x2802400,0x962460,0xd0012fbe,0x2806400,0x962460,0xd0012fbe,0x4000000,0x400000,0xd0012fbe,0x6800000,0x1329800,0xd0012fbe,0x6800100,0x962540,
-0xd0012fbe,0x6800100,0x962541,0xd0012fbe,0x6804400,0x962540,0xd0012fbe,0x7c00100,0x230400,0xd0012fbe,0x7c00100,0x230560,0xd0012fbe,0xc000010,0x448000,0xd0013183,
-0x7c00100,0x230400,0xd0013200,0x4000000,0x200000,0xd0013200,0x6800000,0x1329805,0xd00134c0,0x2802100,0x962460,0xd00134c0,0x4000002,0x400000,0xd00134c0,0x7c00100,
-0x230400,0xd00a4305,0x7c00100,0xe30400,0xd00a4611,0x7c40300,0xe30000,0xd00a4711,0x7c40300,0xe30000,0xd00a5e11,0x7c40300,0xe30000,0xd00acf00,0x4000000,0xe00000,
-0xd00b0500,0x4000000,0xe00000,0xd00b0500,0x4000000,0x2800000,0xd00b0b11,0x6800500,0x962540,0xd00b0bbf,0x2802200,0xc62460,0xd00b119a,0x7c00300,0xe30000,0xd00b2a00,
-0x4000000,0xe00000,0xd00b2e11,0x7c40300,0xe30000,0xd00b30bf,0x7c00300,0x230000,0xd00b339a,0x7c00300,0xe30000,0xe0000c02,0xc000010,0xb48000,0xe0001524,0x2802400,
-0x962460,0xe0001524,0x7c00100,0x230400,0xe0001615,0x7c00100,0x230400,0xe000251b,0x12882000,0x962460,0xe0002a00,0x4000000,0x1500000,0xe0005102,0x4000000,0x200000,
-0xe0005c00,0x4000000,0x200000,0xe000622a,0x6804400,0x962540,0xe000622a,0x7c00100,0x230400,0xe0008838,0x7c00100,0x220400,0xe0008838,0x7c00100,0x250400,0xe0008e00,
-0x24000000,0x810000,0xe0008e00,0x24000000,0x1410000,0xe0008e00,0x24000002,0x400000,0xe0008e00,0x2c000010,0xb48000,0xe000933e,0x7c00100,0x230400,0xe000933e,0xc000010,
-0x448000,0xe0009519,0x7c00100,0x220400,0xe0009519,0x7c00100,0x23040f,0xe0009519,0x7c00100,0x250400,0xe000c178,0x2802100,0x962460,0xe000c941,0x2802100,0x962460,
-0xe000c941,0x2806400,0x962460,0xe000c941,0x7c00100,0x230400,0xe000d202,0x2802400,0x962460,0xe000d202,0x7c00100,0x230400,0xe000d202,0x7c00500,0x230400,0xe000dc99,
-0x4000000,0x200000,0xe000e001,0x2802100,0x962460,0xe000e001,0x2802400,0x962460,0xe000fda1,0x7c00100,0x1830000,0xe0013502,0x2802400,0x962460,0xe0013502,0x4000000,
-0x200000,0xe0013502,0x7c00100,0x230400,0xe0013502,0x80000000,0x218960,0xe00136c1,0x4000000,0x200000,0xe00136c1,0x7c00100,0x230400,0xe001370b,0x7c00100,0x230400,
-0xe0013919,0x7c00500,0x220400,0xe0013919,0x7c00500,0x22040f,0xe0013919,0x7c00d00,0x23040f,0xe0013a19,0x7c00100,0x220400,0xe0013a19,0x7c00100,0x230400,0xe0013bc2,
-0x2802400,0x962460,0xe0013bc2,0x7c00100,0x230400,0xe0013bc2,0xc000010,0x248000,0xe0013cc3,0x6800000,0x1329800,0xe0013cc3,0x7c00100,0x230400,0xe0013dc4,0x2802400,
-0x962460,0xe0013dc4,0x7c00100,0x230400,0xe0013e28,0x7c00100,0x230400,0xe0013fc5,0x7c00100,0x220400,0xe0013fc5,0x7c00100,0x250400,0xe0014000,0x4000000,0x200000,
-0xe0014001,0x2802400,0x962460,0xe00a4711,0x7c40300,0xe30000,0xe00a5e11,0x7c40300,0xe30000,0xe00ac511,0x7c40300,0xe30000,0xe00acf00,0x4000000,0xe00000,0xe00ae300,
-0x4000000,0xe00000,0xe00b0500,0x4000000,0xe00000,0xe00b1314,0x7c00100,0xe30000,0xe00b1316,0x7c00100,0xe30c00,0xe00b2a00,0x4000000,0xe00000,0xe00b2a00,0x4000000,
-0x2800000,0xe00b3816,0x7c00500,0x230c00,0xe0808328,0x2802400,0x962460};
+0,0xc167,0,0,0xc367,0,0xe00000,0xc467,0,0xe00000,0xc667,0,0,0xc767,0,0,
+0xc867,0,0,0xc967,0,0,0xca67,0,0,0xcc67,0,0xe00000,0xcf67,0,0xe00000,0xd067,
+0,0xe00000,0xd367,0,0,0xd467,0,0,0xd567,0,0,0xd667,0,0,0xd867,0,
+0,0xda67,0,0,0xdb67,0,0,0xdc67,0,0,0xdd67,0,0,0xde67,0,0,
+0xdf67,0,0,0xe067,0,0,0xe167,0,0,0xe267,0,0,0xe367,0,0xe00000,0xe467,
+0,0,0xe567,0,0,0xe667,0,0,0xe767,0,0,0xe867,0,0,0xe967,0,
+0,0xea67,0,0,0xeb67,0,0,0xec67,0,0,0xed67,0,0,0xee67,0,0,
+0xef67,0,0,0xf167,0,0,0xf367,0,0,0xf567,0,0,0xf667,0,0,0xf767,
+0,0,0xf867,0,0,0xf967,0,0,0xfa67,0,0xe00000,0xfb67,0,0,0xfc67,0,
+0,0xfd67,0,0,0xfe67,0,0,0x10167,0,0,0x10267,0,0,0x10367,0,0,
+0x10467,0,0,0x10667,0,0,0x10767,0,0,0x10867,0,0,0x10967,0,0,0x10a67,
+0,0,0x10b67,0,0,0x10c67,0,0,0x10d67,0,0,0x10e67,0,0,0x10f67,0,
+0,0x11067,0,0,0x11367,0,0,0x11467,0,0,0x11567,0,0,0x11667,0,0,
+0x11767,0,0,0x11867,0,0,0x11967,0,0xe00000,0x11a67,0,0,0x11b67,0,0,0x11c67,
+0,0,0x11d67,0,0,0x11e67,0,0,0x11f67,0,0,0x12067,0,0,0x12167,0,
+0,0x12267,0,0,0x12367,0,0,0x12467,0,0,0x12567,0,0,0x12667,0,0,
+0x12767,0,0,0x12867,0,0,0x12967,0,0,0x12a67,0,0xe00000,0x12b67,0,0,0x12c67,
+0,0,0x12d67,0,0,0x12f67,0,0,0x13067,0,0,0x13167,0,0,0x13267,0,
+0,0x13367,0,0,0x13467,0,0,0x13567,0,0,0x13667,0,0,0x13767,0,0,
+0x13867,0,0,0x13967,0,0,0x13a67,0,0,0x13b67,0,0,0x13c67,0,0,0x13d67,
+0,0,0x13f67,0,0,0x14067,0,0,0x14167,0,0,0x14367,0,0,0x14467,0,
+0,0x14567,0,0,0x14667,0,0,0x14767,0,0,0xa0067,0,0xe00000,0xa4f67,0,0xe00000,
+0xa5f67,0,0xe00000,0xac567,0,0xe00000,0xad167,0,0xe00000,0xb0067,0,0xe00000,0xb1267,0,0xe00000,0xb2e67,
+0,0xe00000,0x11000100,0,0x900020,0x11000100,0x40000001,0x440020,0x11000100,0x40000001,0x643020,0x11000100,0x40000001,0xa5a040,0x11000100,0x40000001,
+0x116a8a0,0x11000200,0,0x900020,0x11000200,0x4000001,0xc4000b,0x11000200,0x7c00100,0x220402,0x11000200,0x24000000,0x200000,0x11000200,0x24000008,0x1710000,
+0x11000200,0x40000001,0x1d3b020,0x11000219,0x7c00100,0x220401,0x11000219,0x7c00100,0x250401,0x11000319,0x7c00100,0x220401,0x11000319,0x7c00100,0x220402,0x11000319,
+0x7c00100,0x250400,0x11000319,0x7c00100,0x250401,0x11000419,0x7c00100,0x220400,0x11000419,0x7c00100,0x220401,0x11000419,0x7c00100,0x220402,0x11000419,0x7c00100,
+0x230400,0x11000419,0x7c00100,0x250400,0x11000419,0x7c00100,0x250401,0x11000419,0x7c00100,0x250402,0x11000519,0x7c00100,0x220400,0x11000519,0x7c00100,0x230400,
+0x11000600,0x4000400,0x200002,0x11000600,0x4000400,0x200400,0x11000600,0x7c00500,0x220400,0x11000600,0x7c00500,0x230400,0x11000600,0x7c00500,0x530400,0x11000600,
+0x7c00d00,0x230400,0x11000619,0x7c00500,0x22040f,0x11000800,0x4000010,0x1001401,0x11000800,0x4000400,0x200001,0x11000800,0x6800010,0x201001,0x11000800,0x7c00500,
+0x230401,0x11000807,0x7c00100,0x220400,0x11000807,0x7c00100,0x250400,0x1100080e,0x4000400,0x200000,0x1100080e,0x4000400,0x200002,0x1100080e,0x7000500,0x220402,
+0x1100080e,0x7c00100,0x220400,0x1100080e,0x7c00100,0x220401,0x1100080e,0x7c00100,0x220402,0x1100080e,0x7c00100,0x250400,0x1100080e,0x7c00100,0x250401,0x1100080e,
+0x7c00120,0x220402,0x1100080e,0x7c00120,0x250402,0x11000908,0x4000000,0x200000,0x11000908,0x7c00100,0x220400,0x11000908,0x7c00100,0x220401,0x11000908,0x7c00100,
+0x250400,0x11000908,0x7c00100,0x250401,0x11000a03,0x4000000,0x200400,0x11000a03,0x4000000,0x201000,0x11000a03,0x4000000,0x270000,0x11000a03,0x7c00100,0x220400,
+0x11000a03,0x7c00100,0x220402,0x11000a03,0x7c00100,0x250400,0x11000a03,0x7c00500,0x230400,0x11000a03,0xc000010,0x1049400,0x11000b13,0x2802500,0x962460,0x11000b13,
+0x4000000,0x200000,0x11000b13,0x4000000,0x201000,0x11000b13,0x4000000,0x230400,0x11000b13,0x4000002,0x400000,0x11000b13,0x4000010,0x200000,0x11000b13,0x7c00100,
+0x2633800,0x11000c00,0x80000000,0x218960,0x11000c02,0x2802100,0x962460,0x11000c02,0x2802400,0x962460,0x11000c02,0x4000000,0x200000,0x11000c02,0x4000000,0x1329400,
+0x11000c02,0x4000000,0x1329800,0x11000c02,0x4000000,0x1500000,0x11000c02,0x6800000,0x1329800,0x11000c02,0x7c00100,0x230400,0x11000c02,0x7c00100,0x230401,0x11000c02,
+0x7c00100,0x230402,0x11000c02,0x7c00500,0x230400,0x11000c02,0x7d00100,0x230400,0x11000f01,0x2802400,0x962460,0x11000f0a,0x2802100,0x962460,0x11000f0a,0x2802400,
+0x962460,0x11000f0a,0x2806400,0x962460,0x11000f0a,0x4000000,0x200000,0x11000f0a,0x6800100,0x962540,0x11000f0a,0x7c00100,0x230400,0x11000f0a,0x7c00100,0x230401,
+0x11001004,0x2802100,0x962460,0x11001004,0x2802400,0x962460,0x11001004,0x2806400,0x962460,0x11001004,0x4000000,0x200000,0x11001004,0x4000000,0x1500000,0x11001004,
+0x6800100,0x962540,0x11001004,0x6800100,0x962541,0x11001004,0x7c00100,0x230400,0x11001004,0x7c00100,0x230401,0x11001110,0x2802100,0x962460,0x11001110,0x2802400,
+0x962460,0x11001110,0x2806400,0x962460,0x11001110,0x6800100,0x962540,0x11001110,0x7c00100,0x230400,0x11001110,0x7c00100,0x230401,0x1100120f,0x2802100,0x962460,
+0x1100120f,0x2802400,0x962460,0x1100120f,0x2806400,0x962460,0x1100120f,0x6800100,0x962540,0x1100120f,0x7c00100,0x230400,0x1100131f,0x2802100,0x962460,0x1100131f,
+0x2802400,0x962460,0x1100131f,0x2806400,0x962460,0x1100131f,0x4000000,0x200000,0x1100131f,0x6800000,0x1329800,0x1100131f,0x6800100,0x962540,0x1100131f,0x6800100,
+0x962541,0x1100131f,0x7c00100,0x230400,0x1100131f,0x7c00100,0x230401,0x11001423,0x2802100,0x962460,0x11001423,0x2806400,0x962460,0x11001423,0x6800100,0x962540,
+0x11001423,0x6800100,0x962541,0x11001423,0x7c00100,0x230400,0x11001423,0x7c00100,0x230401,0x11001524,0x2802100,0x962460,0x11001524,0x2802100,0x962461,0x11001524,
+0x2806400,0x962460,0x11001524,0x6800000,0x1329800,0x11001524,0x6800100,0x962540,0x11001524,0x7c00100,0x230400,0x11001615,0x2802100,0x962460,0x11001615,0x2806400,
+0x962460,0x11001615,0x6800100,0x962540,0x11001615,0x6800100,0x962541,0x11001615,0x7c00100,0x230400,0x1100171a,0x2802100,0x962460,0x1100171a,0x2806400,0x962460,
+0x1100171a,0x6800000,0x1329800,0x1100171a,0x6800100,0x962540,0x1100171a,0x6800100,0x962541,0x1100171a,0x7c00100,0x230400,0x11001900,0x4000000,0x1600000,0x11001926,
+0x2802100,0x1862460,0x11001926,0x2802400,0x1862460,0x11001926,0x2806100,0x1862460,0x11001926,0x4000000,0x200000,0x11001926,0x4000010,0x400000,0x11001926,0x6800000,
+0x1329800,0x11001926,0x7800100,0x1830142,0x11001926,0x7c00100,0x1830000,0x11001926,0x7c00900,0x1830000,0x11001926,0x7e00100,0x1830000,0x11001a18,0x2802100,0x1862460,
+0x11001a18,0x2802400,0x1862460,0x11001a18,0x6800000,0x1329800,0x11001a18,0x7800100,0x1830142,0x11001a18,0x7c00100,0x1830000,0x11001a18,0x7c00100,0x1830002,0x11001a18,
+0x7c00900,0x1830000,0x11001a18,0x7e00100,0x1830000,0x11001d0c,0x7c00100,0x230400,0x11001d0c,0x7c00100,0x250400,0x11001e12,0x7c00100,0x2230500,0x11001e12,0x7c00100,
+0x2330520,0x11001e12,0x7c80100,0x2330520,0x11002619,0x7c00100,0x220401,0x11002619,0x7c00100,0x220402,0x11002619,0x7c00100,0x250401,0x1100270e,0x4000400,0x200001,
+0x1100270e,0x4000400,0x200002,0x1100270e,0x4000400,0x500001,0x1100270e,0x7c00100,0x220401,0x1100270e,0x7c00100,0x250401,0x11002800,0x80000,0x918820,0x11002800,
+0x80000,0x1c18020,0x11002800,0x180000,0x918820,0x11002800,0x4000001,0x445801,0x11002800,0x4000001,0x445802,0x11002800,0x4000001,0xc4000b,0x11002800,0x6800000,
+0x201c00,0x11002800,0x6800020,0x201c00,0x11002800,0x24000000,0x200000,0x11002800,0x24000000,0x200002,0x11002800,0x24000000,0x810000,0x11002800,0x24000000,0x1410000,
+0x11002800,0x24000000,0x1500000,0x11002800,0x24000000,0x1500002,0x11002800,0x24000002,0x400000,0x11002800,0x24000006,0xc0000b,0x11002800,0x24000008,0x1410000,0x11002800,
+0x24000008,0x1710000,0x11002800,0x24000020,0x1001400,0x11002800,0x24000020,0x1500002,0x11002800,0x2c000010,0x1248000,0x11002800,0x2c000010,0x1248002,0x11002800,0x40000001,
+0x63b020,0x11002800,0x40080000,0x918820,0x11002801,0x80000,0x2a65620,0x11002801,0x82000,0x962460,0x11002900,0x4000000,0x20000e,0x11002900,0x4000000,0x20000f,
+0x11002900,0x4000020,0x20000e,0x11002900,0x4000020,0x20000f,0x11002900,0x4000020,0x81000e,0x11002900,0x4000020,0x81000f,0x11002900,0x4000020,0x141000e,0x11002900,
+0x4000020,0x141000f,0x11002900,0x4000022,0x20000e,0x11002900,0x4000022,0x20000f,0x11002a00,0x4000000,0x1500000,0x11002a00,0x4000000,0x1600000,0x11002a00,0x4000000,
+0x1600002,0x11002b01,0x2000,0x962460,0x11002b01,0x2802020,0x962460,0x11002c00,0x4000000,0x200000,0x11002c00,0x4000000,0x200002,0x11002c00,0x4000000,0x20000f,
+0x11002c00,0x4000020,0x200000,0x11002c00,0x7c00000,0x200000,0x11002c00,0x7c00020,0x200000,0x11002c00,0x7c00120,0x220405,0x11002c00,0x7c00120,0x230402,0x11002c00,
+0x7c00120,0x250402,0x11002c00,0x7c00120,0x250405,0x11002c19,0x7c00100,0x250400,0x11002c19,0x7c00100,0x250401,0x11002d00,0x4000000,0x100006,0x11002d00,0x4000000,
+0x200006,0x11002d19,0x7c00100,0x220402,0x11002d19,0x7c00100,0x230400,0x11002d19,0x7c00100,0x250402,0x11002e00,0x24000000,0x200000,0x11002e00,0x24000020,0x200000,
+0x11002e00,0x24000020,0x200001,0x11002f00,0x24000020,0x200000,0x11002f00,0x24000020,0x200001,0x11002f00,0x24000020,0x200002,0x11002f00,0x24000020,0xf00000,0x11002f00,
+0x24000020,0x1600000,0x11002f00,0x24000022,0x1600000,0x11003000,0x24000000,0x200000,0x11003000,0x24000020,0x200000,0x11003000,0x24000020,0x810000,0x11003000,0x24000020,
+0x1410000,0x11003100,0x24000000,0x200000,0x11003200,0x24000000,0x200000,0x11003300,0x4000000,0x100003,0x11003400,0x24000000,0x100000,0x11003400,0x24000000,0x200000,
+0x11003500,0x24000000,0x200000,0x11003600,0x24000000,0x200000,0x11003600,0x24000020,0x200000,0x11003700,0x24000000,0x200000,0x11003700,0x24000000,0xe00000,0x11003700,
+0x24000000,0x2800000,0x11003700,0x24000020,0x200000,0x11003800,0x4000000,0x100000,0x11003800,0x24000000,0x200000,0x11003800,0x24000000,0xb00000,0x11003800,0x24000000,
+0xe00000,0x11003800,0x24000000,0x1710000,0x11003800,0x24000000,0x2800000,0x11005003,0x7c00100,0x220402,0x11005013,0x2802500,0x962460,0x11005013,0x4000020,0x200005,
+0x11005013,0x7c00100,0x2633801,0x11005013,0x7c00100,0x2633802,0x11005013,0x7c00100,0x2633805,0x11005019,0x7c00100,0x220402,0x11005102,0x7000100,0x230408,0x11005102,
+0x7c00100,0x230404,0x11005102,0x7c00100,0x230407,0x11005102,0x7c00100,0x230408,0x11005102,0x7c00100,0x230409,0x11005201,0x2802400,0x962460,0x11005500,0x80000,
+0x1e18820,0x11005502,0x7000100,0x230408,0x11005502,0x7c00100,0x230404,0x11005502,0x7c00100,0x230407,0x11005502,0x7c00100,0x230408,0x11005502,0x7c00100,0x230409,
+0x11005667,0x1000,0,0x11020200,0x80004,0x418820,0x11020200,0x4000000,0x100006,0x11020200,0x4000000,0x10000f,0x11020200,0x4000400,0x100002,0x11020200,
+0x4000400,0x500002,0x11020200,0x6800c00,0x101000,0x11020200,0x24000000,0x100000,0x11020200,0x24000000,0x200000,0x11020200,0x24000000,0x1400000,0x11020200,0x24000000,
+0x1500000,0x11020200,0x24000000,0x1600000,0x11020200,0x24000020,0x100000,0x11020200,0x24000020,0x1600000,0x11020219,0x7c00100,0x12040f,0x11020219,0x7c00100,0x220400,
+0x11020219,0x7c00100,0x220401,0x11020219,0x7c00100,0x250400,0x11020319,0x7c00100,0x220400,0x11020319,0x7c00100,0x220401,0x11020319,0x7c00100,0x220402,0x11020319,
+0x7c00100,0x250400,0x11020319,0x7c00100,0x250402,0x11020319,0x7d00100,0x220402,0x11020419,0x7c00100,0x220401,0x11020519,0x7c00100,0x220400,0x11020600,0x4000400,
+0x100002,0x11020600,0x4000400,0x200400,0x11020600,0x7c00500,0x130400,0x11020600,0x7c00d00,0x130400,0x11020701,0x2802400,0x962460,0x11020701,0x2802400,0x962461,
+0x11020701,0x2802400,0xc62460,0x1102080e,0x7c00100,0x220400,0x1102080e,0x7c00100,0x250400,0x11020908,0x7c00100,0x220400,0x11020908,0x7c00100,0x220401,0x11020908,
+0x7c00100,0x250400,0x11020908,0x7c00100,0x250401,0x11022800,0x24000000,0x100000,0x11022800,0x24000000,0x200000,0x11022800,0x24000000,0x200002,0x11022800,0x24000000,
+0x401000,0x11022800,0x24000000,0xf00002,0x11022800,0x24000000,0xf0ac02,0x11022800,0x24000000,0x1500000,0x11022800,0x24000002,0x100000,0x11022800,0x24000002,0x370000,
+0x11022800,0x24000002,0x470000,0x11022800,0x24000006,0x400000,0x11022800,0x24000008,0x1710000,0x11022800,0x24000008,0x1712c00,0x11022800,0x24000020,0x100000,0x11022800,
+0x24000020,0x1500000,0x11022800,0x24000020,0x1500002,0x11022900,0x4000000,0x10000e,0x11022900,0x4000000,0x10000f,0x11022919,0x7c00100,0x12040f,0x11022c00,0x4000000,
+0x100002,0x11022c00,0x4000000,0x10000f,0x11022c00,0x4000000,0x1500002,0x11022c00,0x4000000,0x1600002,0x11022c00,0x7c00120,0x120405,0x11022c0e,0x7c00100,0x250401,
+0x11022c19,0x7c00100,0x150401,0x11022d00,0x4000000,0x100006,0x11022d00,0x4000000,0x200006,0x11022d19,0x7c00100,0x120402,0x11022d19,0x7c00100,0x150402,0x11022e00,
+0x24000000,0x200000,0x11022e00,0x24000020,0x100000,0x11022f00,0x24000020,0x100000,0x11022f00,0x24000020,0x100001,0x11022f00,0x24000020,0x100002,0x11023000,0x24000000,
+0x100000,0x11023300,0x4000000,0x100002,0x11023300,0x4000000,0x100003,0x11023300,0x4000100,0x120403,0x11023300,0x4000100,0x150403,0x11023400,0x24000000,0x100000,
+0x11023500,0x24000000,0x100000,0x11023600,0x24000000,0x100000,0x11023600,0x24000020,0x100000,0x11023700,0x24000000,0x100000,0x11023700,0x24000000,0xe00000,0x11023700,
+0x24000020,0x100000,0x11023800,0x4000000,0x100000,0x11023800,0x24000000,0x200000,0x11024e67,0,0,0x11025600,0x4000000,0x100000,0x11042a00,0x4000000,
+0x1600000,0x11045700,0x4000000,0x20000a,0x11045700,0x4000020,0x20000a,0x11045712,0x7c00100,0xe3040a,0x11045712,0x7c80100,0xe3040a,0x11045716,0x7c00100,0xe30c0a,
+0x11045716,0x7c00100,0x2530c0a,0x11063d00,0x4000001,0x445811,0x11065700,0x4000000,0x810011,0x11065700,0x4000000,0xe00011,0x11065700,0x4000000,0x1410011,0x11065700,
+0x4000000,0x1500011,0x11065700,0x4000000,0x1600011,0x11065700,0x4000006,0xe70011,0x11065700,0x4000008,0xe00011,0x11065700,0x4000008,0xe02c11,0x11065700,0x4000010,
+0x871411,0x11065700,0x4000010,0x1201411,0x11065700,0x4000010,0x1271011,0x11065700,0x4000020,0xe00011,0x11065700,0x4000400,0xe00011,0x11065700,0x4000420,0xe00011,
+0x11065700,0x6800000,0xe01c11,0x11065700,0x6800040,0xe29811,0x11065700,0xc000010,0x80ac11,0x11065700,0xc000010,0xb48011,0x11065719,0x7c00100,0xe20411,0x11065719,
+0x7c00100,0xe50411,0x11065719,0x7c00140,0xe20411,0x11065719,0x7c00140,0xe50411,0x11080100,0x6800000,0x201c00,0x11080100,0x68000c0,0x1329800,0x11080100,0x24000000,
+0x200000,0x11080100,0x24000000,0x810000,0x11080100,0x24000000,0x1410000,0x11080100,0x24000000,0x1500000,0x11080100,0x24000000,0x1600000,0x11080100,0x24000000,0x1b00000,
+0x11080100,0x24000000,0x2410000,0x11080100,0x24000006,0xd70000,0x11080100,0x24000008,0x1713c00,0x11080100,0x24000008,0x1714000,0x11080100,0x24000010,0x1001400,0x11080100,
+0x24000010,0x1071000,0x11080100,0x24000010,0x1071400,0x11080100,0x24000020,0x200000,0x11080100,0x24000020,0x400000,0x11080100,0x24000020,0x1600000,0x11080100,0x24000400,
+0x200000,0x11080100,0x24000420,0x200000,0x11080100,0x2c000010,0xb48000,0x11080100,0x2c000010,0x100ac00,0x11080100,0x44000001,0x1a45800,0x11080119,0x7c00100,0x220400,
+0x11080119,0x7c00100,0x250400,0x11080119,0x7c001c0,0x220400,0x11080119,0x7c001c0,0x250400,0x11080200,0x4000400,0x200002,0x11080200,0x24000000,0x200000,0x11080200,
+0x24000000,0x1500000,0x11080200,0x24000000,0x1600000,0x11080200,0x24000020,0x200000,0x110a1e12,0x7c00100,0x2130480,0x110a1e12,0x7c80100,0x2130480,0x110a3000,0x24000000,
+0xe00000,0x110a3000,0x24100000,0x810001,0x110a3000,0x24100000,0x1410001,0x110a3700,0x24000000,0x200000,0x110a3d00,0x4000000,0xe00000,0x110a3d00,0x4000000,0xe00002,
+0x110a3d00,0x24000000,0xe00000,0x110a3d11,0x7c00300,0xe30000,0x110a3d11,0x7c00900,0x1230400,0x110a3d12,0x2802400,0x962460,0x110a3e14,0x7c00100,0xe30000,0x110a3e14,
+0x7c00100,0xe30001,0x110a3e14,0x7c00100,0x2530000,0x110a3e14,0x7c00900,0x1230000,0x110a3e14,0x7c00900,0x1230001,0x110a3f16,0x7c00100,0xe30c00,0x110a3f16,0x7c00100,
+0xe30c01,0x110a3f16,0x7c00100,0x2530c00,0x110a3f16,0x7c00900,0x1230c00,0x110a3f16,0x7c00900,0x1230c01,0x110a4005,0x7c00100,0xe30400,0x110a4112,0x7c00100,0xe30402,
+0x110a4112,0x7c80100,0xe30402,0x110a4400,0x4000000,0xe00000,0x110a4412,0x4000000,0xe00002,0x110a4412,0x4000000,0xe00003,0x110a4416,0x4000000,0xe00c03,0x110a4500,
+0x4000000,0xe0000d,0x110a4516,0x4000000,0xe00c0d,0x110a4711,0x7c40300,0xe30000,0x110a4f11,0x7c00300,0xe30001,0x110a4f11,0x7c40300,0xe30000,0x110a5300,0x4000000,
+0x810010,0x110a5300,0x4000000,0xe00002,0x110a5300,0x4000000,0xe00010,0x110a5300,0x4000000,0x1410010,0x110a5300,0x4000002,0xe70010,0x110a5300,0x4000008,0x810010,
+0x110a5300,0x4000008,0x1410010,0x110a5300,0x6800000,0xe01c02,0x110a5300,0x6800000,0xe01c10,0x110a5400,0x4000000,0x81000c,0x110a5400,0x4000000,0xe0000c,0x110a5400,
+0x4000000,0x141000c,0x110a5400,0x4000000,0x150000c,0x110a5400,0x4000000,0x160000c,0x110a5400,0x4000002,0xe7000c,0x110a5400,0x4000010,0x87140c,0x110a5400,0x4000010,
+0xe7000c,0x110a5400,0x4000010,0x120140c,0x110a5400,0x4000010,0x127100c,0x110a5400,0x4000020,0xe0000c,0x110a5400,0x4000026,0xe7000c,0x110a5400,0xc000010,0x80ac0c,
+0x110a5400,0xc000010,0xb4800c,0x11400c0c,0x4000010,0xb00000,0x11400c0c,0x4000010,0x1071400,0x11400c17,0xc000010,0xb48000,0x11400c1e,0x7c00900,0x230400,0x11400f4b,
+0xc000010,0x448000,0x11400f5f,0xc000010,0x448000,0x11401d94,0x4000000,0x200000,0x11403dca,0x4000000,0xe00000,0x114457bf,0x4000004,0x120000a,0x114457bf,0x4000008,
+0x81000a,0x114457bf,0x4000008,0x141000a,0x114457bf,0x4000010,0x87000a,0x114457bf,0xc000010,0x84800a,0x114457c8,0x3802500,0x126246a,0x114457c8,0x7c00d00,0x2530c0a,
+0x114a3dbf,0x24000000,0x810000,0x114a3dbf,0x24000000,0x1410000,0x114a3dbf,0x24000008,0x810000,0x114a3dbf,0x24000008,0x1410000,0x114a3dbf,0x24000010,0x870000,0x114a3dbf,
+0x2c000010,0x848000,0x114a3dc5,0x4000000,0xe00000,0x114a3dc5,0x24000000,0xe00000,0x114a3dc5,0x24000002,0xe00000,0x114a3dc5,0x24000002,0x1200000,0x114a3dc5,0x24000008,
+0x810000,0x114a3dc5,0x24000008,0x1410000,0x114a3dc8,0x7c00900,0x930c00,0x114a3dc8,0x7c00900,0xe30c00,0x114a3dca,0x7c00300,0xe30000,0x114a3ec8,0x7000400,0x1200c02,
+0x114a3fbf,0x4000004,0x1200000,0x114a3fc8,0x7c00d00,0x2530c00,0x114a42ca,0x4000000,0xe00000,0x114a42ca,0x4000000,0xe0000f,0x114a44ca,0x4000000,0xe00002,0x114a44ca,
+0x4000000,0xe00003,0x114a45ca,0x4000000,0xe00002,0x114a45ca,0x4000000,0xe0000d,0x11505103,0x24000000,0x810000,0x11505103,0x24000000,0x1410000,0x1180090a,0x2802400,
+0x962460,0x11800c27,0x2802100,0x962460,0x11800c27,0x2802500,0x962460,0x11800f32,0x2802400,0x962460,0x11800f3f,0x2802400,0x962460,0x11820700,0x2802400,0x962460,
+0x11820700,0x2802500,0x962460,0x118a3dcb,0x2802400,0x962460,0x118a3ec8,0x2802400,0x962460,0x11c00904,0x2802400,0x962460,0x11c00908,0x2802400,0x962460,0x11c00c2c,
+0x6800000,0x1329800,0x11c00c30,0xc000010,0xb48000,0x11c00f78,0x6800000,0x1329800,0x11c0107d,0x6800000,0x1329800,0x11c01181,0x6800000,0x1329800,0x11c01285,0x6800000,
+0x1329800,0x11c01489,0x4000000,0x200000,0x11c01489,0x6800000,0x1329800,0x11c0168d,0x6800000,0x1329800,0x11d05107,0x7c00100,0x230408,0x20000067,0x1000,0,
+0x20000b13,0x2802400,0x962460,0x20000b13,0x2802500,0x962460,0x20001b27,0x2802100,0x962460,0x20001b27,0x2802100,0x962461,0x20001b27,0x2802400,0x962460,0x20001b27,
+0x2802500,0x962460,0x20001b27,0x2806400,0x962460,0x20001b27,0x2902100,0x962462,0x20001b27,0x4000000,0x200000,0x20001b27,0x4000000,0x400000,0x20001b27,0x4000000,
+0x500000,0x20001b27,0x4000000,0x810000,0x20001b27,0x4000000,0xb00000,0x20001b27,0x4000000,0xc0000b,0x20001b27,0x4000000,0x1410000,0x20001b27,0x4000010,0xb00000,
+0x20001b27,0x4000010,0xc00000,0x20001b27,0x6800000,0x1329800,0x20001b27,0x6800100,0x462540,0x20001b27,0x6800400,0x962540,0x20001b27,0x7c00100,0x230400,0x20001b27,
+0x7c00100,0x230401,0x20002619,0x7c00100,0x220401,0x20002a00,0x4000000,0x1600000,0x20004b67,0,0x1900000,0x20004c67,0,0x1900000,0x20004d67,0,
+0x1900000,0x20006d67,0x1000,0,0x20006e67,0x1000,0,0x20026d67,0,0,0x20026e67,0,0,0x200a4a12,0x7c00100,0x1f304c1,
+0x200a4a12,0x7c00100,0x20304e1,0x21005600,0x4000000,0x700000,0x21022a00,0x4000000,0x1600000,0x30000419,0x7c00100,0x220400,0x30000419,0x7c00100,0x220401,0x30000419,
+0x7c00100,0x250400,0x30000419,0x7c00100,0x250401,0x30000519,0x7c00100,0x220400,0x30000600,0x4000400,0x200400,0x30000600,0x7c00500,0x230400,0x30000605,0x4000400,
+0x200400,0x3000080e,0x7c00100,0x220400,0x30000908,0x2000,0x962460,0x30000908,0x7c00100,0x220400,0x30000908,0x7c00100,0x220401,0x30000908,0x7c00100,0x250400,
+0x30000908,0x7c00100,0x250401,0x30000a03,0x4000006,0x400400,0x30000c02,0x4000000,0x200000,0x30000c02,0x7c00100,0x230400,0x30000d22,0x2802100,0x962460,0x30000d22,
+0x2802400,0x962460,0x30000d22,0x2802500,0x962460,0x30000d22,0x4000000,0x200000,0x30000d22,0x4000010,0x200000,0x30000d22,0x7c00100,0x230400,0x30000d22,0xc000010,
+0x248000,0x30000d22,0x80000000,0x218960,0x30000e25,0x2802500,0x962460,0x30000e25,0x7c00100,0x230400,0x30001821,0x2802100,0x962460,0x30001821,0x2806400,0x962460,
+0x30001821,0x4000000,0x200000,0x30001821,0x6800100,0x962540,0x30001821,0x6800100,0x962541,0x30001821,0x7c00100,0x230400,0x30001b27,0x2802100,0x962460,0x30001b27,
+0x2802400,0x962460,0x30001b27,0x4000000,0x200000,0x30001b27,0x4000000,0x400000,0x30001b27,0x7c00100,0x230400,0x30001c1c,0x2802100,0x1862460,0x30001c1c,0x2802400,
+0x1862460,0x30001c1c,0x2806400,0x1862460,0x30001c1c,0x4000000,0x200000,0x30001c1c,0x6800100,0x1862400,0x30001c1c,0x6800100,0x1862540,0x30001c1c,0x7c00100,0x1830000,
+0x30001c1c,0x7c00100,0x1830001,0x30001c1c,0xc000010,0x448000,0x30001f0b,0x4000000,0x200000,0x30001f0b,0x4000010,0x200000,0x30001f0b,0x4000010,0x400000,0x30001f0b,
+0x6800000,0x200000,0x30001f0b,0x7c00100,0x230400,0x30001f0b,0xc000010,0x248000,0x30002006,0x7c00100,0x250400,0x30002128,0x4000000,0x200000,0x30002128,0x7c00100,
+0x230400,0x30002128,0xc000010,0x248000,0x3000221d,0x4000000,0x810000,0x3000221d,0x4000000,0x1410000,0x3000221d,0x4000001,0x445800,0x3000221d,0x7c00100,0x230400,
+0x30002300,0x4000010,0x400000,0x30002320,0x7c00100,0x230400,0x30002417,0x2802100,0x1862460,0x30002417,0x2802400,0x1862460,0x30002417,0x2806400,0x1862460,0x30002417,
+0x2882000,0x1862460,0x30002417,0x4000000,0x200000,0x30002417,0x4000000,0x400000,0x30002417,0x4000000,0x1600000,0x30002417,0x4000010,0x400000,0x30002417,0x4000010,
+0x1200000,0x30002417,0x6800000,0x1329800,0x30002417,0x6800100,0x1862540,0x30002417,0x7c00100,0x1830000,0x30002417,0x7d00100,0x1830000,0x3000251b,0x80000,0xc18820,
+0x3000251b,0x2802100,0x962460,0x3000251b,0x3c02100,0x962460,0x3000251b,0x4000000,0x200000,0x3000251b,0x4000006,0x500000,0x3000251b,0x4000010,0x400000,0x3000251b,
+0x4000010,0xb70000,0x3000251b,0x4000800,0x200000,0x3000251b,0x6800000,0x1329800,0x3000251b,0x7c00100,0x230400,0x3000251b,0x7c00900,0x230400,0x3000251b,0xc000010,
+0xb48000,0x3000251b,0x12882000,0x962460,0x30002800,0x24000000,0x200000,0x30002800,0x2c000010,0x1248002,0x30002a00,0x4000000,0x1600000,0x30002b01,0x2000,0x962460,
+0x30002c00,0x4000000,0x200000,0x30002c00,0x7c00100,0x220405,0x30002d19,0x7c00100,0x250400,0x30002e00,0x24000000,0x200000,0x30003000,0x24000000,0x200000,0x30003100,
+0x24000000,0x200000,0x30003600,0x24000000,0x200000,0x30003700,0x24000000,0x200000,0x3000392e,0x24000000,0x200000,0x30005013,0x7c00100,0x2633801,0x30005600,0,
+0x918820,0x30020600,0x4000400,0x500400,0x30020701,0x2802400,0x962460,0x30020701,0x2802400,0xc62460,0x300a3a11,0x4020000,0xe00000,0x300a3a11,0x4020000,0xe00002,
+0x300a3b11,0x4020000,0xe00002,0x300a3c00,0x4008000,0xe00000,0x300a3c00,0x4010000,0xe00000,0x300a3d11,0x7c00300,0xe30002,0x300a4305,0x7c00100,0xe30400,0x300a4611,
+0x7c40300,0xe30000,0x300a4829,0x7c00100,0xe30400,0x300a4829,0x7c00900,0x1230400,0x300a4929,0x4000000,0xe00000,0x3040259a,0x4000010,0x400000,0x3040259a,0x4000010,
+0xb70000,0x3040259a,0xc000010,0xb48000,0x304028ba,0x4000001,0xc41c0b,0x304a3dca,0x4000000,0xe00000,0x30800c27,0x2802100,0x962460,0x30c01c92,0x6800000,0x1329800,
+0x3100080e,0x7c00120,0x220402,0x3100080e,0x7c00120,0x250402,0x31005167,0x1000,0,0x3100581e,0x4000000,0x200000,0x3100581e,0x7c00100,0x230400,0x3100590d,
+0x7c00100,0x230400,0x31005a09,0x7c00100,0x220400,0x31005a09,0x7c00100,0x250400,0x31005b00,0x4000000,0x200000,0x31005c00,0x80000,0x918820,0x31005c00,0x2802000,
+0x962460,0x31005c00,0x2802400,0x962460,0x31005c00,0x4000000,0x200000,0x31005c00,0x4000000,0x200001,0x31005c00,0x6800000,0x962540,0x31005c00,0x6800400,0x962540,
+0x31005c01,0x2802400,0x962460,0x31005d00,0x4000020,0x200005,0x31005d00,0x6800020,0x1329805,0x31005d00,0x7c00120,0x220405,0x31005d00,0x7c00120,0x250405,0x31006000,
+0x82000,0x962460,0x31006000,0x180000,0x918820,0x310a5e11,0x7c40300,0xe30000,0x310a5f11,0x7c00300,0xe30001,0x32000419,0x7c00100,0x250400,0x3200080e,0x4000020,
+0x200000,0x3200080e,0x7c00100,0x220400,0x3200080e,0x7c00100,0x250400,0x32000908,0x7c00100,0x220400,0x32000908,0x7c00100,0x250400,0x32000c02,0x7c00100,0x230400,
+0x32000e25,0x7c00100,0x230400,0x32001d0c,0x7c00100,0x230400,0x32002800,0x80000,0x1e18820,0x32002800,0x80020,0x218820,0x32002800,0x4000001,0x445802,0x32002800,
+0x24000000,0x200000,0x32002800,0x24000000,0x1500002,0x32002800,0x24000020,0x200000,0x32002800,0x2c000010,0x1248002,0x32002919,0x7c00100,0x22040f,0x32002a00,0x4000000,
+0x1600000,0x32002b01,0x2000,0x962460,0x32002b01,0x2802000,0x962460,0x32002b01,0x2802020,0x962460,0x32002c00,0x4000000,0x200000,0x32002c00,0x4000020,0x200000,
+0x32002c00,0x4000020,0x200005,0x32002c00,0x7c00120,0x220405,0x32002c00,0x7c00120,0x250405,0x32002e00,0x24000020,0x200000,0x32002f00,0x24000020,0x200000,0x32003000,
+0x24000000,0x200000,0x32003000,0x24000020,0x200000,0x32003500,0x24000000,0x200000,0x32003600,0x24000020,0x200000,0x32003700,0x24000000,0x100000,0x32003700,0x24000000,
+0x200000,0x32003800,0x24000000,0x810000,0x32003800,0x24000000,0x1410000,0x32005102,0x4000000,0x1500008,0x32005502,0x7c00100,0x230400,0x32006108,0x7c00100,0x220400,
+0x32006108,0x7c00100,0x250400,0x3200622a,0x2802100,0x962460,0x3200622a,0x2806400,0x962460,0x3200622a,0x7c00100,0x230400,0x3200632b,0x2802100,0x962460,0x3200632b,
+0x6804000,0x962540,0x3200632b,0x7c00100,0x230400,0x3200642c,0x2802100,0x962460,0x3200642c,0x7c00100,0x230400,0x3200652d,0x2802100,0x962460,0x3200652d,0x7c00100,
+0x230400,0x32006600,0x24000020,0x200000,0x32006700,0x24000020,0x200000,0x32006800,0x24000020,0x200000,0x32006900,0x24000020,0x200000,0x32006900,0x24000020,0x810000,
+0x32006900,0x24000020,0x1410000,0x32006a00,0x24000020,0x200000,0x32006a00,0x24000020,0x200001,0x32006a00,0x24000020,0x200002,0x32020701,0x2882000,0xc62460,0x32023300,
+0x4000000,0x100000,0x32026c01,0x12882000,0x962460,0x32065700,0x4000000,0x810011,0x32065700,0x4000000,0x1410011,0x32086600,0x24000020,0x810000,0x32086600,0x24000020,
+0x1410000,0x32086900,0x24000020,0x810000,0x32086900,0x24000020,0x1410000,0x320a3600,0x24000020,0x200000,0x320a3d11,0x7c00100,0x1230400,0x320a3e14,0x7c00100,0xe30010,
+0x320a3e14,0x7c00100,0x2530000,0x320a3f16,0x7c00100,0xe30c10,0x320a4400,0x4000000,0xe00003,0x320a4929,0x4000000,0xe00000,0x320a4f11,0x7c00300,0xe30001,0x320a6b16,
+0x7c00100,0x2530c00,0x32406396,0xc000010,0x448000,0x324a3dcd,0x4000000,0xe00000,0x324a3dcd,0x7c00100,0x1230400,0x324a3fc8,0x4000002,0x1200c00,0x324a53c5,0x24000000,
+0xe00000,0x32820701,0x2802000,0x962460,0x40000419,0x7c00100,0x220400,0x40000519,0x7c00100,0x220400,0x40000600,0x4000400,0x200400,0x4000080e,0x7c00100,0x220400,
+0x4000080e,0x7c00100,0x250400,0x4000080e,0x7c00100,0x250402,0x40000c02,0x2802100,0x962460,0x40000c02,0x2802400,0x962460,0x40000c02,0x2802500,0x962460,0x40000c02,
+0x4000000,0x200000,0x40000c02,0x4000000,0x1071400,0x40000c02,0x7c00100,0x230400,0x40000c02,0x80000000,0x218960,0x40000d22,0x7c00100,0x230400,0x40000f0a,0x7c00100,
+0x230400,0x40001004,0x7c00100,0x230400,0x40001110,0x2802100,0x962460,0x40001110,0x6800100,0x962540,0x4000120f,0x2802100,0x962460,0x4000120f,0x4000000,0x1600000,
+0x4000120f,0x7c00100,0x230400,0x4000131f,0x7c00100,0x230400,0x40001423,0x4000000,0x200000,0x40001423,0x4000000,0x1600000,0x40001615,0x2802400,0x962460,0x40001615,
+0x7c00100,0x230400,0x40002417,0x2802400,0x1862460,0x40002417,0x4000000,0x200000,0x40002800,0x6800000,0x201c00,0x40002800,0x24000002,0x200000,0x40002c00,0x4000000,
+0x200002,0x40003000,0x24000000,0x200000,0x40003000,0x24000020,0x200000,0x40003700,0x24000000,0x200000,0x40005a09,0x7c00100,0x220400,0x40005a09,0x7c00100,0x250400,
+0x40005d00,0x7c00120,0x220405,0x40006f30,0x2802100,0x962460,0x40006f30,0x2802400,0x962460,0x40006f30,0x4000000,0x200000,0x40006f30,0x6800000,0x1329800,0x40006f30,
+0x6800100,0x962540,0x40006f30,0x7c00100,0x230400,0x40006f30,0xc000010,0xb48000,0x40007034,0x7c00100,0x1830000,0x40007117,0x4000000,0x200000,0x40007208,0x7c00100,
+0x220400,0x4000720e,0x7c00100,0x220400,0x4000720e,0x7c00500,0x22040e,0x4000720e,0x7c00500,0x22040f,0x40007219,0x7c00100,0x220400,0x40007219,0x7c00500,0x220400,
+0x40007219,0x7c00500,0x22040e,0x40007219,0x7c00500,0x22040f,0x40007300,0x24000000,0x200000,0x40007400,0x4000000,0x200000,0x40007531,0x7c00100,0x230400,0x40007631,
+0x7c00100,0x230400,0x40007835,0x4000010,0x400000,0x40007835,0x7c00100,0x230400,0x40007933,0x7c00100,0x230400,0x40007a32,0x6800000,0x1329800,0x40007a32,0x7c00100,
+0x230400,0x40007b2f,0x7c00100,0x230400,0x40007c00,0x4000000,0x200000,0x40020701,0x2802400,0x962460,0x40020701,0x2802400,0xc62460,0x40023300,0x4000000,0x200000,
+0x40027d01,0x12882000,0x962460,0x400a3700,0x24000000,0x200000,0x400a3700,0x24000000,0xe00000,0x400a4400,0x4000000,0xe0000d,0x400a4412,0x4000000,0xe00002,0x400a4412,
+0x4000000,0xe00003,0x400a4500,0x4000000,0xe0000d,0x400a5300,0x4000000,0x810010,0x400a5300,0x4000000,0x1410010,0x40507709,0x4000000,0x200000,0x4050770c,0x4000000,
+0x400000,0x4050770f,0x4000000,0x200000,0x4050770f,0x4000000,0x400000,0x40c01489,0x4000000,0x200000,0x40d05107,0x4000000,0x200000,0x41000419,0x7c00100,0x220400,
+0x41000419,0x7c00100,0x250400,0x4100080e,0x7c00100,0x220400,0x4100080e,0x7c00100,0x250400,0x41000908,0x7c00100,0x220400,0x41000908,0x7c00100,0x250400,0x41000b13,
+0x2802000,0x962460,0x41000b13,0x2802100,0x962460,0x41000b13,0x4000000,0xb00000,0x41000c02,0x2802100,0x962460,0x41000c02,0x4000000,0x1500000,0x41000c02,0xc000010,
+0xb48000,0x41000f0a,0x7c00100,0x230400,0x41001004,0x7c00100,0x230400,0x41001423,0x7c00100,0x230400,0x41001b27,0x4000000,0x500000,0x41001d0c,0x7c00100,0x22040f,
+0x41001d0c,0x7c00100,0x230400,0x41001f0b,0x2802400,0x962460,0x41001f0b,0x4000000,0x200000,0x41001f0b,0x7c00100,0x230400,0x41002800,0x24000000,0x200000,0x41002800,
+0x24000000,0x400000,0x41002919,0x7c00100,0x22040e,0x41002a00,0x4000000,0x1600000,0x41002b01,0x2802020,0x962460,0x41002c00,0x4000000,0x200000,0x41002c00,0x7c00120,
+0x220405,0x41003000,0x24000000,0x200000,0x41003700,0x24000000,0x200000,0x41003700,0x24000000,0xe00000,0x41005d00,0x7c00120,0x220405,0x41006600,0x24000020,0x200000,
+0x41006600,0x24000020,0x810000,0x41006600,0x24000020,0x1410000,0x41007208,0x7c00100,0x22040f,0x41007219,0x7c00100,0x220400,0x41007300,0x24000000,0x200000,0x41007e0e,
+0x2802000,0x962460,0x41007e0e,0x4000000,0x200000,0x41007f0e,0x4000000,0x200000,0x41007f0e,0x7c00100,0x230400,0x41008002,0x7c00100,0x230400,0x41008137,0x2802100,
+0x962460,0x41008137,0x4000000,0x200000,0x41008137,0x6800100,0x962540,0x41008137,0x7c00100,0x230400,0x41008301,0x2802000,0x962460,0x41008407,0x4000000,0x200000,
+0x41008407,0x4000000,0x400000,0x41008407,0x4000000,0xb00000,0x41008407,0x7c00100,0x220400,0x41008407,0x7c00100,0x250400,0x4100850b,0x7c00100,0x230400,0x4100860b,
+0x4000000,0x200000,0x4100860b,0x7c00100,0x230400,0x4100870c,0x7c00100,0x220400,0x41008838,0x7c00100,0x220400,0x41008838,0x7c00100,0x250400,0x41008939,0x2802000,
+0x962460,0x41008939,0x2802100,0x962460,0x41008939,0x2806000,0x962460,0x41008939,0x4000000,0x200000,0x41008939,0x4000000,0x400000,0x41008939,0x7c00100,0x230400,
+0x41008939,0xc000010,0x448000,0x41008a00,0x4000400,0x200400,0x41008b3b,0x4000000,0x1800000,0x41008b3b,0x6800000,0x1329800,0x41008b3b,0x7c00100,0x1830000,0x41008b3b,
+0x7e00100,0x1830000,0x41008c3d,0x4000010,0x400000,0x41008c3d,0x7c00100,0x230400,0x41008d0e,0x7c00100,0x22040f,0x41008d19,0x7c00100,0x220400,0x41008d19,0x7c00100,
+0x22040f,0x41008e00,0x24000000,0x200000,0x41008e00,0x24000000,0x400000,0x41008e00,0x24000000,0x1710000,0x41008e00,0x24000006,0x400000,0x41008f3a,0x2802100,0x962460,
+0x41008f3a,0x2806000,0x962460,0x41008f3a,0x4000000,0x200000,0x41008f3a,0x6800100,0x962540,0x41008f3a,0x7c00100,0x230400,0x4100903c,0x7c00100,0x230400,0x4100903c,
+0x7c00100,0x23040f,0x41020701,0x2802000,0x962460,0x41020701,0x2802000,0xc62460,0x410a3700,0x24000000,0x200000,0x410a3700,0x24000000,0xe00000,0x410a4412,0x4000000,
+0xe00003,0x410a4711,0x7c40300,0xe30000,0x410a4f11,0x7c00300,0xe30001,0x410a9100,0x4000000,0x800010,0x410a9100,0x4000000,0x810010,0x410a9100,0x4000000,0x870010,
+0x410a9100,0x4000000,0xb00010,0x410a9100,0x4000000,0xf00010,0x410a9100,0x4000000,0x1001410,0x410a9100,0x4000000,0x1071010,0x410a9100,0x4000000,0x1071410,0x410a9100,
+0x4000000,0x1410010,0x41408ad0,0x4000400,0x200000,0x414a82ca,0x4000000,0xe00000,0x41808300,0x2802000,0x962460,0x41c01489,0x6800000,0x1329800,0x50000419,0x7c00100,
+0x220400,0x50000419,0x7c00100,0x250400,0x5000080e,0x7c00100,0x220400,0x50000908,0x7c00100,0x220400,0x50000908,0x7c00100,0x250400,0x50000b13,0x2802500,0x962460,
+0x50000f0a,0x7c00100,0x230400,0x50001615,0x2802100,0x962460,0x50001615,0x7c00100,0x230400,0x50002b01,0x2802020,0x962460,0x50002c00,0x4000000,0x200000,0x50002c19,
+0x7c00100,0x220400,0x50002d19,0x7c00100,0x220400,0x50003000,0x24000000,0x200000,0x50003000,0x24000020,0x200000,0x50003700,0x24000000,0x200000,0x50005d00,0x7c00120,
+0x220405,0x50005d00,0x7c00120,0x250405,0x50006108,0x7c00100,0x220400,0x50006108,0x7c00100,0x250400,0x50006600,0x24000020,0x200000,0x50007300,0x24000000,0x200000,
+0x50008301,0x2802400,0x962460,0x50008a00,0x7c00500,0x230400,0x50009257,0x2802400,0x962460,0x50009257,0x4000000,0x200000,0x50009257,0x4000010,0x1071400,0x50009257,
+0x6800000,0x1329800,0x50009257,0x7c00100,0x230400,0x50009257,0x7c00500,0x230400,0x50009257,0x7c00900,0x230400,0x50009257,0xc000010,0xb48000,0x5000933e,0x2802100,
+0x962460,0x5000933e,0x2802400,0x962460,0x5000933e,0x4000000,0x200000,0x5000933e,0x4000000,0x400000,0x5000933e,0x4000010,0x400000,0x5000933e,0x6800000,0x1329800,
+0x5000933e,0x6800100,0x962540,0x5000933e,0x6800100,0x962541,0x5000933e,0x6804400,0x962540,0x5000933e,0x7c00100,0x230400,0x5000933e,0x7c00100,0x230401,0x5000933e,
+0xc000010,0x448000,0x50009419,0x7c00100,0x220400,0x50009419,0x7c00100,0x250400,0x50009500,0x4000400,0x200400,0x5000965a,0x4000000,0x500000,0x5000965a,0x7c00100,
+0x230400,0x5000965a,0xc000010,0xb48000,0x5000975b,0x4000000,0x200000,0x5000975b,0x4000010,0x400000,0x5000975b,0x7c00100,0x230400,0x50009865,0x7c00100,0x230400,
+0x50009965,0x4000010,0x400000,0x50009965,0x7c00100,0x230400,0x50409aca,0x4000000,0x200000,0x5100080e,0x7c00100,0x220400,0x5100080e,0x7c00100,0x250400,0x51000c02,
+0x2802100,0x962460,0x51000c02,0x4000000,0x1500000,0x51000c02,0x4000020,0x200000,0x51000c02,0x7c00100,0x230400,0x51000f0a,0x7c00100,0x230400,0x51000f0a,0x7c00500,
+0x230400,0x51001110,0x2802100,0x962460,0x5100131f,0x2802100,0x962460,0x51001423,0x7c00100,0x230400,0x51001524,0x2802100,0x962460,0x51001524,0x4000000,0x200000,
+0x51001524,0x7c00100,0x230400,0x5100171a,0x2802100,0x962460,0x5100171a,0x4000000,0x200000,0x5100171a,0x4000000,0x1500000,0x5100171a,0x7c00100,0x230400,0x51001b27,
+0x4000000,0x200000,0x51001b27,0x4000000,0x400000,0x51001b27,0x4000000,0x500000,0x51001b27,0x7c00100,0x230400,0x51001c1c,0x2802100,0x1862460,0x51001c1c,0x2802500,
+0x1862460,0x51001c1c,0x2806400,0x1862460,0x51001c1c,0x4000000,0x1800000,0x51001c1c,0x6800000,0x1329800,0x51001c1c,0x6800100,0x1862400,0x51001c1c,0x6800100,0x1862540,
+0x51001c1c,0x6800500,0x1862400,0x51001c1c,0x7c00100,0x1830000,0x5100251b,0x7c00100,0x230400,0x51002619,0x7c00100,0x220400,0x51002619,0x7c00100,0x250400,0x51002800,
+0x80020,0x218820,0x51002c00,0x4000000,0x200000,0x51002d19,0x7c00100,0x230400,0x51003700,0x24000000,0x200000,0x51003700,0x24000000,0xe00000,0x51005201,0x2802400,
+0x962460,0x51005c00,0x4000000,0x200000,0x51006108,0x7c00100,0x220400,0x51006108,0x7c00100,0x250400,0x51006600,0x24000020,0x200000,0x51006600,0x24000020,0x810000,
+0x51006600,0x24000020,0x1410000,0x51007300,0x24000000,0x200000,0x51007300,0x24000020,0x200000,0x51008002,0x7c00100,0x230400,0x51008301,0x2802000,0x962460,0x51008301,
+0x2802400,0x962460,0x51008301,0x2802400,0xc62460,0x51008a00,0x7c00500,0x230400,0x51008e00,0x24000000,0x200000,0x51008e00,0x24000000,0x400000,0x51008e00,0x24000000,
+0x810000,0x51008e00,0x24000000,0x1400000,0x51008e00,0x24000000,0x1410000,0x51008e00,0x24000000,0x1710000,0x51008e00,0x24000002,0x200000,0x51008e00,0x24000500,0x230400,
+0x51008e00,0x2c000010,0xb48000,0x51009419,0x7c00100,0x220400,0x51009419,0x7c00100,0x22040e,0x51009419,0x7c00100,0x22040f,0x51009419,0x7c00100,0x250400,0x51009500,
+0x4000400,0x200400,0x51009500,0x7c00500,0x230400,0x51009519,0x7c00100,0x220400,0x51009519,0x7c00100,0x22040f,0x51009519,0x7c00100,0x230400,0x51009519,0x7c00100,
+0x250400,0x51009b71,0x2802100,0x962460,0x51009b71,0x6800000,0x1329800,0x51009b71,0x6800100,0x962540,0x51009b71,0x6804400,0x962540,0x51009b71,0x7c00100,0x230400,
+0x51009c52,0x2802100,0x962460,0x51009c52,0x2802400,0x962460,0x51009c52,0x2802d00,0x962460,0x51009c52,0x4000010,0x400000,0x51009c52,0x6800000,0x1329800,0x51009c52,
+0x6800100,0x962540,0x51009c52,0x7c00100,0x230400,0x51009c52,0xc000010,0x448000,0x51009d6d,0x6800000,0x1329800,0x51009d6d,0x7c00100,0x230400,0x51009d6d,0x7c00500,
+0x230400,0x51009d6d,0x7c00d00,0x230400,0x51009d6d,0xc000010,0x448000,0x51009e08,0x2802100,0x962460,0x51009f63,0x4000010,0x400000,0x51009f63,0x6800000,0x1329800,
+0x51009f63,0x7c00100,0x230400,0x51009f63,0x7c00900,0x230400,0x51009f63,0xc000010,0x448000,0x51009f63,0xc000010,0xb48000,0x5100a008,0x2000,0x962460,0x5100a008,
+0x2802400,0x962460,0x5100a008,0x4000000,0x200000,0x5100a008,0x7c00100,0x220400,0x5100a008,0x7c00100,0x230400,0x5100a008,0x7c00100,0x250400,0x5100a008,0x7c00500,
+0x230400,0x5100a16f,0x2806400,0x962460,0x5100a16f,0x6800000,0x1329800,0x5100a16f,0x6800100,0x962540,0x5100a16f,0x7c00100,0x230400,0x5100a16f,0xc000010,0x448000,
+0x5100a24f,0x2802100,0x962460,0x5100a24f,0x2802400,0x962460,0x5100a24f,0x6800000,0x1329800,0x5100a24f,0x7c00100,0x230400,0x5100a24f,0xc000010,0x448000,0x5100a36e,
+0x2802100,0x962460,0x5100a36e,0x4000000,0x200000,0x5100a36e,0x6800100,0x962540,0x5100a36e,0x6804400,0x962540,0x5100a36e,0x7c00100,0x230400,0x5100a442,0x2802100,
+0x962460,0x5100a442,0x4000000,0x200000,0x5100a442,0x6800000,0x1329800,0x5100a442,0x6800100,0x962540,0x5100a442,0x7c00100,0x230400,0x5100a442,0xc000010,0x448000,
+0x5100a500,0x4000000,0x200000,0x5100a600,0x4000000,0x200000,0x5100a601,0x2802000,0x962460,0x5100a76b,0x7c00100,0x230400,0x5100a868,0x7c00100,0x230400,0x5100a96c,
+0x4000000,0x200000,0x5100a96c,0x7c00100,0x230400,0x5100aa00,0x4000000,0xe00000,0x5100ab00,0x4000000,0xe00000,0x51086600,0x24000020,0x810000,0x51086600,0x24000020,
+0x1410000,0x510a4005,0x7c00100,0xe30400,0x510a4711,0x7c40300,0xe30000,0x510a7300,0x24000000,0x200000,0x510aaa00,0x4000000,0xe00000,0x5140a2fe,0x4000400,0x400000,
+0x514a82ca,0x4000000,0xe00000,0x51802bbc,0x2802000,0x962460,0x51c00908,0x2802400,0x962460,0x51c0a008,0x2802400,0x962460,0x52000f0a,0x2802100,0x962460,0x52000f0a,
+0x6800100,0x962540,0x52000f0a,0x7c00100,0x230400,0x52001004,0x4000000,0x1600000,0x52001b00,0x4000000,0x200000,0x52001c1c,0x2802100,0x1862460,0x52001c1c,0x6800100,
+0x1862400,0x52001c1c,0x6800500,0x1862400,0x52001e12,0x7c00100,0x2230500,0x52001e12,0x7c00100,0x2330520,0x52002128,0x4000002,0x400000,0x52002128,0x7c00100,0x230400,
+0x52002a00,0x4000000,0x1500000,0x52002a00,0x4000000,0x1600000,0x52002d00,0x4000000,0x200006,0x52003000,0x24000000,0x200000,0x52006108,0x7c00100,0x220400,0x52006108,
+0x7c00100,0x250400,0x52008301,0x2802400,0x962460,0x52008407,0x2802400,0x962460,0x52008407,0x7c00100,0x220400,0x52008407,0x7c00100,0x250400,0x52008b3b,0x6800000,
+0x1800000,0x52008b3b,0x7c00100,0x1830000,0x52008e00,0x24000000,0x400000,0x52009419,0x7c00100,0x250400,0x5200975b,0x4000000,0x200000,0x5200ac7e,0x2802000,0x962460,
+0x5200ac7e,0x2802100,0x962460,0x5200ac7e,0x2802400,0x962460,0x5200ac7e,0x4000010,0x200000,0x5200ac7e,0x7c00100,0x230400,0x5200ac7e,0xc000010,0x248000,0x5200ad28,
+0x7c00100,0x230400,0x5200ae6a,0x2802100,0x1862460,0x5200ae6a,0x2802400,0x962460,0x5200ae6a,0x2802400,0x1862460,0x5200ae6a,0x2806000,0x1862460,0x5200ae6a,0x4000000,
+0x1800000,0x5200ae6a,0x6800000,0x1329800,0x5200ae6a,0x6800100,0x1862400,0x5200ae6a,0x6800100,0x1862540,0x5200ae6a,0x7c00100,0x1830000,0x5200ae6a,0x7c00900,0x1830000,
+0x5200ae6a,0xc000010,0x1848000,0x5200b083,0x4000010,0x400000,0x5200b083,0x7c00100,0x230400,0x5200b083,0xc000010,0x448000,0x5200b182,0x2802400,0x962460,0x5200b182,
+0x4000000,0x200000,0x5200b182,0x4000010,0x400000,0x5200b182,0x7c00100,0x230400,0x5200b182,0xc000010,0x448000,0x5200b30a,0x2802400,0x962460,0x5200b30a,0x4000000,
+0x200000,0x5200b30a,0x7c00100,0x230400,0x5200b54e,0x2802100,0x962460,0x5200b54e,0x2802400,0x962460,0x5200b54e,0x4000000,0x200000,0x5200b54e,0x4000010,0x400000,
+0x5200b54e,0x6800000,0x1329800,0x5200b54e,0x6800100,0x962540,0x5200b54e,0x6804400,0x962540,0x5200b54e,0x7c00100,0x230400,0x5200b54e,0xc000010,0x448000,0x5200b61c,
+0x4000000,0x1800000,0x5200b61c,0x6800500,0x1862400,0x5200b61c,0x7c00100,0x1830000,0x5200b61c,0x7c00900,0x1830000,0x5200b77f,0x2802100,0x1862460,0x5200b77f,0x2802400,
+0x1862460,0x5200b77f,0x4000000,0x1800000,0x5200b77f,0x4000010,0x1800000,0x5200b77f,0x7c00100,0x1830000,0x5200b77f,0x7c00500,0x1830000,0x5200b77f,0x7c00900,0x1830000,
+0x5200b77f,0x7e00100,0x1830000,0x5200b873,0x2802100,0x962460,0x5200b873,0x2806400,0x962460,0x5200b873,0x6800000,0x1329800,0x5200b873,0x6800100,0x962540,0x5200b873,
+0x6800400,0x962540,0x5200b873,0x7c00100,0x230400,0x5200b873,0xc000010,0x448000,0x5200b912,0x7c00100,0x2230500,0x5200b912,0x7c00100,0x2330520,0x5200ba74,0x4000000,
+0x200000,0x5200ba74,0x4000010,0x400000,0x5200ba74,0x7c00100,0x230400,0x5200bb85,0x4000000,0x200000,0x5200bb85,0x7c00100,0x230400,0x5200bc75,0x4000000,0x400000,
+0x5200bc75,0x4000010,0x400000,0x5200bc75,0x7c00100,0x230400,0x5200bd7d,0x4000000,0x200000,0x5200bd7d,0x7c00100,0x230400,0x5200be7a,0x4000000,0x200000,0x5200be7a,
+0x7c00100,0x230400,0x5200bf58,0x7c00100,0x230400,0x5200c002,0x4000000,0x200000,0x5200c178,0x2802100,0x962460,0x5200c178,0x2802400,0x962460,0x5200c178,0x2806400,
+0x962460,0x5200c178,0x4000000,0x200000,0x5200c178,0x6800100,0x962540,0x5200c178,0x7c00100,0x230400,0x5200c178,0x7c00100,0x230401,0x5200c178,0xc000010,0x448000,
+0x5200c178,0x80000000,0x218960,0x5200c247,0x7c00100,0x230400,0x5200c247,0x7c00100,0x830400,0x5200c247,0x7c00100,0x1430400,0x5200c300,0x4000000,0x200003,0x52022d00,
+0x4000000,0x100006,0x52023700,0x24000000,0x100000,0x52023700,0x24000000,0xe00000,0x52023700,0x24000000,0x2800000,0x52024400,0x4000000,0x100000,0x52027300,0x24000000,
+0x100000,0x5202c300,0x4000000,0x100000,0x5202c300,0x4000000,0x100002,0x5202c300,0x4000000,0x100003,0x5202c300,0x4000000,0x10000d,0x5202c300,0x4000100,0x150400,
+0x5202c300,0x4000100,0x15040d,0x520a1e12,0x7c00100,0x2130480,0x520a3700,0x24000000,0xe00000,0x520a3800,0x24000000,0x100000,0x520a4711,0x7c40300,0xe30000,0x520a4f11,
+0x7c00300,0xe30001,0x520a7300,0x24000000,0x100000,0x520ab412,0x7c00100,0x2130480,0x520ac400,0x4000000,0xe00002,0x520ac400,0x4000000,0xe0000d,0x520ac414,0x4000000,
+0xe0000d,0x520ac511,0x7c40300,0xe30000,0x5240af9c,0x7c00100,0x230400,0x5240afa1,0x4000400,0x200000,0x5240afa3,0x6800400,0x962540,0x5240afa3,0x7c00100,0x230400,
+0x5240afad,0x7c00100,0x230400,0x5240afaf,0x7c00100,0x230400,0x5240b2d2,0x4000000,0x200000,0x5240b2d2,0x4000000,0x1500000,0x5240b2dd,0x4000000,0x200000,0x5240b2eb,
+0x4000000,0x200000,0x524a44ca,0x4000000,0xe00003,0x5250b501,0x7c00900,0x230400,0x5280af9c,0x2802400,0x962460,0x5280af9d,0x2802400,0x962460,0x5280afa3,0x2802400,
+0x962460,0x5280afa5,0x2802400,0x962460,0x5280afa7,0x2802400,0x962460,0x52c0b3f8,0x2802400,0x962460,0x52c0b3fc,0x7c00100,0x230400,0x60000c02,0x2802100,0x962460,
+0x60000c02,0x7c00100,0x230400,0x60000f0a,0x2802100,0x962460,0x60000f0a,0x6800100,0x962540,0x60000f0a,0x7c00100,0x230400,0x6000131f,0x4000000,0x200000,0x6000171a,
+0x7c00100,0x230400,0x6000171a,0x7c00100,0x230560,0x60001b27,0x2802100,0x962460,0x60001b27,0x4000000,0xc00000,0x60001b27,0x7c00100,0x230400,0x60001f0b,0x2802400,
+0x962460,0x60002919,0x7c00100,0x22040e,0x60002a00,0x4000000,0x1600000,0x60003000,0x24000000,0x200000,0x60003000,0x24000000,0xe00000,0x60003700,0x24000000,0x200000,
+0x60003800,0x24000000,0x1710000,0x60005102,0x4000000,0x200000,0x60006108,0x7c00100,0x220400,0x60006108,0x7c00100,0x250400,0x60006600,0x24000020,0x200000,0x60008301,
+0x2802400,0xc62460,0x6000903c,0x2806000,0x962460,0x6000903c,0x4000000,0x400000,0x60009519,0x7c00100,0x220400,0x60009519,0x7c00100,0x250400,0x6000a008,0x7c00100,
+0x220400,0x6000a008,0x7c00100,0x250400,0x6000c300,0x4000000,0x2703580,0x6000c654,0x2802000,0x962460,0x6000c654,0x4000010,0x200000,0x6000c654,0x7c00100,0x230400,
+0x6000c73f,0x2802000,0x962460,0x6000c73f,0x2802100,0x962460,0x6000c73f,0x4000000,0x200000,0x6000c73f,0x6800100,0x962540,0x6000c73f,0x6804000,0x962540,0x6000c73f,
+0x7c00100,0x230400,0x6000c80b,0x7c00100,0x230400,0x6000c941,0x2802100,0x962460,0x6000c941,0x2806400,0x962460,0x6000c941,0x4000000,0x200000,0x6000c941,0x4000010,
+0x200000,0x6000c941,0x6800000,0x1329800,0x6000c941,0x6800100,0x962540,0x6000c941,0x7c00100,0x230400,0x6000c941,0xc000010,0x448000,0x6000ca82,0x7c00100,0x230400,
+0x6000cc00,0x4000000,0xe00000,0x6000d000,0x4000000,0x200000,0x6002c300,0x4000000,0x100000,0x6002c300,0x4000000,0x10000d,0x6002c300,0x4000100,0x150400,0x6002c300,
+0x4000100,0x15040d,0x600a3000,0x24000000,0x200000,0x600a3000,0x24000000,0xe00000,0x600a3700,0x24000000,0x200000,0x600a3800,0x24000000,0x200000,0x600a3800,0x24000000,
+0x2800000,0x600a4305,0x7c00100,0xe30400,0x600ac300,0x4000000,0x100000,0x600ac400,0x4000000,0xe0000d,0x600acb14,0x7c00100,0xe30000,0x600acb16,0x7c00100,0xe30c00,
+0x600acc00,0x4000000,0xe00000,0x600acd00,0x4000000,0x200000,0x600acd00,0x4000000,0xe00000,0x600acd00,0x4000000,0x2800000,0x600ace00,0x4000000,0xe00000,0x600ace00,
+0x4000000,0x2800000,0x600acf00,0x4000000,0xe00000,0x600acf00,0x4000000,0x2800000,0x600ad111,0x7c40300,0xe30000,0x604ac4ca,0x4000000,0xe00003,0x61000a03,0x4000000,
+0x1600000,0x61000c02,0x80000000,0x218960,0x6100120f,0x4000000,0x200000,0x61001a18,0x7c00100,0x1830000,0x61001d0c,0x7c00100,0x230400,0x61001d0c,0x7c00100,0x250400,
+0x61006600,0x24000020,0x200000,0x61008407,0x7c00100,0x220400,0x61008407,0x7c00100,0x250400,0x6100870c,0x7c00100,0x220400,0x61008e00,0x24000000,0x200000,0x61008e00,
+0x24000000,0x400000,0x61008e00,0x24000002,0x300000,0x6100903c,0x7c00100,0x230400,0x61009519,0x7c00100,0x220400,0x61009519,0x7c00100,0x250400,0x61009519,0x7c00500,
+0x22040f,0x61009b71,0x2802100,0x962460,0x61009b71,0x2806400,0x962460,0x61009b71,0x7c00100,0x230400,0x6100a008,0x2802100,0x962460,0x6100c300,0x4000000,0x20000f,
+0x6100cd00,0x4000000,0x200000,0x6100d202,0x2802400,0x962460,0x6100d202,0x2802500,0x962460,0x6100d202,0x7c00100,0x230400,0x6100d302,0x4000020,0x200000,0x6100d302,
+0x7c00120,0x230405,0x6100d476,0x2802100,0x962460,0x6100d476,0x2802100,0x962461,0x6100d476,0x2806400,0x962460,0x6100d476,0x4000000,0x400000,0x6100d476,0x6800000,
+0x1329800,0x6100d476,0x6800100,0x962540,0x6100d476,0x7c00100,0x230400,0x6100d476,0xc000010,0x448000,0x6100d573,0x2802100,0x962460,0x6100d573,0x2806400,0x962460,
+0x6100d573,0x6800100,0x962540,0x6100d573,0x7c00100,0x230400,0x6100d573,0x7c00900,0x230400,0x6100d573,0xc000010,0x448000,0x6100d68d,0x7c00100,0x230400,0x6100d756,
+0x7c00100,0x230400,0x6100d85c,0x2802500,0x962460,0x6100d85c,0x6800100,0x962540,0x6100d85c,0x7c00100,0x230400,0x6100d85c,0x7c00500,0x230400,0x6100d997,0x2802100,
+0x962460,0x6100d997,0x4000000,0x200000,0x6100d997,0x4000000,0x400000,0x6100d997,0x6800000,0x1329800,0x6100d997,0x6800100,0x962540,0x6100d997,0x6804400,0x962540,
+0x6100d997,0x7c00100,0x230400,0x6100d997,0x7c00100,0x230560,0x6100d997,0xc000010,0x448000,0x6100da98,0x6800000,0x1329800,0x6100da98,0x7c00100,0x230400,0x6100db71,
+0x4000000,0x200000,0x6100dc99,0x2802100,0x962460,0x6100dc99,0x2802400,0x962460,0x6100dc99,0x6800000,0x1329800,0x6100dc99,0x6800100,0x962540,0x6100dc99,0x6804400,
+0x962540,0x6100dc99,0x7c00100,0x230400,0x610a4711,0x7c40300,0xe30000,0x610a4f11,0x7c00300,0xe30001,0x610ace00,0x4000000,0xe00000,0x6140afa1,0x7c00100,0x230400,
+0x6140afa3,0x7c00100,0x230400,0x6180af9e,0x2802400,0x962460,0x62002a00,0x4000000,0x1600000,0x63002800,0x80000,0x918820,0x63c00c15,0x80000,0x918820,0x7000080e,
+0x7c00100,0x250400,0x70000a03,0x4000000,0x200000,0x70000c00,0x80000000,0x218960,0x70000f0a,0x7c00100,0x230400,0x70001004,0x7c00100,0x230400,0x70001524,0x2802100,
+0x962460,0x70001524,0x7c00100,0x230400,0x70001615,0x2802100,0x962460,0x7000171a,0x2802100,0x962460,0x70001821,0x6800000,0x1329800,0x70002320,0x7c00100,0x230400,
+0x70002a00,0x4000000,0x1500000,0x70002a00,0x4000000,0x1600000,0x70003000,0x24000000,0x200000,0x70003800,0x24000000,0xe00000,0x70005201,0x2802400,0x962460,0x7000581e,
+0x7c00100,0x230400,0x70006108,0x7c00100,0x220400,0x70006108,0x7c00100,0x250400,0x70006f30,0x7c00100,0x230400,0x70007300,0x24000000,0x200000,0x70007f0e,0x4000000,
+0x200000,0x70008301,0x2802100,0x962460,0x70008301,0x2802400,0x962460,0x70008e00,0x24000000,0x200000,0x70008e00,0x24000000,0x400000,0x70008e00,0x24000002,0x400000,
+0x70008e00,0x24000008,0x1410000,0x70008e00,0x24000010,0x400000,0x70008e00,0x2c000010,0x448000,0x70009519,0x7c00100,0x220400,0x70009519,0x7c00100,0x230400,0x70009519,
+0x7c00100,0x250400,0x70009865,0x7c00100,0x230400,0x70009965,0x4000010,0x400000,0x70009965,0x7c00100,0x230400,0x7000a008,0x7c00100,0x220400,0x7000a008,0x7c00100,
+0x250400,0x7000a008,0x7c00500,0x22040f,0x7000a50e,0x4000000,0x200000,0x7000b61c,0x2802500,0x1862460,0x7000b61c,0x6800500,0x1862400,0x7000b61c,0x7c00100,0x1830000,
+0x7000c300,0x4000000,0x100000,0x7000c941,0x2806000,0x962460,0x7000cc00,0x4000000,0xe00000,0x7000cd00,0x4000000,0x200000,0x7000cd00,0x4000000,0xe00000,0x7000cd00,
+0x4000000,0x2800000,0x7000cf00,0x4000000,0xe00000,0x7000d202,0x2802100,0x962460,0x7000d202,0x7c00100,0x230400,0x7000d997,0x7c00100,0x230400,0x7000d997,0xc000010,
+0x248000,0x7000dd86,0x2802400,0x962460,0x7000dd86,0x7c00100,0x230400,0x7000dd86,0xc000010,0x448000,0x7000de9f,0x4000000,0x200000,0x7000de9f,0x7c00100,0x230400,
+0x7000e001,0x2400,0x962460,0x7000e001,0x2802400,0x962460,0x7000e187,0x2802000,0x962460,0x7000e187,0x2802100,0x962460,0x7000e187,0x4000000,0x200000,0x7000e187,
+0x7c00100,0x230400,0x7000e187,0xc000010,0x448000,0x7000e288,0x7c00100,0x230400,0x7000e300,0x4000000,0x200000,0x7000e489,0x2802100,0x962460,0x7000e489,0x2802400,
+0x962460,0x7000e489,0x6800100,0x962540,0x7000e489,0x6800100,0x962541,0x7000e489,0x6804400,0x962540,0x7000e489,0x7c00100,0x230400,0x7000e489,0x7c00900,0x230400,
+0x7000e59d,0x2802100,0x962460,0x7000e59d,0x2802400,0x962460,0x7000e59d,0x4000000,0x200000,0x7000e59d,0x4000010,0x200000,0x7000e59d,0x6800100,0x962540,0x7000e59d,
+0x6804400,0x962540,0x7000e59d,0x7c00100,0x230400,0x7000e59d,0xc000010,0x448000,0x7000e691,0x2802100,0x962460,0x7000e691,0x2802400,0x962460,0x7000e691,0x2806400,
+0x962460,0x7000e691,0x6800000,0x1329800,0x7000e691,0x6800100,0x962540,0x7000e691,0x7c00100,0x230400,0x7000e700,0x4000400,0x200400,0x7000e70e,0x7c00100,0x220400,
+0x7000e719,0x7c00100,0x220400,0x7000e719,0x7c00500,0x22040f,0x7000e853,0x7c00100,0x230400,0x7000e9a0,0x2802400,0x962460,0x7000e9a0,0x4000000,0x200000,0x7000e9a0,
+0x4000000,0x500000,0x7000e9a0,0x7c00100,0x230400,0x7000ea79,0x2802400,0x962460,0x7000ea79,0x4000000,0x200000,0x7000ea79,0x4000000,0xf00000,0x7000ea79,0x4000010,
+0x400000,0x7000ea79,0x7c00100,0x230400,0x7000eb8c,0x2802400,0x962460,0x7000eb8c,0x4000000,0x200000,0x7000eb8c,0x7c00100,0x230400,0x7000eca3,0x2802100,0x962460,
+0x7000eca3,0x2806400,0x962460,0x7000eca3,0x4000000,0x200000,0x7000eca3,0x6800000,0x1329800,0x7000eca3,0x6800100,0x962540,0x7000eca3,0x7c00100,0x230400,0x7000eca3,
+0xc000010,0x448000,0x7000ed95,0x6800000,0x1329800,0x7000ed95,0x7c00100,0x230400,0x7000ed95,0xc000010,0x448000,0x7000ee1c,0x2802500,0x1862460,0x7000ee1c,0x6800000,
+0x1329800,0x7000ee1c,0x7c00100,0x1830000,0x7000ee1c,0x7c00900,0x1830000,0x7000ef8f,0x4000000,0x200000,0x7000ef8f,0x7c00100,0x230400,0x7000f08e,0x4000000,0x200000,
+0x7000f08e,0x7c00100,0x230400,0x7000f159,0x2802100,0x962460,0x7000f159,0x7c00100,0x230400,0x7000f200,0x4000000,0x200000,0x7000f200,0x4000000,0x1200000,0x7000f200,
+0x4000000,0x1710000,0x7000f34b,0x2802400,0x962460,0x7000f34b,0x4000000,0x200000,0x7000f34b,0x4000010,0x400000,0x7000f34b,0x6800000,0x1329800,0x7000f34b,0x7c00100,
+0x230400,0x7000f34b,0x7c00900,0x230400,0x7000f34b,0xc000010,0x448000,0x7000f490,0x4000000,0x200000,0x7000f490,0x7c00100,0x230400,0x7000f5a5,0x7c00100,0x230400,
+0x7000f67b,0x4000000,0x200000,0x7000f67b,0x4000010,0x200000,0x7000f67b,0x7c00100,0x230400,0x7000f8a6,0x2802100,0x962460,0x7000f8a6,0x2802400,0x962460,0x7000f8a6,
+0x2806400,0x962460,0x7000f8a6,0x4000000,0x500000,0x7000f8a6,0x4000010,0xb00000,0x7000f8a6,0x4000800,0x200000,0x7000f8a6,0x6800100,0x962540,0x7000f8a6,0x6800100,
+0x962541,0x7000f8a6,0x7c00100,0x230400,0x7000f8a6,0xc000010,0x448000,0x7000f921,0x4000000,0x200000,0x7000fa00,0x4000000,0x200000,0x7000fb9e,0x2802100,0x962460,
+0x7000fb9e,0x2802400,0x962460,0x7000fb9e,0x2806400,0x962460,0x7000fb9e,0x4000000,0x200000,0x7000fb9e,0x6800000,0x1329800,0x7000fb9e,0x6800100,0x962540,0x7000fb9e,
+0x6800100,0x962541,0x7000fb9e,0x7c00100,0x230400,0x7000fc92,0x4000000,0x200000,0x7000fc92,0x6800000,0x1329800,0x7000fc92,0x7c00100,0x220400,0x7000fc92,0x7c00100,
+0x230400,0x7000fc92,0x7c00100,0x250400,0x700acd00,0x4000000,0xe00000,0x700acd00,0x4000000,0x2800000,0x700ace00,0x4000000,0xe00000,0x700acf00,0x4000000,0xe00000,
+0x700acf00,0x4000000,0x2800000,0x7050df11,0x4000000,0x200000,0x7050f719,0x80000,0x918820,0x7080afa1,0x2802400,0x962460,0x7090df11,0x2802400,0x962460,0x70d0e417,
+0x2802100,0x962460,0x70d0e417,0x2802400,0x962460,0x70d0e417,0x6800100,0x962540,0x70d0ea15,0x4000010,0x400000,0x8000120f,0x7c00100,0x230400,0x80001524,0x7c00100,
+0x230400,0x8000171a,0x7c00100,0x230400,0x80002006,0x7c00100,0x220400,0x80002006,0x7c00100,0x250400,0x80002a00,0x4000000,0x1500000,0x80002d00,0x4000000,0x200000,
+0x80005208,0x2802400,0x962460,0x80005c00,0x4000000,0x200000,0x80007300,0x24000000,0x200000,0x80009519,0x7c00100,0x220400,0x80009519,0x7c00100,0x230400,0x80009519,
+0x7c00100,0x250400,0x80009865,0x7c00100,0x230400,0x8000a008,0x2802100,0x962460,0x8000b30a,0x4000000,0x500000,0x8000b30a,0x7c00100,0x230400,0x8000cd00,0x4000000,
+0xe00000,0x8000d202,0x2802500,0x962460,0x8000d202,0x7c00100,0x230400,0x8000d68d,0x4000000,0x200000,0x8000d997,0x2802000,0x962460,0x8000d997,0x2802400,0x962460,
+0x8000d997,0x4000000,0x400000,0x8000d997,0x4000000,0x500000,0x8000d997,0x7c00100,0x230400,0x8000d997,0xc000010,0x448000,0x8000e489,0x2802100,0x962460,0x8000e489,
+0x7c00100,0x230400,0x8000e719,0x7c00100,0x220400,0x8000f8a6,0x2802100,0x962460,0x8000f8a6,0x7c00100,0x230400,0x8000f8a6,0xc000010,0x448000,0x8000fda1,0x2802100,
+0x1862460,0x8000fda1,0x2806400,0x1862460,0x8000fda1,0x4000000,0x1800000,0x8000fda1,0x6800000,0x1329800,0x8000fda1,0x6800100,0x1862400,0x8000fda1,0x6800100,0x1862540,
+0x8000fda1,0x7c00100,0x1830000,0x8000fda1,0xc000010,0x448000,0x8000fe9c,0x7c00100,0x230400,0x8000fe9c,0x7c00100,0x830400,0x8000fe9c,0x7c00100,0x1430400,0x8000ff06,
+0x7c00100,0x220400,0x80010165,0x7c00100,0x230400,0x800102a2,0x4000000,0x200000,0x800102a2,0x7c00100,0x230400,0x800103a4,0x7c00100,0x230400,0x800103a4,0xc000010,
+0x448000,0x8001044c,0x4000000,0x200000,0x8001044c,0x7c00100,0x220400,0x8001044c,0x7c00100,0x250400,0x80010670,0x2802000,0x962460,0x80010670,0x4000000,0x200000,
+0x80010670,0x4000010,0x400000,0x80010670,0xc000010,0x448000,0x800a4711,0x7c40300,0xe30000,0x800acd00,0x4000000,0xe00000,0x800acd00,0x4000000,0x2902460,0x800ace00,
+0x4000000,0xe00000,0x800acf00,0x4000000,0xe00000,0x800b0011,0x7c40300,0xe30000,0x800b0500,0x4000000,0xe00000,0x800b0500,0x4000000,0x2800000,0x90001615,0x7c00100,
+0x230400,0x9000171a,0x4000000,0x200000,0x9000171a,0x7c00100,0x230400,0x90003000,0x24000000,0x200000,0x90007f0e,0x4000000,0x200000,0x90008301,0x2802400,0x962460,
+0x90008e00,0x24000000,0x400000,0x90009519,0x7c00100,0x250400,0x9000a16f,0x2802100,0x962460,0x9000d200,0x80000000,0x218960,0x9000d202,0x2802000,0x962460,0x9000d202,
+0x2802100,0x962460,0x9000d202,0x7c00100,0x230400,0x9000e59d,0x2802100,0x962460,0x90010500,0x4000000,0xe00000,0x900107a7,0x2802100,0x962460,0x900107a7,0x2802400,
+0x962460,0x900107a7,0x2802c00,0x962460,0x900107a7,0x4000000,0x1400000,0x900107a7,0x6800000,0x1329800,0x900107a7,0x7c00100,0x220400,0x900107a7,0x7c00100,0x250400,
+0x900108a8,0x2802100,0x962460,0x900108a8,0x2806400,0x962460,0x900108a8,0x4000000,0x200000,0x900108a8,0x4000000,0x400000,0x900108a8,0x4000010,0x400000,0x900108a8,
+0x6800000,0x1329800,0x900108a8,0x6800100,0x962540,0x900108a8,0x7c00100,0x230400,0x900108a8,0xc000010,0x448000,0x90010908,0x7c00100,0x220400,0x90010a38,0x2802100,
+0x962460,0x90010ca9,0x2802100,0x962460,0x90010ca9,0x4000000,0x500000,0x90010ca9,0x4000010,0xb00000,0x90010ca9,0x6800100,0x962540,0x90010ca9,0x7c00100,0x230400,
+0x90010d1b,0x4000000,0x500000,0x90010eaa,0x2802100,0x962460,0x90010eaa,0x2802400,0x962460,0x90010eaa,0x2806400,0x962460,0x90010eaa,0x4000000,0x200000,0x90010eaa,
+0x4000000,0x400000,0x90010eaa,0x4000010,0x400000,0x90010eaa,0x6800000,0x1329800,0x90010eaa,0x6800100,0x962540,0x90010eaa,0x7c00100,0x230400,0x90010eaa,0xc000010,
+0x448000,0x90010fab,0x7c00100,0x220400,0x90010fab,0x7c00100,0x250400,0x9002c300,0x4000000,0x100000,0x900ac400,0x4000000,0xe0000d,0x900acd00,0x4000000,0xe00000,
+0x900acd00,0x4000000,0x2800000,0x900acf00,0x4000000,0xe00000,0x900b0500,0x4000000,0xe00000,0x900b0500,0x4000000,0x2800000,0x900b0b9a,0x7c00900,0x1230400,0x900b109a,
+0x7c00300,0xe30000,0x900b119a,0x7c00300,0xe30000,0x90408e06,0x24000000,0x400000,0xa0001004,0x4000000,0x200000,0xa0001004,0x7c00100,0x230400,0xa000120f,0x2802100,
+0x962460,0xa000120f,0x2802400,0x962460,0xa000171a,0x2802100,0x962460,0xa000171a,0x2806400,0x962460,0xa0002a00,0x4000000,0x1600000,0xa0003000,0x24000000,0x200000,
+0xa000581e,0x7c00100,0x230400,0xa0007300,0x24000000,0x200000,0xa0008301,0x2802400,0x962460,0xa0008e00,0x24000000,0x400000,0xa000cf00,0x4000000,0xe00000,0xa0010500,
+0x4000000,0x200000,0xa00114af,0x2802100,0x962460,0xa00114af,0x2802400,0x962460,0xa00114af,0x2806400,0x962460,0xa00114af,0x6800000,0x1329800,0xa00114af,0x7c00100,
+0x230400,0xa00114af,0x7c00100,0x230560,0xa00116b0,0x2802100,0x962460,0xa00116b0,0x2802800,0x962460,0xa00116b0,0x2806400,0x962460,0xa00116b0,0x4000000,0x400000,
+0xa00116b0,0x4000000,0x500000,0xa00116b0,0x4000010,0x400000,0xa00116b0,0x6800100,0x962540,0xa00116b0,0x7c00100,0x230400,0xa00116b0,0x7c00100,0x230560,0xa00116b0,
+0xc000010,0x448000,0xa0011722,0x7c00100,0x230400,0xa00118b1,0x2802000,0x962460,0xa00118b1,0x2802100,0x962460,0xa00118b1,0x2806400,0x962460,0xa00118b1,0x4000000,
+0x200000,0xa00118b1,0x4000000,0x400000,0xa00118b1,0x4000000,0x500000,0xa00118b1,0x6800100,0x962540,0xa00118b1,0x7c00100,0x230400,0xa00118b1,0x7c00100,0x230560,
+0xa00118b1,0xc000010,0x448000,0xa00a4005,0x7c00100,0xe30400,0xa00a4711,0x7c40300,0xe30000,0xa00ac400,0x4000000,0xe00000,0xa00acb14,0x7c00100,0xe30000,0xa00acf00,
+0x4000000,0xe00000,0xa00b0500,0x4000000,0xe00000,0xa00b0500,0x4000000,0x2800000,0xa00b0b96,0x7c00900,0x1230400,0xa00b1211,0x7c40300,0xe30000,0xa00b1314,0x7c00100,
+0xe30000,0xa00b1596,0x7c00300,0xe30000,0xa040afb7,0x6800400,0x962540,0xa08083b8,0x2802400,0x962460,0xb0000a03,0x7c00100,0x220400,0xb0000b13,0x7c00100,0x2633800,
+0xb0001004,0x2802000,0x962460,0xb0001110,0x4000000,0x200000,0xb0001524,0x2802100,0x962460,0xb0001615,0x4000000,0x500000,0xb000251b,0x7c00100,0x230400,0xb0007300,
+0x24000000,0x200000,0xb0008939,0x4000000,0x200000,0xb0008939,0x7c00100,0x230400,0xb0008e00,0x24000000,0x200000,0xb0008e00,0x24000000,0x400000,0xb0008e00,0x24000010,
+0x400000,0xb0009257,0x2802000,0x962460,0xb0009257,0x4000000,0x1600000,0xb0009519,0x7c00100,0x220400,0xb0009519,0x7c00100,0x250400,0xb0009a00,0x4000000,0x200000,
+0xb000b30a,0x2802100,0x962460,0xb000b30a,0x7c00100,0x230400,0xb000c178,0x80000000,0x218960,0xb000c300,0x4000000,0x200000,0xb000d202,0x2802000,0x962460,0xb000d476,
+0x6800100,0x962540,0xb000d476,0x7c00100,0x230400,0xb000e300,0x4000000,0xe00000,0xb000fda1,0x7c00100,0x1830000,0xb0010eaa,0x2802000,0x962460,0xb00116b0,0x7c00100,
+0x230400,0xb0011900,0x4000000,0xe00000,0xb0011ab2,0x2802100,0x962460,0xb0011ab2,0x2802400,0x962460,0xb0011ab2,0x2806400,0x962460,0xb0011ab2,0x4000000,0x200000,
+0xb0011ab2,0x6800100,0x962540,0xb0011ab2,0x7c00100,0x230400,0xb0011b0c,0x7c00100,0x230400,0xb0011cb3,0x2802100,0x962460,0xb0011cb3,0x2806400,0x962460,0xb0011cb3,
+0x6800000,0x1329800,0xb0011cb3,0x6800100,0x962540,0xb0011cb3,0x7c00100,0x230400,0xb0011db6,0x2802500,0x962460,0xb0011db6,0x6800000,0x1329800,0xb0011db6,0x7c00100,
+0x230400,0xb0011db6,0x7c00500,0x230400,0xb0011e00,0x4000000,0x200000,0xb0011e00,0x4000000,0x1500000,0xb0011fb4,0x2802100,0x962460,0xb0011fb4,0x6800100,0x962540,
+0xb0011fb4,0x7c00100,0x230400,0xb0011fb4,0xc000010,0x248000,0xb0012000,0x4000000,0x200000,0xb00121b5,0x4000000,0x200000,0xb00121b5,0x4000010,0x400000,0xb00121b5,
+0x7c00100,0x220400,0xb00121b5,0x7c00100,0x250400,0xb00121b5,0xc000010,0x448000,0xb00122b8,0x4000000,0x200000,0xb00122b8,0x7c00100,0x230400,0xb00123b7,0x2802400,
+0x962460,0xb00123b7,0x4000000,0x200000,0xb00123b7,0x7c00100,0x230400,0xb00123b7,0xc000010,0x248000,0xb00a4005,0x7c00100,0xe30400,0xb00a4711,0x7c40300,0xe30000,
+0xb00acf00,0x4000000,0xe00000,0xb00b0500,0x4000000,0xe00000,0xb00b0500,0x4000000,0x2800000,0xb00b109a,0x7c00300,0xe30000,0xb080e487,0x2802000,0x962460,0xc0001524,
+0x4000000,0x500000,0xc0001a18,0x2806400,0x1862460,0xc0001a18,0x7c00100,0x1830000,0xc0007300,0x24000000,0x200000,0xc0008e00,0x24000010,0x400000,0xc0009519,0x7c00100,
+0x220400,0xc0009519,0x7c00100,0x250400,0xc000c300,0x4000000,0x20000f,0xc000d85c,0x2802100,0x962460,0xc000d85c,0x6800100,0x962540,0xc000d85c,0x7c00100,0x230400,
+0xc000dc99,0x7c00100,0x230400,0xc000e719,0x7c00100,0x220400,0xc00107a7,0x7c00100,0x230400,0xc0010eaa,0x7c00100,0x230400,0xc00116b0,0x7c00100,0x230560,0xc0011900,
+0x4000000,0x200000,0xc0012447,0,0x818820,0xc0012447,0,0xc18820,0xc0012447,0,0x1418820,0xc00125b9,0x7c00100,0x230400,0xc00126bb,0x2802100,
+0x962460,0xc00126bb,0x2806400,0x962460,0xc00126bb,0x4000000,0x500000,0xc00126bb,0x6800100,0x962540,0xc00126bb,0x7c00100,0x230400,0xc00127ba,0x2802400,0x962460,
+0xc00127ba,0x4000000,0x200000,0xc00127ba,0x6800000,0x1329800,0xc00127ba,0x7c00100,0x230400,0xc00127ba,0x7c00900,0x230400,0xc0012800,0x4000000,0x200000,0xc0012b23,
+0x4000000,0x200000,0xc0012b23,0x4000000,0x400000,0xc0012b23,0x4000000,0x1500000,0xc0012cbc,0x2802400,0x962460,0xc0012cbc,0x4000000,0x1600000,0xc0012cbc,0x6800000,
+0x1329800,0xc0012cbc,0x7c00100,0x230400,0xc00acf00,0x4000000,0xe00000,0xc00ae300,0x4000000,0xe00000,0xc00b0500,0x4000000,0xe00000,0xc00b0500,0x4000000,0x2800000,
+0xc00b0b11,0x4000000,0x1200000,0xc00b0b11,0x7c00900,0x1230400,0xc00b109a,0x7c00300,0xe30000,0xc00b2914,0x7c00100,0x2530000,0xc00b2916,0x7c00100,0x2530c00,0xc00b2a00,
+0x4000000,0xe00000,0xc040af5e,0x7c00100,0x230400,0xc0c12b89,0x4000000,0x200000,0xc14a44ca,0x4000000,0xe0000d,0xd000131f,0x2802c00,0x962460,0xd000171a,0x7c00100,
+0x230400,0xd0001821,0x2802100,0x962460,0xd0007300,0x24000000,0x200000,0xd0008e00,0x24000000,0x200000,0xd0008f3a,0x2806000,0x962460,0xd0009519,0x7c00100,0x220400,
+0xd0009519,0x7c00100,0x250400,0xd000a500,0x4000000,0x200000,0xd000c300,0x4000000,0xe00000,0xd000d202,0x7c00100,0x230400,0xd000d476,0x7c00100,0x230400,0xd000d997,
+0x2802100,0x962460,0xd000d997,0x6800100,0x962540,0xd000e001,0x2802100,0x962460,0xd000e700,0x4000400,0x200000,0xd000e719,0x7c00100,0x220400,0xd000e719,0x7c00500,
+0x22040f,0xd000fa00,0x4000000,0xe00000,0xd0010eaa,0x4000010,0x400000,0xd0010eaa,0x7c00100,0x230400,0xd0012dbd,0x4000000,0x200000,0xd0012dbd,0x7c00100,0x230400,
+0xd0012fbe,0x2802100,0x962460,0xd0012fbe,0x2802400,0x962460,0xd0012fbe,0x2806400,0x962460,0xd0012fbe,0x4000000,0x400000,0xd0012fbe,0x6800000,0x1329800,0xd0012fbe,
+0x6800100,0x962540,0xd0012fbe,0x6800100,0x962541,0xd0012fbe,0x6804400,0x962540,0xd0012fbe,0x7c00100,0x230400,0xd0012fbe,0x7c00100,0x230560,0xd0012fbe,0xc000010,
+0x448000,0xd0013183,0x7c00100,0x230400,0xd0013200,0x4000000,0x200000,0xd0013200,0x6800000,0x1329805,0xd00134c0,0x2802100,0x962460,0xd00134c0,0x4000002,0x400000,
+0xd00134c0,0x7c00100,0x230400,0xd00a4305,0x7c00100,0xe30400,0xd00a4611,0x7c40300,0xe30000,0xd00a4711,0x7c40300,0xe30000,0xd00a5e11,0x7c40300,0xe30000,0xd00acf00,
+0x4000000,0xe00000,0xd00b0500,0x4000000,0xe00000,0xd00b0500,0x4000000,0x2800000,0xd00b0b11,0x6800500,0x962540,0xd00b0bbf,0x2802200,0xc62460,0xd00b119a,0x7c00300,
+0xe30000,0xd00b2a00,0x4000000,0xe00000,0xd00b2e11,0x7c40300,0xe30000,0xd00b30bf,0x7c00300,0x230000,0xd00b339a,0x7c00300,0xe30000,0xe0000c02,0xc000010,0xb48000,
+0xe0001524,0x2802400,0x962460,0xe0001524,0x7c00100,0x230400,0xe0001615,0x7c00100,0x230400,0xe000251b,0x12882000,0x962460,0xe0002a00,0x4000000,0x1500000,0xe0005102,
+0x4000000,0x200000,0xe0005c00,0x4000000,0x200000,0xe000622a,0x6804400,0x962540,0xe000622a,0x7c00100,0x230400,0xe0008838,0x7c00100,0x220400,0xe0008838,0x7c00100,
+0x250400,0xe0008e00,0x24000000,0x810000,0xe0008e00,0x24000000,0x1410000,0xe0008e00,0x24000002,0x400000,0xe0008e00,0x2c000010,0xb48000,0xe000933e,0x7c00100,0x230400,
+0xe000933e,0xc000010,0x448000,0xe0009519,0x7c00100,0x220400,0xe0009519,0x7c00100,0x22040f,0xe0009519,0x7c00100,0x250400,0xe000c178,0x2802100,0x962460,0xe000c941,
+0x2802100,0x962460,0xe000c941,0x2806400,0x962460,0xe000c941,0x7c00100,0x230400,0xe000d202,0x2802400,0x962460,0xe000d202,0x7c00100,0x230400,0xe000d202,0x7c00500,
+0x230400,0xe000dc99,0x4000000,0x200000,0xe000e001,0x2802100,0x962460,0xe000e001,0x2802400,0x962460,0xe000fda1,0x7c00100,0x1830000,0xe0013502,0x2802400,0x962460,
+0xe0013502,0x4000000,0x200000,0xe0013502,0x7c00100,0x230400,0xe0013502,0x80000000,0x218960,0xe00136c1,0x4000000,0x200000,0xe00136c1,0x7c00100,0x230400,0xe001370b,
+0x7c00100,0x230400,0xe0013919,0x7c00500,0x220400,0xe0013919,0x7c00500,0x22040f,0xe0013919,0x7c00d00,0x23040f,0xe0013a19,0x7c00100,0x220400,0xe0013a19,0x7c00100,
+0x230400,0xe0013bc2,0x2802400,0x962460,0xe0013bc2,0x7c00100,0x230400,0xe0013bc2,0xc000010,0x248000,0xe0013cc3,0x6800000,0x1329800,0xe0013cc3,0x7c00100,0x230400,
+0xe0013dc4,0x2802400,0x962460,0xe0013dc4,0x7c00100,0x230400,0xe0013e28,0x7c00100,0x230400,0xe0013fc5,0x7c00100,0x220400,0xe0013fc5,0x7c00100,0x250400,0xe0014000,
+0x4000000,0x200000,0xe0014001,0x2802400,0x962460,0xe00a4711,0x7c40300,0xe30000,0xe00a5e11,0x7c40300,0xe30000,0xe00ac511,0x7c40300,0xe30000,0xe00acf00,0x4000000,
+0xe00000,0xe00ae300,0x4000000,0xe00000,0xe00b0500,0x4000000,0xe00000,0xe00b1314,0x7c00100,0xe30000,0xe00b1316,0x7c00100,0xe30c00,0xe00b2a00,0x4000000,0xe00000,
+0xe00b2a00,0x4000000,0x2800000,0xe00b3816,0x7c00500,0x230c00,0xe0808328,0x2802400,0x962460,0xf0001615,0x6800100,0x962540,0xf0001a18,0x2802000,0x1862460,0xf000c247,
+0x7c00100,0x230400,0xf000d000,0x4000000,0xe00000,0xf000e300,0x4000000,0xe00000,0xf000e59d,0x2802100,0x962460,0xf000e59d,0x7c00100,0x230400,0xf0012447,0,
+0x818820,0xf0012447,0,0xc18820,0xf0012447,0,0x1418820,0xf0012447,0x2802000,0x962460,0xf0012447,0x2802400,0x962460,0xf0012447,0x7c00100,0x230400,
+0xf0013a19,0x7c00100,0x220400,0xf0014102,0x2802400,0x962460,0xf0014308,0x2802100,0x962460,0xf0014308,0x7c00500,0x22040e,0xf0014308,0x7c00500,0x22040f,0xf001440a,
+0x4000000,0x500000,0xf0014500,0x4000000,0x200000,0xf00146c6,0x2802100,0x962460,0xf00146c6,0x2806000,0x962460,0xf00146c6,0x4000000,0xe00000,0xf00146c6,0x6800000,
+0x1329800,0xf00146c6,0x6800100,0x962540,0xf00146c6,0x6804000,0x962540,0xf00146c6,0x7c00100,0x230400,0xf00146c6,0x7c00100,0x230560,0xf00146c6,0xc000010,0x448000,
+0xf00147c7,0x2802000,0x962460,0xf00147c7,0x6800000,0x1329800,0xf00147c7,0x7c00100,0x230400,0xf00ac511,0x7c40300,0xe30000,0xf00acf00,0x4000000,0xe00000,0xf00b2914,
+0x7c00100,0x2530000,0xf00b2916,0x7c00100,0x2530c00,0xf00b2a00,0x4000000,0xe00000,0xf00b2a00,0x4000000,0x2800000,0xf00b4211,0x7c40300,0xe30000};
-static const int32_t countPropsVectors=7095;
+static const int32_t countPropsVectors=7230;
static const int32_t propsVectorsColumns=3;
static const uint16_t scriptExtensions[282]={
0x800e,0x8019,8,0x8059,8,2,8,0x8038,8,6,8,0x8019,2,0x22,0x25,0x57,
@@ -3937,6 +4006,6 @@ static const uint16_t scriptExtensions[282]={
0x804f,0x37,0x804e,2,0x8057,2,0x8025,2,0x105,0x2f,0x31,0x8053,0x2f,0x31,0x80c1,0x2f,
0x8031,2,0x8007,0x79,0x80c2,0x79,0x113,0x89,0x87,0x8087};
-static const int32_t indexes[UPROPS_INDEX_COUNT]={0x2c64,0x2c64,0x2c64,0x2c64,0x6b06,3,0x86bd,0x874a,0x874a,0x874a,0xb40c5,0x2a75a31,0,0,0,0};
+static const int32_t indexes[UPROPS_INDEX_COUNT]={0x2d08,0x2d08,0x2d08,0x2d08,0x6ce6,3,0x8924,0x89b1,0x89b1,0x89b1,0xb47c7,0x2a75a31,0,0,0,0};
#endif // INCLUDED_FROM_UCHAR_C
diff --git a/thirdparty/icu4c/common/ucharstrie.cpp b/thirdparty/icu4c/common/ucharstrie.cpp
index e0b33af519..24ab425777 100644
--- a/thirdparty/icu4c/common/ucharstrie.cpp
+++ b/thirdparty/icu4c/common/ucharstrie.cpp
@@ -308,13 +308,13 @@ UCharsTrie::findUniqueValueFromBranch(const UChar *pos, int32_t length,
}
} else {
uniqueValue=value;
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
} else {
if(!findUniqueValue(pos+value, haveUniqueValue, uniqueValue)) {
return NULL;
}
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
} while(--length>1);
return pos+1; // ignore the last comparison unit
@@ -330,9 +330,9 @@ UCharsTrie::findUniqueValue(const UChar *pos, UBool haveUniqueValue, int32_t &un
}
pos=findUniqueValueFromBranch(pos, node+1, haveUniqueValue, uniqueValue);
if(pos==NULL) {
- return FALSE;
+ return false;
}
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
node=*pos++;
} else if(node<kMinValueLead) {
// linear-match node
@@ -348,14 +348,14 @@ UCharsTrie::findUniqueValue(const UChar *pos, UBool haveUniqueValue, int32_t &un
}
if(haveUniqueValue) {
if(value!=uniqueValue) {
- return FALSE;
+ return false;
}
} else {
uniqueValue=value;
- haveUniqueValue=TRUE;
+ haveUniqueValue=true;
}
if(isFinal) {
- return TRUE;
+ return true;
}
pos=skipNodeValue(pos, node);
node&=kNodeTypeMask;
diff --git a/thirdparty/icu4c/common/ucharstriebuilder.cpp b/thirdparty/icu4c/common/ucharstriebuilder.cpp
index 3871df6c27..be3260941e 100644
--- a/thirdparty/icu4c/common/ucharstriebuilder.cpp
+++ b/thirdparty/icu4c/common/ucharstriebuilder.cpp
@@ -163,7 +163,7 @@ UCharsTrieBuilder::buildUnicodeString(UStringTrieBuildOption buildOption, Unicod
UErrorCode &errorCode) {
buildUChars(buildOption, errorCode);
if(U_SUCCESS(errorCode)) {
- result.setTo(FALSE, uchars+(ucharsCapacity-ucharsLength), ucharsLength);
+ result.setTo(false, uchars+(ucharsCapacity-ucharsLength), ucharsLength);
}
return result;
}
@@ -188,7 +188,7 @@ UCharsTrieBuilder::buildUChars(UStringTrieBuildOption buildOption, UErrorCode &e
}
uprv_sortArray(elements, elementsLength, (int32_t)sizeof(UCharsTrieElement),
compareElementStrings, &strings,
- FALSE, // need not be a stable sort
+ false, // need not be a stable sort
&errorCode);
if(U_FAILURE(errorCode)) {
return;
@@ -322,7 +322,7 @@ UCharsTrieBuilder::createLinearMatchNode(int32_t i, int32_t unitIndex, int32_t l
UBool
UCharsTrieBuilder::ensureCapacity(int32_t length) {
if(uchars==NULL) {
- return FALSE; // previous memory allocation had failed
+ return false; // previous memory allocation had failed
}
if(length>ucharsCapacity) {
int32_t newCapacity=ucharsCapacity;
@@ -335,7 +335,7 @@ UCharsTrieBuilder::ensureCapacity(int32_t length) {
uprv_free(uchars);
uchars=NULL;
ucharsCapacity=0;
- return FALSE;
+ return false;
}
u_memcpy(newUChars+(newCapacity-ucharsLength),
uchars+(ucharsCapacity-ucharsLength), ucharsLength);
@@ -343,7 +343,7 @@ UCharsTrieBuilder::ensureCapacity(int32_t length) {
uchars=newUChars;
ucharsCapacity=newCapacity;
}
- return TRUE;
+ return true;
}
int32_t
diff --git a/thirdparty/icu4c/common/ucharstrieiterator.cpp b/thirdparty/icu4c/common/ucharstrieiterator.cpp
index b3132241fe..2ba43692dd 100644
--- a/thirdparty/icu4c/common/ucharstrieiterator.cpp
+++ b/thirdparty/icu4c/common/ucharstrieiterator.cpp
@@ -26,7 +26,7 @@ UCharsTrie::Iterator::Iterator(ConstChar16Ptr trieUChars, int32_t maxStringLengt
: uchars_(trieUChars),
pos_(uchars_), initialPos_(uchars_),
remainingMatchLength_(-1), initialRemainingMatchLength_(-1),
- skipValue_(FALSE),
+ skipValue_(false),
maxLength_(maxStringLength), value_(0), stack_(NULL) {
if(U_FAILURE(errorCode)) {
return;
@@ -48,7 +48,7 @@ UCharsTrie::Iterator::Iterator(const UCharsTrie &trie, int32_t maxStringLength,
: uchars_(trie.uchars_), pos_(trie.pos_), initialPos_(trie.pos_),
remainingMatchLength_(trie.remainingMatchLength_),
initialRemainingMatchLength_(trie.remainingMatchLength_),
- skipValue_(FALSE),
+ skipValue_(false),
maxLength_(maxStringLength), value_(0), stack_(NULL) {
if(U_FAILURE(errorCode)) {
return;
@@ -82,7 +82,7 @@ UCharsTrie::Iterator &
UCharsTrie::Iterator::reset() {
pos_=initialPos_;
remainingMatchLength_=initialRemainingMatchLength_;
- skipValue_=FALSE;
+ skipValue_=false;
int32_t length=remainingMatchLength_+1; // Remaining match length.
if(maxLength_>0 && length>maxLength_) {
length=maxLength_;
@@ -100,12 +100,12 @@ UCharsTrie::Iterator::hasNext() const { return pos_!=NULL || !stack_->isEmpty();
UBool
UCharsTrie::Iterator::next(UErrorCode &errorCode) {
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
const UChar *pos=pos_;
if(pos==NULL) {
if(stack_->isEmpty()) {
- return FALSE;
+ return false;
}
// Pop the state off the stack and continue with the next outbound edge of
// the branch node.
@@ -118,7 +118,7 @@ UCharsTrie::Iterator::next(UErrorCode &errorCode) {
if(length>1) {
pos=branchNext(pos, length, errorCode);
if(pos==NULL) {
- return TRUE; // Reached a final value.
+ return true; // Reached a final value.
}
} else {
str_.append(*pos++);
@@ -135,7 +135,7 @@ UCharsTrie::Iterator::next(UErrorCode &errorCode) {
if(skipValue_) {
pos=skipNodeValue(pos, node);
node&=kNodeTypeMask;
- skipValue_=FALSE;
+ skipValue_=false;
} else {
// Deliver value for the string so far.
UBool isFinal=(UBool)(node>>15);
@@ -152,9 +152,9 @@ UCharsTrie::Iterator::next(UErrorCode &errorCode) {
// next time.
// Instead, keep pos_ on the node lead unit itself.
pos_=pos-1;
- skipValue_=TRUE;
+ skipValue_=true;
}
- return TRUE;
+ return true;
}
}
if(maxLength_>0 && str_.length()==maxLength_) {
@@ -166,7 +166,7 @@ UCharsTrie::Iterator::next(UErrorCode &errorCode) {
}
pos=branchNext(pos, node+1, errorCode);
if(pos==NULL) {
- return TRUE; // Reached a final value.
+ return true; // Reached a final value.
}
} else {
// Linear-match node, append length units to str_.
diff --git a/thirdparty/icu4c/common/uchriter.cpp b/thirdparty/icu4c/common/uchriter.cpp
index 2967375a6a..f2a9953841 100644
--- a/thirdparty/icu4c/common/uchriter.cpp
+++ b/thirdparty/icu4c/common/uchriter.cpp
@@ -171,7 +171,7 @@ UCharCharacterIterator::nextPostInc() {
UBool
UCharCharacterIterator::hasNext() {
- return (UBool)(pos < end ? TRUE : FALSE);
+ return (UBool)(pos < end ? true : false);
}
UChar
@@ -185,7 +185,7 @@ UCharCharacterIterator::previous() {
UBool
UCharCharacterIterator::hasPrevious() {
- return (UBool)(pos > begin ? TRUE : FALSE);
+ return (UBool)(pos > begin ? true : false);
}
UChar32
diff --git a/thirdparty/icu4c/common/ucln_cmn.cpp b/thirdparty/icu4c/common/ucln_cmn.cpp
index f3e07c6b89..ea797d1344 100644
--- a/thirdparty/icu4c/common/ucln_cmn.cpp
+++ b/thirdparty/icu4c/common/ucln_cmn.cpp
@@ -120,5 +120,5 @@ U_CFUNC UBool ucln_lib_cleanup(void) {
#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
ucln_unRegisterAutomaticCleanup();
#endif
- return TRUE;
+ return true;
}
diff --git a/thirdparty/icu4c/common/ucnv.cpp b/thirdparty/icu4c/common/ucnv.cpp
index 019bcb6a79..26baa550c3 100644
--- a/thirdparty/icu4c/common/ucnv.cpp
+++ b/thirdparty/icu4c/common/ucnv.cpp
@@ -163,7 +163,7 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
UErrorCode cbErr;
UConverterToUnicodeArgs toUArgs = {
sizeof(UConverterToUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -173,7 +173,7 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
};
UConverterFromUnicodeArgs fromUArgs = {
sizeof(UConverterFromUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -269,7 +269,7 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
/* Copy initial state */
uprv_memcpy(localConverter, cnv, sizeof(UConverter));
- localConverter->isCopyLocal = localConverter->isExtraLocal = FALSE;
+ localConverter->isCopyLocal = localConverter->isExtraLocal = false;
/* copy the substitution string */
if (cnv->subChars == (uint8_t *)cnv->subUChars) {
@@ -306,7 +306,7 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
if(localConverter == (UConverter*)stackBuffer) {
/* we're using user provided data - set to not destroy */
- localConverter->isCopyLocal = TRUE;
+ localConverter->isCopyLocal = true;
}
/* allow callback functions to handle any memory allocation */
@@ -352,7 +352,7 @@ ucnv_close (UConverter * converter)
if (converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
UConverterToUnicodeArgs toUArgs = {
sizeof(UConverterToUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -368,7 +368,7 @@ ucnv_close (UConverter * converter)
if (converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
UConverterFromUnicodeArgs fromUArgs = {
sizeof(UConverterFromUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -580,7 +580,7 @@ static void _reset(UConverter *converter, UConverterResetChoice choice,
if(choice<=UCNV_RESET_TO_UNICODE && converter->fromCharErrorBehaviour != UCNV_TO_U_DEFAULT_CALLBACK) {
UConverterToUnicodeArgs toUArgs = {
sizeof(UConverterToUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -595,7 +595,7 @@ static void _reset(UConverter *converter, UConverterResetChoice choice,
if(choice!=UCNV_RESET_TO_UNICODE && converter->fromUCharErrorBehaviour != UCNV_FROM_U_DEFAULT_CALLBACK) {
UConverterFromUnicodeArgs fromUArgs = {
sizeof(UConverterFromUnicodeArgs),
- TRUE,
+ true,
NULL,
NULL,
NULL,
@@ -634,19 +634,19 @@ static void _reset(UConverter *converter, UConverterResetChoice choice,
U_CAPI void U_EXPORT2
ucnv_reset(UConverter *converter)
{
- _reset(converter, UCNV_RESET_BOTH, TRUE);
+ _reset(converter, UCNV_RESET_BOTH, true);
}
U_CAPI void U_EXPORT2
ucnv_resetToUnicode(UConverter *converter)
{
- _reset(converter, UCNV_RESET_TO_UNICODE, TRUE);
+ _reset(converter, UCNV_RESET_TO_UNICODE, true);
}
U_CAPI void U_EXPORT2
ucnv_resetFromUnicode(UConverter *converter)
{
- _reset(converter, UCNV_RESET_FROM_UNICODE, TRUE);
+ _reset(converter, UCNV_RESET_FROM_UNICODE, true);
}
U_CAPI int8_t U_EXPORT2
@@ -871,7 +871,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
/* avoid compiler warnings - not otherwise necessary, and the values do not matter */
realSourceLimit=NULL;
- realFlush=FALSE;
+ realFlush=false;
realSourceIndex=0;
} else {
/*
@@ -887,7 +887,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
pArgs->source=replay;
pArgs->sourceLimit=replay-cnv->preFromULength;
- pArgs->flush=FALSE;
+ pArgs->flush=false;
sourceIndex=-1;
cnv->preFromULength=0;
@@ -923,11 +923,11 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
cnv->fromUChar32==0);
} else {
/* handle error from ucnv_convertEx() */
- converterSawEndOfInput=FALSE;
+ converterSawEndOfInput=false;
}
/* no callback called yet for this iteration */
- calledCallback=FALSE;
+ calledCallback=false;
/* no sourceIndex adjustment for conversion, only for callback output */
errorInputLength=0;
@@ -976,7 +976,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
uprv_memcpy(replay, cnv->preFromU, -cnv->preFromULength*U_SIZEOF_UCHAR);
pArgs->source=replay;
pArgs->sourceLimit=replay-cnv->preFromULength;
- pArgs->flush=FALSE;
+ pArgs->flush=false;
if((sourceIndex+=cnv->preFromULength)<0) {
sourceIndex=-1;
}
@@ -1017,7 +1017,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
/* inject an error and continue with callback handling */
*err=U_TRUNCATED_CHAR_FOUND;
- calledCallback=FALSE; /* new error condition */
+ calledCallback=false; /* new error condition */
} else {
/* input consumed */
if(pArgs->flush) {
@@ -1033,7 +1033,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
}
/* reset the converter without calling the callback function */
- _reset(cnv, UCNV_RESET_FROM_UNICODE, FALSE);
+ _reset(cnv, UCNV_RESET_FROM_UNICODE, false);
}
/* done successfully */
@@ -1110,7 +1110,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
* that a callback was called;
* if the callback did not resolve the error, then we return
*/
- calledCallback=TRUE;
+ calledCallback=true;
}
}
}
@@ -1118,7 +1118,7 @@ _fromUnicodeWithCallback(UConverterFromUnicodeArgs *pArgs, UErrorCode *err) {
/*
* Output the fromUnicode overflow buffer.
* Call this function if(cnv->charErrorBufferLength>0).
- * @return TRUE if overflow
+ * @return true if overflow
*/
static UBool
ucnv_outputOverflowFromUnicode(UConverter *cnv,
@@ -1154,7 +1154,7 @@ ucnv_outputOverflowFromUnicode(UConverter *cnv,
*pOffsets=offsets;
}
*err=U_BUFFER_OVERFLOW_ERROR;
- return TRUE;
+ return true;
}
/* copy the overflow contents to the target */
@@ -1170,7 +1170,7 @@ ucnv_outputOverflowFromUnicode(UConverter *cnv,
if(offsets!=NULL) {
*pOffsets=offsets;
}
- return FALSE;
+ return false;
}
U_CAPI void U_EXPORT2
@@ -1316,7 +1316,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
/* avoid compiler warnings - not otherwise necessary, and the values do not matter */
realSourceLimit=NULL;
- realFlush=FALSE;
+ realFlush=false;
realSourceIndex=0;
} else {
/*
@@ -1332,7 +1332,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
pArgs->source=replay;
pArgs->sourceLimit=replay-cnv->preToULength;
- pArgs->flush=FALSE;
+ pArgs->flush=false;
sourceIndex=-1;
cnv->preToULength=0;
@@ -1368,11 +1368,11 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
cnv->toULength==0);
} else {
/* handle error from getNextUChar() or ucnv_convertEx() */
- converterSawEndOfInput=FALSE;
+ converterSawEndOfInput=false;
}
/* no callback called yet for this iteration */
- calledCallback=FALSE;
+ calledCallback=false;
/* no sourceIndex adjustment for conversion, only for callback output */
errorInputLength=0;
@@ -1421,7 +1421,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
uprv_memcpy(replay, cnv->preToU, -cnv->preToULength);
pArgs->source=replay;
pArgs->sourceLimit=replay-cnv->preToULength;
- pArgs->flush=FALSE;
+ pArgs->flush=false;
if((sourceIndex+=cnv->preToULength)<0) {
sourceIndex=-1;
}
@@ -1462,7 +1462,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
/* inject an error and continue with callback handling */
*err=U_TRUNCATED_CHAR_FOUND;
- calledCallback=FALSE; /* new error condition */
+ calledCallback=false; /* new error condition */
} else {
/* input consumed */
if(pArgs->flush) {
@@ -1478,7 +1478,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
}
/* reset the converter without calling the callback function */
- _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
+ _reset(cnv, UCNV_RESET_TO_UNICODE, false);
}
/* done successfully */
@@ -1556,7 +1556,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
* that a callback was called;
* if the callback did not resolve the error, then we return
*/
- calledCallback=TRUE;
+ calledCallback=true;
}
}
}
@@ -1564,7 +1564,7 @@ _toUnicodeWithCallback(UConverterToUnicodeArgs *pArgs, UErrorCode *err) {
/*
* Output the toUnicode overflow buffer.
* Call this function if(cnv->UCharErrorBufferLength>0).
- * @return TRUE if overflow
+ * @return true if overflow
*/
static UBool
ucnv_outputOverflowToUnicode(UConverter *cnv,
@@ -1600,7 +1600,7 @@ ucnv_outputOverflowToUnicode(UConverter *cnv,
*pOffsets=offsets;
}
*err=U_BUFFER_OVERFLOW_ERROR;
- return TRUE;
+ return true;
}
/* copy the overflow contents to the target */
@@ -1616,7 +1616,7 @@ ucnv_outputOverflowToUnicode(UConverter *cnv,
if(offsets!=NULL) {
*pOffsets=offsets;
}
- return FALSE;
+ return false;
}
U_CAPI void U_EXPORT2
@@ -1754,7 +1754,7 @@ ucnv_fromUChars(UConverter *cnv,
destLimit=dest+destCapacity;
/* perform the conversion */
- ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+ ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, pErrorCode);
destLength=(int32_t)(dest-originalDest);
/* if an overflow occurs, then get the preflighting length */
@@ -1765,7 +1765,7 @@ ucnv_fromUChars(UConverter *cnv,
do {
dest=buffer;
*pErrorCode=U_ZERO_ERROR;
- ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+ ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, pErrorCode);
destLength+=(int32_t)(dest-buffer);
} while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
}
@@ -1810,7 +1810,7 @@ ucnv_toUChars(UConverter *cnv,
destLimit=dest+destCapacity;
/* perform the conversion */
- ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+ ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, pErrorCode);
destLength=(int32_t)(dest-originalDest);
/* if an overflow occurs, then get the preflighting length */
@@ -1822,7 +1822,7 @@ ucnv_toUChars(UConverter *cnv,
do {
dest=buffer;
*pErrorCode=U_ZERO_ERROR;
- ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, pErrorCode);
+ ucnv_toUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, pErrorCode);
destLength+=(int32_t)(dest-buffer);
}
while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
@@ -1907,15 +1907,15 @@ ucnv_getNextUChar(UConverter *cnv,
}
/*
- * flush==TRUE is implied for ucnv_getNextUChar()
+ * flush==true is implied for ucnv_getNextUChar()
*
* do not simply return even if s==sourceLimit because the converter may
- * not have seen flush==TRUE before
+ * not have seen flush==true before
*/
/* prepare the converter arguments */
args.converter=cnv;
- args.flush=TRUE;
+ args.flush=true;
args.offsets=NULL;
args.source=s;
args.sourceLimit=sourceLimit;
@@ -1937,7 +1937,7 @@ ucnv_getNextUChar(UConverter *cnv,
*source=s=args.source;
if(*err==U_INDEX_OUTOFBOUNDS_ERROR) {
/* reset the converter without calling the callback function */
- _reset(cnv, UCNV_RESET_TO_UNICODE, FALSE);
+ _reset(cnv, UCNV_RESET_TO_UNICODE, false);
return 0xffff; /* no output */
} else if(U_SUCCESS(*err) && c>=0) {
return c;
@@ -2176,7 +2176,7 @@ ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
/* prepare the converter arguments */
fromUArgs.converter=targetCnv;
- fromUArgs.flush=FALSE;
+ fromUArgs.flush=false;
fromUArgs.offsets=NULL;
fromUArgs.target=*target;
fromUArgs.targetLimit=targetLimit;
@@ -2331,8 +2331,8 @@ ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
/* input consumed */
if(flush) {
/* reset the converters without calling the callback functions */
- _reset(sourceCnv, UCNV_RESET_TO_UNICODE, FALSE);
- _reset(targetCnv, UCNV_RESET_FROM_UNICODE, FALSE);
+ _reset(sourceCnv, UCNV_RESET_TO_UNICODE, false);
+ _reset(targetCnv, UCNV_RESET_FROM_UNICODE, false);
}
/* done successfully */
@@ -2372,7 +2372,7 @@ ucnv_convertEx(UConverter *targetCnv, UConverter *sourceCnv,
sourceCnv->preToULength>=0 &&
sourceCnv->UCharErrorBufferLength==0
) {
- fromUArgs.flush=TRUE;
+ fromUArgs.flush=true;
}
}
@@ -2436,8 +2436,8 @@ ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
&myTarget, targetLimit,
&source, sourceLimit,
pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
- FALSE,
- TRUE,
+ false,
+ true,
pErrorCode);
targetLength=(int32_t)(myTarget-target);
}
@@ -2459,8 +2459,8 @@ ucnv_internalConvert(UConverter *outConverter, UConverter *inConverter,
&myTarget, targetLimit,
&source, sourceLimit,
pivotBuffer, &pivot, &pivot2, pivotBuffer+CHUNK_SIZE,
- FALSE,
- TRUE,
+ false,
+ true,
pErrorCode);
targetLength+=(int32_t)(myTarget-targetBuffer);
} while(*pErrorCode==U_BUFFER_OVERFLOW_ERROR);
@@ -2585,7 +2585,7 @@ ucnv_toAlgorithmic(UConverterType algorithmicType,
char *target, int32_t targetCapacity,
const char *source, int32_t sourceLength,
UErrorCode *pErrorCode) {
- return ucnv_convertAlgorithmic(TRUE, algorithmicType, cnv,
+ return ucnv_convertAlgorithmic(true, algorithmicType, cnv,
target, targetCapacity,
source, sourceLength,
pErrorCode);
@@ -2597,7 +2597,7 @@ ucnv_fromAlgorithmic(UConverter *cnv,
char *target, int32_t targetCapacity,
const char *source, int32_t sourceLength,
UErrorCode *pErrorCode) {
- return ucnv_convertAlgorithmic(FALSE, algorithmicType, cnv,
+ return ucnv_convertAlgorithmic(false, algorithmicType, cnv,
target, targetCapacity,
source, sourceLength,
pErrorCode);
@@ -2885,12 +2885,12 @@ ucnv_toUCountPending(const UConverter* cnv, UErrorCode* status){
U_CAPI UBool U_EXPORT2
ucnv_isFixedWidth(UConverter *cnv, UErrorCode *status){
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
if (cnv == NULL) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
switch (ucnv_getType(cnv)) {
@@ -2900,9 +2900,9 @@ ucnv_isFixedWidth(UConverter *cnv, UErrorCode *status){
case UCNV_UTF32_LittleEndian:
case UCNV_UTF32:
case UCNV_US_ASCII:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
#endif
diff --git a/thirdparty/icu4c/common/ucnv2022.cpp b/thirdparty/icu4c/common/ucnv2022.cpp
index aa1e169c99..ec096780e9 100644
--- a/thirdparty/icu4c/common/ucnv2022.cpp
+++ b/thirdparty/icu4c/common/ucnv2022.cpp
@@ -491,7 +491,7 @@ _ISO2022Open(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode){
uprv_memset(myConverterData, 0, sizeof(UConverterDataISO2022));
myConverterData->currentType = ASCII1;
- cnv->fromUnicodeStatus =FALSE;
+ cnv->fromUnicodeStatus =false;
if(pArgs->locale){
uprv_strncpy(myLocale, pArgs->locale, sizeof(myLocale)-1);
}
@@ -623,7 +623,7 @@ _ISO2022Open(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode){
#endif // !UCONFIG_ONLY_HTML_CONVERSION
else{
#ifdef U_ENABLE_GENERIC_ISO_2022
- myConverterData->isFirstBuffer = TRUE;
+ myConverterData->isFirstBuffer = true;
/* append the UTF-8 escape sequence */
cnv->charErrorBufferLength = 3;
@@ -682,7 +682,7 @@ _ISO2022Reset(UConverter *converter, UConverterResetChoice choice) {
if(choice<=UCNV_RESET_TO_UNICODE) {
uprv_memset(&myConverterData->toU2022State, 0, sizeof(ISO2022State));
myConverterData->key = 0;
- myConverterData->isEmptySegment = FALSE;
+ myConverterData->isEmptySegment = false;
}
if(choice!=UCNV_RESET_TO_UNICODE) {
uprv_memset(&myConverterData->fromU2022State, 0, sizeof(ISO2022State));
@@ -690,7 +690,7 @@ _ISO2022Reset(UConverter *converter, UConverterResetChoice choice) {
#ifdef U_ENABLE_GENERIC_ISO_2022
if(myConverterData->locale[0] == 0){
if(choice<=UCNV_RESET_TO_UNICODE) {
- myConverterData->isFirstBuffer = TRUE;
+ myConverterData->isFirstBuffer = true;
myConverterData->key = 0;
if (converter->mode == UCNV_SO){
ucnv_close (myConverterData->currentConverter);
@@ -1285,7 +1285,7 @@ T_UConverter_toUnicode_ISO_2022_OFFSETS_LOGIC(UConverterToUnicodeArgs* args,
}
/* convert to before the ESC or until the end of the buffer */
- myData->isFirstBuffer=FALSE;
+ myData->isFirstBuffer=false;
sourceStart = args->source;
myTargetStart = args->target;
args->converter = myData->currentConverter;
@@ -1848,7 +1848,7 @@ getTrail:
len = 1;
cs = cs0;
g = 0;
- useFallback = FALSE;
+ useFallback = false;
}
break;
case JISX208:
@@ -1864,7 +1864,7 @@ getTrail:
len = len2;
cs = cs0;
g = 0;
- useFallback = FALSE;
+ useFallback = false;
}
} else if(len == 0 && useFallback &&
(uint32_t)(sourceChar - HWKANA_START) <= (HWKANA_END - HWKANA_START)) {
@@ -1872,7 +1872,7 @@ getTrail:
len = -2;
cs = cs0;
g = 0;
- useFallback = FALSE;
+ useFallback = false;
}
break;
case ISO8859_7:
@@ -1886,7 +1886,7 @@ getTrail:
len = len2;
cs = cs0;
g = 2;
- useFallback = FALSE;
+ useFallback = false;
}
break;
default:
@@ -1911,7 +1911,7 @@ getTrail:
len = len2;
cs = cs0;
g = 0;
- useFallback = FALSE;
+ useFallback = false;
}
break;
}
@@ -2121,7 +2121,7 @@ UConverter_toUnicode_ISO_2022_JP_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
continue;
} else {
/* only JIS7 uses SI/SO, not ISO-2022-JP-x */
- myData->isEmptySegment = FALSE; /* reset this, we have a different error */
+ myData->isEmptySegment = false; /* reset this, we have a different error */
break;
}
@@ -2133,7 +2133,7 @@ UConverter_toUnicode_ISO_2022_JP_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
continue;
} else {
/* only JIS7 uses SI/SO, not ISO-2022-JP-x */
- myData->isEmptySegment = FALSE; /* reset this, we have a different error */
+ myData->isEmptySegment = false; /* reset this, we have a different error */
break;
}
@@ -2159,12 +2159,12 @@ escape:
if(U_FAILURE(*err)){
args->target = myTarget;
args->source = mySource;
- myData->isEmptySegment = FALSE; /* Reset to avoid future spurious errors */
+ myData->isEmptySegment = false; /* Reset to avoid future spurious errors */
return;
}
/* If we successfully completed an escape sequence, we begin a new segment, empty so far */
if(myData->key==0) {
- myData->isEmptySegment = TRUE;
+ myData->isEmptySegment = true;
}
continue;
@@ -2181,7 +2181,7 @@ escape:
U_FALLTHROUGH;
default:
/* convert one or two bytes */
- myData->isEmptySegment = FALSE;
+ myData->isEmptySegment = false;
cs = (StateEnum)pToU2022State->cs[pToU2022State->g];
if( (uint8_t)(mySourceChar - 0xa1) <= (0xdf - 0xa1) && myData->version==4 &&
!IS_JP_DBCS(cs)
@@ -2262,7 +2262,7 @@ getTrailByte:
tempBuf[0] = (char)(tmpSourceChar >> 8);
tempBuf[1] = (char)(tmpSourceChar);
}
- targetUniChar = ucnv_MBCSSimpleGetNextUChar(myData->myConverterArray[cs], tempBuf, 2, FALSE);
+ targetUniChar = ucnv_MBCSSimpleGetNextUChar(myData->myConverterArray[cs], tempBuf, 2, false);
} else if (!(trailIsOk || IS_2022_CONTROL(trailByte))) {
/* report a pair of illegal bytes if the second byte is not a DBCS starter */
++mySource;
@@ -2534,7 +2534,7 @@ getTrail:
int32_t sourceIndex;
/* we are switching to ASCII */
- isTargetByteDBCS=FALSE;
+ isTargetByteDBCS=false;
/* get the source index of the last input character */
/*
@@ -2712,7 +2712,7 @@ UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
if(mySourceChar==UCNV_SI){
myData->toU2022State.g = 0;
if (myData->isEmptySegment) {
- myData->isEmptySegment = FALSE; /* we are handling it, reset to avoid future spurious errors */
+ myData->isEmptySegment = false; /* we are handling it, reset to avoid future spurious errors */
*err = U_ILLEGAL_ESCAPE_SEQUENCE;
args->converter->toUCallbackReason = UCNV_IRREGULAR;
args->converter->toUBytes[0] = (uint8_t)mySourceChar;
@@ -2725,13 +2725,13 @@ UConverter_toUnicode_ISO_2022_KR_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
continue;
}else if(mySourceChar==UCNV_SO){
myData->toU2022State.g = 1;
- myData->isEmptySegment = TRUE; /* Begin a new segment, empty so far */
+ myData->isEmptySegment = true; /* Begin a new segment, empty so far */
/*consume the source */
continue;
}else if(mySourceChar==ESC_2022){
mySource--;
escape:
- myData->isEmptySegment = FALSE; /* Any invalid ESC sequences will be detected separately, so just reset this */
+ myData->isEmptySegment = false; /* Any invalid ESC sequences will be detected separately, so just reset this */
changeState_2022(args->converter,&(mySource),
mySourceLimit, ISO_2022_KR, err);
if(U_FAILURE(*err)){
@@ -2742,7 +2742,7 @@ escape:
continue;
}
- myData->isEmptySegment = FALSE; /* Any invalid char errors will be detected separately, so just reset this */
+ myData->isEmptySegment = false; /* Any invalid char errors will be detected separately, so just reset this */
if(myData->toU2022State.g == 1) {
if(mySource < mySourceLimit) {
int leadIsOk, trailIsOk;
@@ -3092,7 +3092,7 @@ getTrail:
len = 2;
} else {
len = -2;
- useFallback = FALSE;
+ useFallback = false;
}
if(cs == CNS_11643_1) {
g = 1;
@@ -3119,7 +3119,7 @@ getTrail:
len = len2;
cs = cs0;
g = 1;
- useFallback = FALSE;
+ useFallback = false;
}
}
}
@@ -3301,7 +3301,7 @@ UConverter_toUnicode_ISO_2022_CN_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
case UCNV_SI:
pToU2022State->g=0;
if (myData->isEmptySegment) {
- myData->isEmptySegment = FALSE; /* we are handling it, reset to avoid future spurious errors */
+ myData->isEmptySegment = false; /* we are handling it, reset to avoid future spurious errors */
*err = U_ILLEGAL_ESCAPE_SEQUENCE;
args->converter->toUCallbackReason = UCNV_IRREGULAR;
args->converter->toUBytes[0] = static_cast<uint8_t>(mySourceChar);
@@ -3315,11 +3315,11 @@ UConverter_toUnicode_ISO_2022_CN_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
case UCNV_SO:
if(pToU2022State->cs[1] != 0) {
pToU2022State->g=1;
- myData->isEmptySegment = TRUE; /* Begin a new segment, empty so far */
+ myData->isEmptySegment = true; /* Begin a new segment, empty so far */
continue;
} else {
/* illegal to have SO before a matching designator */
- myData->isEmptySegment = FALSE; /* Handling a different error, reset this to avoid future spurious errs */
+ myData->isEmptySegment = false; /* Handling a different error, reset this to avoid future spurious errs */
break;
}
@@ -3345,7 +3345,7 @@ escape:
if(U_FAILURE(*err)){
args->target = myTarget;
args->source = mySource;
- myData->isEmptySegment = FALSE; /* Reset to avoid future spurious errors */
+ myData->isEmptySegment = false; /* Reset to avoid future spurious errors */
return;
}
continue;
@@ -3358,7 +3358,7 @@ escape:
U_FALLTHROUGH;
default:
/* convert one or two bytes */
- myData->isEmptySegment = FALSE;
+ myData->isEmptySegment = false;
if(pToU2022State->g != 0) {
if(mySource < mySourceLimit) {
UConverterSharedData *cnv;
@@ -3397,7 +3397,7 @@ getTrailByte:
tempBuf[1] = (char) trailByte;
tempBufLen = 2;
}
- targetUniChar = ucnv_MBCSSimpleGetNextUChar(cnv, tempBuf, tempBufLen, FALSE);
+ targetUniChar = ucnv_MBCSSimpleGetNextUChar(cnv, tempBuf, tempBufLen, false);
mySourceChar = (mySourceChar << 8) | trailByte;
} else if (!(trailIsOk || IS_2022_CONTROL(trailByte))) {
/* report a pair of illegal bytes if the second byte is not a DBCS starter */
@@ -3609,7 +3609,7 @@ _ISO_2022_SafeClone(
uprv_memcpy(&localClone->mydata, cnvData, sizeof(UConverterDataISO2022));
localClone->cnv.extraInfo = &localClone->mydata; /* set pointer to extra data */
- localClone->cnv.isExtraLocal = TRUE;
+ localClone->cnv.isExtraLocal = true;
/* share the subconverters */
@@ -3808,8 +3808,8 @@ static const UConverterStaticData _ISO2022StaticData={
3, /* max 3 bytes per UChar from UTF-8 (4 bytes from surrogate _pair_) */
{ 0x1a, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -3853,8 +3853,8 @@ static const UConverterStaticData _ISO2022JPStaticData={
6, /* max 6 bytes per UChar: 4-byte escape sequence + DBCS */
{ 0x1a, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -3904,8 +3904,8 @@ static const UConverterStaticData _ISO2022KRStaticData={
8, /* max 8 bytes per UChar */
{ 0x1a, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -3955,8 +3955,8 @@ static const UConverterStaticData _ISO2022CNStaticData={
8, /* max 8 bytes per UChar: 4-byte CNS designator + 2 bytes for SS2/SS3 + DBCS */
{ 0x1a, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnv_bld.cpp b/thirdparty/icu4c/common/ucnv_bld.cpp
index d08eec7369..a0fbfe2d7f 100644
--- a/thirdparty/icu4c/common/ucnv_bld.cpp
+++ b/thirdparty/icu4c/common/ucnv_bld.cpp
@@ -200,7 +200,7 @@ static icu::UMutex cnvCacheMutex;
static const char **gAvailableConverters = NULL;
static uint16_t gAvailableConverterCount = 0;
-static icu::UInitOnce gAvailableConvertersInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gAvailableConvertersInitOnce {};
#if !U_CHARSET_IS_UTF8
@@ -254,7 +254,7 @@ static UBool U_CALLCONV ucnv_cleanup(void) {
#if !U_CHARSET_IS_UTF8
gDefaultConverterName = NULL;
gDefaultConverterNameBuffer[0] = 0;
- gDefaultConverterContainsOption = FALSE;
+ gDefaultConverterContainsOption = false;
gDefaultAlgorithmicSharedData = NULL;
#endif
@@ -318,7 +318,7 @@ ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCo
data->staticData = source;
- data->sharedDataCached = FALSE;
+ data->sharedDataCached = false;
/* fill in fields from the loaded data */
data->dataMemory = (void*)pData; /* for future use */
@@ -462,7 +462,7 @@ ucnv_shareConverterData(UConverterSharedData * data)
*/
/* Mark it shared */
- data->sharedDataCached = TRUE;
+ data->sharedDataCached = true;
uhash_put(SHARED_DATA_HASHTABLE,
(void*) data->staticData->name, /* Okay to cast away const as long as
@@ -502,11 +502,11 @@ ucnv_getSharedConverterData(const char *name)
*/
/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to
* see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and
- * returns TRUE,
- * otherwise returns FALSE
+ * returns true,
+ * otherwise returns false
* @param sharedConverterData The shared data
* @return if not it frees all the memory stemming from sharedConverterData and
- * returns TRUE, otherwise returns FALSE
+ * returns true, otherwise returns false
*/
static UBool
ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
@@ -515,8 +515,8 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
UTRACE_DATA2(UTRACE_OPEN_CLOSE, "unload converter %s shared data %p", deadSharedData->staticData->name, deadSharedData);
if (deadSharedData->referenceCounter > 0) {
- UTRACE_EXIT_VALUE((int32_t)FALSE);
- return FALSE;
+ UTRACE_EXIT_VALUE((int32_t)false);
+ return false;
}
if (deadSharedData->impl->unload != NULL) {
@@ -531,8 +531,8 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
uprv_free(deadSharedData);
- UTRACE_EXIT_VALUE((int32_t)TRUE);
- return TRUE;
+ UTRACE_EXIT_VALUE((int32_t)true);
+ return true;
}
/**
@@ -589,7 +589,7 @@ ucnv_unload(UConverterSharedData *sharedData) {
sharedData->referenceCounter--;
}
- if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) {
+ if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == false)) {
ucnv_deleteSharedConverterData(sharedData);
}
}
@@ -703,10 +703,10 @@ parseConverterOptions(const char *inName,
/*Logic determines if the converter is Algorithmic AND/OR cached
*depending on that:
- * -we either go to get data from disk and cache it (Data=TRUE, Cached=False)
- * -Get it from a Hashtable (Data=X, Cached=TRUE)
- * -Call dataConverter initializer (Data=TRUE, Cached=TRUE)
- * -Call AlgorithmicConverter initializer (Data=FALSE, Cached=TRUE)
+ * -we either go to get data from disk and cache it (Data=true, Cached=false)
+ * -Get it from a Hashtable (Data=X, Cached=true)
+ * -Call dataConverter initializer (Data=true, Cached=true)
+ * -Call AlgorithmicConverter initializer (Data=false, Cached=true)
*/
U_CFUNC UConverterSharedData *
ucnv_loadSharedData(const char *converterName,
@@ -717,8 +717,8 @@ ucnv_loadSharedData(const char *converterName,
UConverterLoadArgs stackArgs;
UConverterSharedData *mySharedConverterData = NULL;
UErrorCode internalErrorCode = U_ZERO_ERROR;
- UBool mayContainOption = TRUE;
- UBool checkForAlgorithmic = TRUE;
+ UBool mayContainOption = true;
+ UBool checkForAlgorithmic = true;
if (U_FAILURE (*err)) {
return NULL;
@@ -762,7 +762,7 @@ ucnv_loadSharedData(const char *converterName,
return NULL;
}
mySharedConverterData = (UConverterSharedData *)gDefaultAlgorithmicSharedData;
- checkForAlgorithmic = FALSE;
+ checkForAlgorithmic = false;
mayContainOption = gDefaultConverterContainsOption;
/* the default converter name is already canonical */
#endif
@@ -866,7 +866,7 @@ ucnv_canCreateConverter(const char *converterName, UErrorCode *err) {
if(U_SUCCESS(*err)) {
UTRACE_DATA1(UTRACE_OPEN_CLOSE, "test if can open converter %s", converterName);
- stackArgs.onlyTestIsLoadable=TRUE;
+ stackArgs.onlyTestIsLoadable=true;
mySharedConverterData = ucnv_loadSharedData(converterName, &stackPieces, &stackArgs, err);
ucnv_createConverterFromSharedData(
&myUConverter, mySharedConverterData,
@@ -989,15 +989,15 @@ ucnv_createConverterFromSharedData(UConverter *myUConverter,
ucnv_unloadSharedDataIfReady(mySharedConverterData);
return NULL;
}
- isCopyLocal = FALSE;
+ isCopyLocal = false;
} else {
- isCopyLocal = TRUE;
+ isCopyLocal = true;
}
/* initialize the converter */
uprv_memset(myUConverter, 0, sizeof(UConverter));
myUConverter->isCopyLocal = isCopyLocal;
- /*myUConverter->isExtraLocal = FALSE;*/ /* Set by the memset call */
+ /*myUConverter->isExtraLocal = false;*/ /* Set by the memset call */
myUConverter->sharedData = mySharedConverterData;
myUConverter->options = pArgs->options;
if(!pArgs->onlyTestIsLoadable) {
@@ -1083,7 +1083,7 @@ ucnv_flushCache ()
UCNV_DEBUG_LOG("del",mySharedData->staticData->name,mySharedData);
uhash_removeElement(SHARED_DATA_HASHTABLE, e);
- mySharedData->sharedDataCached = FALSE;
+ mySharedData->sharedDataCached = false;
ucnv_deleteSharedConverterData (mySharedData);
} else {
++remaining;
@@ -1342,7 +1342,7 @@ ucnv_swap(const UDataSwapper *ds,
_MBCSHeader *outMBCSHeader;
_MBCSHeader mbcsHeader;
uint32_t mbcsHeaderLength;
- UBool noFromU=FALSE;
+ UBool noFromU=false;
uint8_t outputType;
diff --git a/thirdparty/icu4c/common/ucnv_cb.cpp b/thirdparty/icu4c/common/ucnv_cb.cpp
index 1bb0012014..7bfde82870 100644
--- a/thirdparty/icu4c/common/ucnv_cb.cpp
+++ b/thirdparty/icu4c/common/ucnv_cb.cpp
@@ -86,7 +86,7 @@ ucnv_cbFromUWriteUChars(UConverterFromUnicodeArgs *args,
source,
sourceLimit,
NULL, /* no offsets */
- FALSE, /* no flush */
+ false, /* no flush */
err);
if(args->offsets)
@@ -141,7 +141,7 @@ ucnv_cbFromUWriteUChars(UConverterFromUnicodeArgs *args,
source,
sourceLimit,
NULL,
- FALSE,
+ false,
&err2);
/* We can go ahead and overwrite the length here. We know just how
diff --git a/thirdparty/icu4c/common/ucnv_ct.cpp b/thirdparty/icu4c/common/ucnv_ct.cpp
index b40e1b2c97..c12e982b88 100644
--- a/thirdparty/icu4c/common/ucnv_ct.cpp
+++ b/thirdparty/icu4c/common/ucnv_ct.cpp
@@ -225,23 +225,23 @@ static COMPOUND_TEXT_CONVERTERS getState(int codepoint) {
static COMPOUND_TEXT_CONVERTERS findStateFromEscSeq(const char* source, const char* sourceLimit, const uint8_t* toUBytesBuffer, int32_t toUBytesBufferLength, UErrorCode *err) {
COMPOUND_TEXT_CONVERTERS state = INVALID;
- UBool matchFound = FALSE;
+ UBool matchFound = false;
int32_t i, n, offset = toUBytesBufferLength;
for (i = 0; i < NUM_OF_CONVERTERS; i++) {
- matchFound = TRUE;
+ matchFound = true;
for (n = 0; escSeqCompoundText[i][n] != 0; n++) {
if (n < toUBytesBufferLength) {
if (toUBytesBuffer[n] != escSeqCompoundText[i][n]) {
- matchFound = FALSE;
+ matchFound = false;
break;
}
} else if ((source + (n - offset)) >= sourceLimit) {
*err = U_TRUNCATED_CHAR_FOUND;
- matchFound = FALSE;
+ matchFound = false;
break;
} else if (*(source + (n - offset)) != escSeqCompoundText[i][n]) {
- matchFound = FALSE;
+ matchFound = false;
break;
}
}
@@ -634,8 +634,8 @@ static const UConverterStaticData _CompoundTextStaticData = {
6,
{ 0xef, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnv_ext.cpp b/thirdparty/icu4c/common/ucnv_ext.cpp
index 7dea4eef41..ffc3c93033 100644
--- a/thirdparty/icu4c/common/ucnv_ext.cpp
+++ b/thirdparty/icu4c/common/ucnv_ext.cpp
@@ -108,7 +108,7 @@ ucnv_extFindToU(const uint32_t *toUSection, int32_t length, uint8_t byte) {
}
/*
- * TRUE if not an SI/SO stateful converter,
+ * true if not an SI/SO stateful converter,
* or if the match length fits with the current converter state
*/
#define UCNV_EXT_TO_U_VERIFY_SISO_MATCH(sisoState, match) \
@@ -154,7 +154,7 @@ ucnv_extMatchToU(const int32_t *cx, int8_t sisoState,
srcLength=1;
}
}
- flush=TRUE;
+ flush=true;
}
/* we must not remember fallback matches when not using fallbacks */
@@ -302,7 +302,7 @@ ucnv_extInitialMatchToU(UConverter *cnv, const int32_t *cx,
target, targetLimit,
offsets, srcIndex,
pErrorCode);
- return TRUE;
+ return true;
} else if(match<0) {
/* save state for partial match */
const char *s;
@@ -323,9 +323,9 @@ ucnv_extInitialMatchToU(UConverter *cnv, const int32_t *cx,
}
*src=s; /* same as *src=srcLimit; because we reached the end of input */
cnv->preToULength=(int8_t)match;
- return TRUE;
+ return true;
} else /* match==0 no match */ {
- return FALSE;
+ return false;
}
}
@@ -345,7 +345,7 @@ ucnv_extSimpleMatchToU(const int32_t *cx,
source, length,
NULL, 0,
&value,
- useFallback, TRUE);
+ useFallback, true);
if(match==length) {
/* write result for simple, single-character conversion */
if(UCNV_EXT_TO_U_IS_CODE_POINT(value)) {
@@ -358,7 +358,7 @@ ucnv_extSimpleMatchToU(const int32_t *cx,
* - match>0 && value points to string: simple conversion cannot handle multiple code points
* - match>0 && match!=length: not all input consumed, forbidden for this function
* - match==0: no match found in the first place
- * - match<0: partial match, not supported for simple conversion (and flush==TRUE)
+ * - match<0: partial match, not supported for simple conversion (and flush==true)
*/
return 0xfffe;
}
@@ -516,13 +516,13 @@ ucnv_extFindFromU(const UChar *fromUSection, int32_t length, UChar u) {
* @param srcLength length of src, >=0
* @param pMatchValue [out] output result value for the match from the data structure
* @param useFallback "use fallback" flag, usually from cnv->useFallback
- * @param flush TRUE if the end of the input stream is reached
+ * @param flush true if the end of the input stream is reached
* @return >1: matched, return value=total match length (number of input units matched)
* 1: matched, no mapping but request for <subchar1>
* (only for the first code point)
* 0: no match
* <0: partial match, return value=negative total match length
- * (partial matches are never returned for flush==TRUE)
+ * (partial matches are never returned for flush==true)
* (partial matches are never returned as being longer than UCNV_EXT_MAX_UCHARS)
* the matchLength is 2 if only firstCP matched, and >2 if firstCP and
* further code units matched
@@ -778,7 +778,7 @@ ucnv_extInitialMatchFromU(UConverter *cnv, const int32_t *cx,
target, targetLimit,
offsets, srcIndex,
pErrorCode);
- return TRUE;
+ return true;
} else if(match<0) {
/* save state for partial match */
const UChar *s;
@@ -795,13 +795,13 @@ ucnv_extInitialMatchFromU(UConverter *cnv, const int32_t *cx,
}
*src=s; /* same as *src=srcLimit; because we reached the end of input */
cnv->preFromULength=(int8_t)match;
- return TRUE;
+ return true;
} else if(match==1) {
/* matched, no mapping but request for <subchar1> */
- cnv->useSubChar1=TRUE;
- return FALSE;
+ cnv->useSubChar1=true;
+ return false;
} else /* match==0 no match */ {
- return FALSE;
+ return false;
}
}
@@ -822,7 +822,7 @@ ucnv_extSimpleMatchFromU(const int32_t *cx,
NULL, 0,
NULL, 0,
&value,
- useFallback, TRUE);
+ useFallback, true);
if(match>=2) {
/* write result for simple, single-character conversion */
int32_t length;
@@ -854,7 +854,7 @@ ucnv_extSimpleMatchFromU(const int32_t *cx,
* - match>1 && resultLength>4: result too long for simple conversion
* - match==1: no match found, <subchar1> preferred
* - match==0: no match found in the first place
- * - match<0: partial match, not supported for simple conversion (and flush==TRUE)
+ * - match<0: partial match, not supported for simple conversion (and flush==true)
*/
return 0;
}
@@ -934,7 +934,7 @@ ucnv_extContinueMatchFromU(UConverter *cnv,
if(match==1) {
/* matched, no mapping but request for <subchar1> */
- cnv->useSubChar1=TRUE;
+ cnv->useSubChar1=true;
}
/* move the first code point to the error field */
@@ -961,12 +961,12 @@ extSetUseMapping(UConverterUnicodeSet which, int32_t minLength, uint32_t value)
// Do not add entries with reserved bits set.
if(((value&(UCNV_EXT_FROM_U_ROUNDTRIP_FLAG|UCNV_EXT_FROM_U_RESERVED_MASK))!=
UCNV_EXT_FROM_U_ROUNDTRIP_FLAG)) {
- return FALSE;
+ return false;
}
} else /* UCNV_ROUNDTRIP_AND_FALLBACK_SET */ {
// Do not add entries with reserved bits set.
if((value&UCNV_EXT_FROM_U_RESERVED_MASK)!=0) {
- return FALSE;
+ return false;
}
}
// Do not add <subchar1> entries or other (future?) pseudo-entries
diff --git a/thirdparty/icu4c/common/ucnv_io.cpp b/thirdparty/icu4c/common/ucnv_io.cpp
index 7a95a3f1e6..c9d20cb941 100644
--- a/thirdparty/icu4c/common/ucnv_io.cpp
+++ b/thirdparty/icu4c/common/ucnv_io.cpp
@@ -175,7 +175,7 @@ static const char DATA_NAME[] = "cnvalias";
static const char DATA_TYPE[] = "icu";
static UDataMemory *gAliasData=NULL;
-static icu::UInitOnce gAliasDataInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gAliasDataInitOnce {};
enum {
tocLengthIndex=0,
@@ -226,7 +226,7 @@ static UBool U_CALLCONV ucnv_io_cleanup(void)
uprv_memset(&gMainTable, 0, sizeof(gMainTable));
- return TRUE; /* Everything was cleaned up */
+ return true; /* Everything was cleaned up */
}
static void U_CALLCONV initAliasData(UErrorCode &errCode) {
@@ -319,7 +319,7 @@ static inline UBool
isAlias(const char *alias, UErrorCode *pErrorCode) {
if(alias==NULL) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
return (UBool)(*alias!=0);
}
@@ -388,13 +388,13 @@ ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
char *dstItr = dst;
uint8_t type, nextType;
char c1;
- UBool afterDigit = FALSE;
+ UBool afterDigit = false;
while ((c1 = *name++) != 0) {
type = GET_ASCII_TYPE(c1);
switch (type) {
case UIGNORE:
- afterDigit = FALSE;
+ afterDigit = false;
continue; /* ignore all but letters and digits */
case ZERO:
if (!afterDigit) {
@@ -405,11 +405,11 @@ ucnv_io_stripASCIIForCompare(char *dst, const char *name) {
}
break;
case NONZERO:
- afterDigit = TRUE;
+ afterDigit = true;
break;
default:
c1 = (char)type; /* lowercased letter */
- afterDigit = FALSE;
+ afterDigit = false;
break;
}
*dstItr++ = c1;
@@ -423,13 +423,13 @@ ucnv_io_stripEBCDICForCompare(char *dst, const char *name) {
char *dstItr = dst;
uint8_t type, nextType;
char c1;
- UBool afterDigit = FALSE;
+ UBool afterDigit = false;
while ((c1 = *name++) != 0) {
type = GET_EBCDIC_TYPE(c1);
switch (type) {
case UIGNORE:
- afterDigit = FALSE;
+ afterDigit = false;
continue; /* ignore all but letters and digits */
case ZERO:
if (!afterDigit) {
@@ -440,11 +440,11 @@ ucnv_io_stripEBCDICForCompare(char *dst, const char *name) {
}
break;
case NONZERO:
- afterDigit = TRUE;
+ afterDigit = true;
break;
default:
c1 = (char)type; /* lowercased letter */
- afterDigit = FALSE;
+ afterDigit = false;
break;
}
*dstItr++ = c1;
@@ -479,14 +479,14 @@ ucnv_compareNames(const char *name1, const char *name2) {
int rc;
uint8_t type, nextType;
char c1, c2;
- UBool afterDigit1 = FALSE, afterDigit2 = FALSE;
+ UBool afterDigit1 = false, afterDigit2 = false;
for (;;) {
while ((c1 = *name1++) != 0) {
type = GET_CHAR_TYPE(c1);
switch (type) {
case UIGNORE:
- afterDigit1 = FALSE;
+ afterDigit1 = false;
continue; /* ignore all but letters and digits */
case ZERO:
if (!afterDigit1) {
@@ -497,11 +497,11 @@ ucnv_compareNames(const char *name1, const char *name2) {
}
break;
case NONZERO:
- afterDigit1 = TRUE;
+ afterDigit1 = true;
break;
default:
c1 = (char)type; /* lowercased letter */
- afterDigit1 = FALSE;
+ afterDigit1 = false;
break;
}
break; /* deliver c1 */
@@ -510,7 +510,7 @@ ucnv_compareNames(const char *name1, const char *name2) {
type = GET_CHAR_TYPE(c2);
switch (type) {
case UIGNORE:
- afterDigit2 = FALSE;
+ afterDigit2 = false;
continue; /* ignore all but letters and digits */
case ZERO:
if (!afterDigit2) {
@@ -521,11 +521,11 @@ ucnv_compareNames(const char *name1, const char *name2) {
}
break;
case NONZERO:
- afterDigit2 = TRUE;
+ afterDigit2 = true;
break;
default:
c2 = (char)type; /* lowercased letter */
- afterDigit2 = FALSE;
+ afterDigit2 = false;
break;
}
break; /* deliver c2 */
@@ -628,11 +628,11 @@ isAliasInList(const char *alias, uint32_t listOffset) {
if (currList[currAlias]
&& ucnv_compareNames(alias, GET_STRING(currList[currAlias]))==0)
{
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
/*
@@ -1288,7 +1288,7 @@ ucnv_swapAliases(const UDataSwapper *ds,
uprv_sortArray(tempTable.rows, (int32_t)count, sizeof(TempRow),
io_compareRows, &tempTable,
- FALSE, pErrorCode);
+ false, pErrorCode);
if(U_SUCCESS(*pErrorCode)) {
/* copy/swap/permutate items */
diff --git a/thirdparty/icu4c/common/ucnv_lmb.cpp b/thirdparty/icu4c/common/ucnv_lmb.cpp
index 6969727927..78b8e40700 100644
--- a/thirdparty/icu4c/common/ucnv_lmb.cpp
+++ b/thirdparty/icu4c/common/ucnv_lmb.cpp
@@ -610,7 +610,7 @@ static const UConverterStaticData _LMBCSStaticData##n={\
sizeof(UConverterStaticData),\
"LMBCS-" #n,\
0, UCNV_IBM, UCNV_LMBCS_##n, 1, 3,\
- { 0x3f, 0, 0, 0 },1,FALSE,FALSE,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} \
+ { 0x3f, 0, 0, 0 },1,false,false,0,0,{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} \
};\
const UConverterSharedData _LMBCSData##n= \
UCNV_IMMUTABLE_SHARED_DATA_INITIALIZER(&_LMBCSStaticData##n, &_LMBCSImpl##n);
@@ -721,7 +721,7 @@ _LMBCSSafeClone(const UConverter *cnv,
}
newLMBCS->cnv.extraInfo = &newLMBCS->lmbcs;
- newLMBCS->cnv.isExtraLocal = TRUE;
+ newLMBCS->cnv.isExtraLocal = true;
return &newLMBCS->cnv;
}
@@ -763,14 +763,14 @@ LMBCSConversionWorker (
U_ASSERT(xcnv);
U_ASSERT(group<ULMBCS_GRP_UNICODE);
- bytesConverted = ucnv_MBCSFromUChar32(xcnv, *pUniChar, &value, FALSE);
+ bytesConverted = ucnv_MBCSFromUChar32(xcnv, *pUniChar, &value, false);
/* get the first result byte */
if(bytesConverted > 0) {
firstByte = (ulmbcs_byte_t)(value >> ((bytesConverted - 1) * 8));
} else {
/* most common failure mode is an unassigned character */
- groups_tried[group] = TRUE;
+ groups_tried[group] = true;
return 0;
}
@@ -1191,11 +1191,11 @@ _LMBCSGetNextUCharWorker(UConverterToUnicodeArgs* args,
if (*args->source == group) {
/* single byte */
++args->source;
- uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 1, FALSE);
+ uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 1, false);
++args->source;
} else {
/* double byte */
- uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 2, FALSE);
+ uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source, 2, false);
args->source += 2;
}
}
@@ -1220,7 +1220,7 @@ _LMBCSGetNextUCharWorker(UConverterToUnicodeArgs* args,
/* Lookup value must include opt group */
bytes[0] = group;
bytes[1] = CurByte;
- uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, bytes, 2, FALSE);
+ uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, bytes, 2, false);
}
}
}
@@ -1236,13 +1236,13 @@ _LMBCSGetNextUCharWorker(UConverterToUnicodeArgs* args,
CHECK_SOURCE_LIMIT(0);
/* let the MBCS conversion consume CurByte again */
- uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 1, FALSE);
+ uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 1, false);
}
else
{
CHECK_SOURCE_LIMIT(1);
/* let the MBCS conversion consume CurByte again */
- uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 2, FALSE);
+ uniChar = ucnv_MBCSSimpleGetNextUChar(cnv, args->source - 1, 2, false);
++args->source;
}
}
diff --git a/thirdparty/icu4c/common/ucnv_u16.cpp b/thirdparty/icu4c/common/ucnv_u16.cpp
index a5e8367400..bebdede4c4 100644
--- a/thirdparty/icu4c/common/ucnv_u16.cpp
+++ b/thirdparty/icu4c/common/ucnv_u16.cpp
@@ -637,7 +637,7 @@ static const UConverterStaticData _UTF16BEStaticData={
sizeof(UConverterStaticData),
"UTF-16BE",
1200, UCNV_IBM, UCNV_UTF16_BigEndian, 2, 2,
- { 0xff, 0xfd, 0, 0 },2,FALSE,FALSE,
+ { 0xff, 0xfd, 0, 0 },2,false,false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -1239,7 +1239,7 @@ static const UConverterStaticData _UTF16LEStaticData={
sizeof(UConverterStaticData),
"UTF-16LE",
1202, UCNV_IBM, UCNV_UTF16_LittleEndian, 2, 2,
- { 0xfd, 0xff, 0, 0 },2,FALSE,FALSE,
+ { 0xfd, 0xff, 0, 0 },2,false,false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -1526,7 +1526,7 @@ static const UConverterStaticData _UTF16StaticData = {
#else
{ 0xfd, 0xff, 0, 0 }, 2,
#endif
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -1567,7 +1567,7 @@ static const UConverterStaticData _UTF16v2StaticData = {
1204, /* CCSID for BOM sensitive UTF-16 */
UCNV_IBM, UCNV_UTF16, 2, 2,
{ 0xff, 0xfd, 0, 0 }, 2,
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnv_u32.cpp b/thirdparty/icu4c/common/ucnv_u32.cpp
index bf6bd11dba..bc160b71dd 100644
--- a/thirdparty/icu4c/common/ucnv_u32.cpp
+++ b/thirdparty/icu4c/common/ucnv_u32.cpp
@@ -494,7 +494,7 @@ static const UConverterStaticData _UTF32BEStaticData = {
"UTF-32BE",
1232,
UCNV_IBM, UCNV_UTF32_BigEndian, 4, 4,
- { 0, 0, 0xff, 0xfd }, 4, FALSE, FALSE,
+ { 0, 0, 0xff, 0xfd }, 4, false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -989,7 +989,7 @@ static const UConverterStaticData _UTF32LEStaticData = {
"UTF-32LE",
1234,
UCNV_IBM, UCNV_UTF32_LittleEndian, 4, 4,
- { 0xfd, 0xff, 0, 0 }, 4, FALSE, FALSE,
+ { 0xfd, 0xff, 0, 0 }, 4, false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -1110,7 +1110,7 @@ _UTF32ToUnicodeWithOffsets(UConverterToUnicodeArgs *pArgs,
/* some of the bytes are from a previous buffer, replay those first */
pArgs->source=utf32BOM+(state&4); /* select the correct BOM */
pArgs->sourceLimit=pArgs->source+((state&3)-count); /* replay previous bytes */
- pArgs->flush=FALSE; /* this sourceLimit is not the real source stream limit */
+ pArgs->flush=false; /* this sourceLimit is not the real source stream limit */
/* no offsets: bytes from previous buffer, and not enough for output */
T_UConverter_toUnicode_UTF32_BE(pArgs, pErrorCode);
@@ -1241,7 +1241,7 @@ static const UConverterStaticData _UTF32StaticData = {
#else
{ 0xfd, 0xff, 0, 0 }, 4,
#endif
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnv_u7.cpp b/thirdparty/icu4c/common/ucnv_u7.cpp
index de9f3f42ec..8964ca01de 100644
--- a/thirdparty/icu4c/common/ucnv_u7.cpp
+++ b/thirdparty/icu4c/common/ucnv_u7.cpp
@@ -184,12 +184,12 @@ static void U_CALLCONV
_UTF7Reset(UConverter *cnv, UConverterResetChoice choice) {
if(choice<=UCNV_RESET_TO_UNICODE) {
/* reset toUnicode */
- cnv->toUnicodeStatus=0x1000000; /* inDirectMode=TRUE */
+ cnv->toUnicodeStatus=0x1000000; /* inDirectMode=true */
cnv->toULength=0;
}
if(choice!=UCNV_RESET_TO_UNICODE) {
/* reset fromUnicode */
- cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+ cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
}
}
@@ -286,7 +286,7 @@ directMode:
} else /* PLUS */ {
/* switch to Unicode mode */
nextSourceIndex=++sourceIndex;
- inDirectMode=FALSE;
+ inDirectMode=false;
byteIndex=0;
bits=0;
base64Counter=-1;
@@ -329,7 +329,7 @@ unicodeMode:
* It may be for example, a plus which we need to deal with in direct mode.
* 2.2.2. Else if the current char is illegal, we might as well deal with it here.
*/
- inDirectMode=TRUE;
+ inDirectMode=true;
if(base64Counter==-1) {
/* illegal: + immediately followed by something other than base64 or minus sign */
/* include the plus sign in the reported sequence, but not the subsequent char */
@@ -411,7 +411,7 @@ unicodeMode:
}
} else /*base64Value==-2*/ {
/* minus sign terminates the base64 sequence */
- inDirectMode=TRUE;
+ inDirectMode=true;
if(base64Counter==-1) {
/* +- i.e. a minus immediately following a plus */
*target++=PLUS;
@@ -541,7 +541,7 @@ directMode:
if(offsets!=NULL) {
*offsets++=sourceIndex;
}
- inDirectMode=FALSE;
+ inDirectMode=false;
base64Counter=0;
goto unicodeMode;
}
@@ -558,7 +558,7 @@ unicodeMode:
c=*source++;
if(c<=127 && encodeDirectly[c]) {
/* encode directly */
- inDirectMode=TRUE;
+ inDirectMode=true;
/* trick: back out this character to make this easier */
--source;
@@ -719,7 +719,7 @@ unicodeMode:
}
}
/* reset the state for the next conversion */
- cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+ cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
} else {
/* set the converter state back into UConverter */
cnv->fromUnicodeStatus=
@@ -778,7 +778,7 @@ static const UConverterStaticData _UTF7StaticData={
UCNV_IBM, UCNV_UTF7,
1, 4,
{ 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -971,7 +971,7 @@ directMode:
} else /* AMPERSAND */ {
/* switch to Unicode mode */
nextSourceIndex=++sourceIndex;
- inDirectMode=FALSE;
+ inDirectMode=false;
byteIndex=0;
bits=0;
base64Counter=-1;
@@ -1002,7 +1002,7 @@ unicodeMode:
++nextSourceIndex;
if(b>0x7e) {
/* illegal - test other illegal US-ASCII values by base64Value==-3 */
- inDirectMode=TRUE;
+ inDirectMode=true;
*pErrorCode=U_ILLEGAL_CHAR_FOUND;
break;
} else if((base64Value=FROM_BASE64_IMAP(b))>=0) {
@@ -1024,7 +1024,7 @@ unicodeMode:
c=(UChar)((bits<<4)|(base64Value>>2));
if(isLegalIMAP(c)) {
/* illegal */
- inDirectMode=TRUE;
+ inDirectMode=true;
*pErrorCode=U_ILLEGAL_CHAR_FOUND;
goto endloop;
}
@@ -1042,7 +1042,7 @@ unicodeMode:
c=(UChar)((bits<<2)|(base64Value>>4));
if(isLegalIMAP(c)) {
/* illegal */
- inDirectMode=TRUE;
+ inDirectMode=true;
*pErrorCode=U_ILLEGAL_CHAR_FOUND;
goto endloop;
}
@@ -1060,7 +1060,7 @@ unicodeMode:
c=(UChar)((bits<<6)|base64Value);
if(isLegalIMAP(c)) {
/* illegal */
- inDirectMode=TRUE;
+ inDirectMode=true;
*pErrorCode=U_ILLEGAL_CHAR_FOUND;
goto endloop;
}
@@ -1079,7 +1079,7 @@ unicodeMode:
}
} else if(base64Value==-2) {
/* minus sign terminates the base64 sequence */
- inDirectMode=TRUE;
+ inDirectMode=true;
if(base64Counter==-1) {
/* &- i.e. a minus immediately following an ampersand */
*target++=AMPERSAND;
@@ -1109,7 +1109,7 @@ unicodeMode:
/* base64Value==-1 for characters that are illegal only in Unicode mode */
/* base64Value==-3 for illegal characters */
/* illegal */
- inDirectMode=TRUE;
+ inDirectMode=true;
*pErrorCode=U_ILLEGAL_CHAR_FOUND;
break;
}
@@ -1144,7 +1144,7 @@ endloop:
}
/* else if(base64Counter!=-1) byteIndex remains 0 because there is no particular byte sequence */
- inDirectMode=TRUE; /* avoid looping */
+ inDirectMode=true; /* avoid looping */
*pErrorCode=U_TRUNCATED_CHAR_FOUND;
}
@@ -1240,7 +1240,7 @@ directMode:
if(offsets!=NULL) {
*offsets++=sourceIndex;
}
- inDirectMode=FALSE;
+ inDirectMode=false;
base64Counter=0;
goto unicodeMode;
}
@@ -1257,7 +1257,7 @@ unicodeMode:
c=*source++;
if(isLegalIMAP(c)) {
/* encode directly */
- inDirectMode=TRUE;
+ inDirectMode=true;
/* trick: back out this character to make this easier */
--source;
@@ -1431,7 +1431,7 @@ unicodeMode:
}
}
/* reset the state for the next conversion */
- cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=TRUE */
+ cnv->fromUnicodeStatus=(cnv->fromUnicodeStatus&0xf0000000)|0x1000000; /* keep version, inDirectMode=true */
} else {
/* set the converter state back into UConverter */
cnv->fromUnicodeStatus=
@@ -1479,7 +1479,7 @@ static const UConverterStaticData _IMAPStaticData={
UCNV_IBM, UCNV_IMAP_MAILBOX,
1, 4,
{ 0x3f, 0, 0, 0 }, 1, /* the subchar is not used */
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnv_u8.cpp b/thirdparty/icu4c/common/ucnv_u8.cpp
index 1ef7fa2f02..3c27f2e46e 100644
--- a/thirdparty/icu4c/common/ucnv_u8.cpp
+++ b/thirdparty/icu4c/common/ucnv_u8.cpp
@@ -56,7 +56,7 @@ static const uint32_t offsetsFromUTF8[5] = {0,
static UBool hasCESU8Data(const UConverter *cnv)
{
#if UCONFIG_ONLY_HTML_CONVERSION
- return FALSE;
+ return false;
#else
return (UBool)(cnv->sharedData == &_CESU8Data);
#endif
@@ -888,7 +888,7 @@ static const UConverterStaticData _UTF8StaticData={
"UTF-8",
1208, UCNV_IBM, UCNV_UTF8,
1, 3, /* max 3 bytes per UChar from UTF-8 (4 bytes from surrogate _pair_) */
- { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
+ { 0xef, 0xbf, 0xbd, 0 },3,false,false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -931,7 +931,7 @@ static const UConverterStaticData _CESU8StaticData={
"CESU-8",
9400, /* CCSID for CESU-8 */
UCNV_UNKNOWN, UCNV_CESU8, 1, 3,
- { 0xef, 0xbf, 0xbd, 0 },3,FALSE,FALSE,
+ { 0xef, 0xbf, 0xbd, 0 },3,false,false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvbocu.cpp b/thirdparty/icu4c/common/ucnvbocu.cpp
index 7c2aab5655..edb49d36a9 100644
--- a/thirdparty/icu4c/common/ucnvbocu.cpp
+++ b/thirdparty/icu4c/common/ucnvbocu.cpp
@@ -195,7 +195,7 @@ bocu1TrailToByte[BOCU1_TRAIL_CONTROLS_COUNT]={
* what we need here.
* This macro adjust the results so that the modulo-value m is always >=0.
*
- * For positive n, the if() condition is always FALSE.
+ * For positive n, the if() condition is always false.
*
* @param n Number to be split into quotient and rest.
* Will be modified to contain the quotient.
@@ -1401,7 +1401,7 @@ static const UConverterStaticData _Bocu1StaticData={
UCNV_IBM, UCNV_BOCU1,
1, 4, /* one UChar generates at least 1 byte and at most 4 bytes */
{ 0x1a, 0, 0, 0 }, 1, /* BOCU-1 never needs to write a subchar */
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvhz.cpp b/thirdparty/icu4c/common/ucnvhz.cpp
index 6b2f5faaf0..e0d2f0775d 100644
--- a/thirdparty/icu4c/common/ucnvhz.cpp
+++ b/thirdparty/icu4c/common/ucnvhz.cpp
@@ -111,18 +111,18 @@ _HZReset(UConverter *cnv, UConverterResetChoice choice){
cnv->toUnicodeStatus = 0;
cnv->mode=0;
if(cnv->extraInfo != NULL){
- ((UConverterDataHZ*)cnv->extraInfo)->isStateDBCS = FALSE;
- ((UConverterDataHZ*)cnv->extraInfo)->isEmptySegment = FALSE;
+ ((UConverterDataHZ*)cnv->extraInfo)->isStateDBCS = false;
+ ((UConverterDataHZ*)cnv->extraInfo)->isEmptySegment = false;
}
}
if(choice!=UCNV_RESET_TO_UNICODE) {
cnv->fromUnicodeStatus= 0;
cnv->fromUChar32=0x0000;
if(cnv->extraInfo != NULL){
- ((UConverterDataHZ*)cnv->extraInfo)->isEscapeAppended = FALSE;
+ ((UConverterDataHZ*)cnv->extraInfo)->isEscapeAppended = false;
((UConverterDataHZ*)cnv->extraInfo)->targetIndex = 0;
((UConverterDataHZ*)cnv->extraInfo)->sourceIndex = 0;
- ((UConverterDataHZ*)cnv->extraInfo)->isTargetUCharDBCS = FALSE;
+ ((UConverterDataHZ*)cnv->extraInfo)->isTargetUCharDBCS = false;
}
}
}
@@ -189,13 +189,13 @@ UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
args->offsets[myTarget - args->target]=(int32_t)(mySource - args->source - 2);
}
*(myTarget++)=(UChar)mySourceChar;
- myData->isEmptySegment = FALSE;
+ myData->isEmptySegment = false;
continue;
case UCNV_OPEN_BRACE:
case UCNV_CLOSE_BRACE:
myData->isStateDBCS = (mySourceChar == UCNV_OPEN_BRACE);
if (myData->isEmptySegment) {
- myData->isEmptySegment = FALSE; /* we are handling it, reset to avoid future spurious errors */
+ myData->isEmptySegment = false; /* we are handling it, reset to avoid future spurious errors */
*err = U_ILLEGAL_ESCAPE_SEQUENCE;
args->converter->toUCallbackReason = UCNV_IRREGULAR;
args->converter->toUBytes[0] = UCNV_TILDE;
@@ -205,7 +205,7 @@ UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
args->source = mySource;
return;
}
- myData->isEmptySegment = TRUE;
+ myData->isEmptySegment = true;
continue;
default:
/* if the first byte is equal to TILDE and the trail byte
@@ -217,7 +217,7 @@ UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
* - If any of the non-initial bytes could be the start of a character,
* we stop the illegal sequence before the first one of those.
*/
- myData->isEmptySegment = FALSE; /* different error here, reset this to avoid spurious future error */
+ myData->isEmptySegment = false; /* different error here, reset this to avoid spurious future error */
*err = U_ILLEGAL_ESCAPE_SEQUENCE;
args->converter->toUBytes[0] = UCNV_TILDE;
if( myData->isStateDBCS ?
@@ -244,7 +244,7 @@ UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
} else {
/* add another bit to distinguish a 0 byte from not having seen a lead byte */
args->converter->toUnicodeStatus = (uint32_t) (mySourceChar | 0x100);
- myData->isEmptySegment = FALSE; /* the segment has something, either valid or will produce a different error, so reset this */
+ myData->isEmptySegment = false; /* the segment has something, either valid or will produce a different error, so reset this */
}
continue;
}
@@ -289,10 +289,10 @@ UConverter_toUnicode_HZ_OFFSETS_LOGIC(UConverterToUnicodeArgs *args,
continue;
} else if(mySourceChar <= 0x7f) {
targetUniChar = (UChar)mySourceChar; /* ASCII */
- myData->isEmptySegment = FALSE; /* the segment has something valid */
+ myData->isEmptySegment = false; /* the segment has something valid */
} else {
targetUniChar = 0xffff;
- myData->isEmptySegment = FALSE; /* different error here, reset this to avoid spurious future error */
+ myData->isEmptySegment = false; /* different error here, reset this to avoid spurious future error */
}
}
if(targetUniChar < 0xfffe){
@@ -396,13 +396,13 @@ UConverter_fromUnicode_HZ_OFFSETS_LOGIC (UConverterFromUnicodeArgs * args,
len =ESC_LEN;
escSeq = SB_ESCAPE;
CONCAT_ESCAPE_MACRO(args, myTargetIndex, targetLength, escSeq,err,len,mySourceIndex);
- myConverterData->isEscapeAppended = TRUE;
+ myConverterData->isEscapeAppended = true;
}
else{ /* Shifting from a single byte to double byte mode*/
len =ESC_LEN;
escSeq = DB_ESCAPE;
CONCAT_ESCAPE_MACRO(args, myTargetIndex, targetLength, escSeq,err,len,mySourceIndex);
- myConverterData->isEscapeAppended = TRUE;
+ myConverterData->isEscapeAppended = true;
}
}
@@ -507,7 +507,7 @@ _HZ_WriteSub(UConverterFromUnicodeArgs *args, int32_t offsetIndex, UErrorCode *e
if( convData->isTargetUCharDBCS){
*p++= UCNV_TILDE;
*p++= UCNV_CLOSE_BRACE;
- convData->isTargetUCharDBCS=FALSE;
+ convData->isTargetUCharDBCS=false;
}
*p++= (char)cnv->subChars[0];
@@ -550,7 +550,7 @@ _HZ_SafeClone(const UConverter *cnv,
uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataHZ));
localClone->cnv.extraInfo = &localClone->mydata;
- localClone->cnv.isExtraLocal = TRUE;
+ localClone->cnv.isExtraLocal = true;
/* deep-clone the sub-converter */
size = (int32_t)sizeof(UConverter);
@@ -611,8 +611,8 @@ static const UConverterStaticData _HZStaticData={
4,
{ 0x1a, 0, 0, 0 },
1,
- FALSE,
- FALSE,
+ false,
+ false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvisci.cpp b/thirdparty/icu4c/common/ucnvisci.cpp
index f303e7e24f..4d747e1ff8 100644
--- a/thirdparty/icu4c/common/ucnvisci.cpp
+++ b/thirdparty/icu4c/common/ucnvisci.cpp
@@ -172,7 +172,7 @@ static const uint8_t pnjMap[80] = {
static UBool
isPNJConsonant(UChar32 c) {
if (c < 0xa00 || 0xa50 <= c) {
- return FALSE;
+ return false;
} else {
return (UBool)(pnjMap[c - 0xa00] & 1);
}
@@ -181,7 +181,7 @@ isPNJConsonant(UChar32 c) {
static UBool
isPNJBindiTippi(UChar32 c) {
if (c < 0xa00 || 0xa50 <= c) {
- return FALSE;
+ return false;
} else {
return (UBool)(pnjMap[c - 0xa00] >> 1);
}
@@ -202,7 +202,7 @@ _ISCIIOpen(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode) {
converterData->contextCharToUnicode=NO_CHAR_MARKER;
cnv->toUnicodeStatus = missingCharMarker;
converterData->contextCharFromUnicode=0x0000;
- converterData->resetToDefaultToUnicode=FALSE;
+ converterData->resetToDefaultToUnicode=false;
/* check if the version requested is supported */
if ((pArgs->options & UCNV_OPTIONS_VERSION_MASK) < 9) {
/* initialize state variables */
@@ -214,7 +214,7 @@ _ISCIIOpen(UConverter *cnv, UConverterLoadArgs *pArgs, UErrorCode *errorCode) {
= converterData->currentMaskToUnicode
= converterData->defMaskToUnicode = lookupInitialData[pArgs->options & UCNV_OPTIONS_VERSION_MASK].maskEnum;
- converterData->isFirstBuffer=TRUE;
+ converterData->isFirstBuffer=true;
(void)uprv_strcpy(converterData->name, ISCII_CNV_PREFIX);
len = (int32_t)uprv_strlen(converterData->name);
converterData->name[len]= (char)((pArgs->options & UCNV_OPTIONS_VERSION_MASK) + '0');
@@ -267,8 +267,8 @@ _ISCIIReset(UConverter *cnv, UConverterResetChoice choice) {
data->contextCharFromUnicode=0x00;
data->currentMaskFromUnicode=data->defMaskToUnicode;
data->currentDeltaFromUnicode=data->defDeltaToUnicode;
- data->isFirstBuffer=TRUE;
- data->resetToDefaultToUnicode=FALSE;
+ data->isFirstBuffer=true;
+ data->resetToDefaultToUnicode=false;
}
}
@@ -906,7 +906,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
UConverterDataISCII *converterData;
uint16_t newDelta=0;
uint16_t range = 0;
- UBool deltaChanged = FALSE;
+ UBool deltaChanged = false;
if ((args->converter == NULL) || (args->targetLimit < args->target) || (args->sourceLimit < args->source)) {
*err = U_ILLEGAL_ARGUMENT_ERROR;
@@ -986,8 +986,8 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
if (newDelta!= converterData->currentDeltaFromUnicode || converterData->isFirstBuffer) {
converterData->currentDeltaFromUnicode = newDelta;
converterData->currentMaskFromUnicode = lookupInitialData[range].maskEnum;
- deltaChanged =TRUE;
- converterData->isFirstBuffer=FALSE;
+ deltaChanged =true;
+ converterData->isFirstBuffer=false;
}
if (converterData->currentDeltaFromUnicode == PNJ_DELTA) {
@@ -1024,7 +1024,7 @@ UConverter_fromUnicode_ISCII_OFFSETS_LOGIC(
temp =(uint16_t)(ATR<<8);
temp += (uint16_t)((uint8_t) lookupInitialData[range].isciiLang);
/* reset */
- deltaChanged=FALSE;
+ deltaChanged=false;
/* now append ATR and language code */
WRITE_TO_TARGET_FROM_U(args,offsets,source,target,targetLimit,temp,err);
if (U_FAILURE(*err)) {
@@ -1330,7 +1330,7 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
break;
case 0x0A:
case 0x0D:
- data->resetToDefaultToUnicode = TRUE;
+ data->resetToDefaultToUnicode = true;
GET_MAPPING(sourceChar,targetUniChar,data)
;
*contextCharToUnicode = sourceChar;
@@ -1338,12 +1338,12 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
case ISCII_VOWEL_SIGN_E:
i=1;
- found=FALSE;
+ found=false;
for (; i<vowelSignESpecialCases[0][0]; i++) {
U_ASSERT(i<UPRV_LENGTHOF(vowelSignESpecialCases));
if (vowelSignESpecialCases[i][0]==(uint8_t)*contextCharToUnicode) {
targetUniChar=vowelSignESpecialCases[i][1];
- found=TRUE;
+ found=true;
break;
}
}
@@ -1397,12 +1397,12 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
} else {
/* try to handle <CHAR> + ISCII_NUKTA special mappings */
i=1;
- found =FALSE;
+ found =false;
for (; i<nuktaSpecialCases[0][0]; i++) {
if (nuktaSpecialCases[i][0]==(uint8_t)
*contextCharToUnicode) {
targetUniChar=nuktaSpecialCases[i][1];
- found =TRUE;
+ found =true;
break;
}
}
@@ -1472,10 +1472,10 @@ UConverter_toUnicode_ISCII_OFFSETS_LOGIC(UConverterToUnicodeArgs *args, UErrorCo
if (targetUniChar != missingCharMarker) {
/* now save the targetUniChar for delayed write */
*toUnicodeStatus = (UChar) targetUniChar;
- if (data->resetToDefaultToUnicode==TRUE) {
+ if (data->resetToDefaultToUnicode==true) {
data->currentDeltaToUnicode = data->defDeltaToUnicode;
data->currentMaskToUnicode = data->defMaskToUnicode;
- data->resetToDefaultToUnicode=FALSE;
+ data->resetToDefaultToUnicode=false;
}
} else {
@@ -1550,7 +1550,7 @@ _ISCII_SafeClone(const UConverter *cnv,
uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(UConverterDataISCII));
localClone->cnv.extraInfo = &localClone->mydata;
- localClone->cnv.isExtraLocal = TRUE;
+ localClone->cnv.isExtraLocal = true;
return &localClone->cnv;
}
@@ -1621,8 +1621,8 @@ static const UConverterStaticData _ISCIIStaticData={
4,
{ 0x1a, 0, 0, 0 },
0x1,
- FALSE,
- FALSE,
+ false,
+ false,
0x0,
0x0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvlat1.cpp b/thirdparty/icu4c/common/ucnvlat1.cpp
index 358bc0caa2..05aad6a0e0 100644
--- a/thirdparty/icu4c/common/ucnvlat1.cpp
+++ b/thirdparty/icu4c/common/ucnvlat1.cpp
@@ -465,7 +465,7 @@ static const UConverterStaticData _Latin1StaticData={
sizeof(UConverterStaticData),
"ISO-8859-1",
819, UCNV_IBM, UCNV_LATIN_1, 1, 1,
- { 0x1a, 0, 0, 0 }, 1, FALSE, FALSE,
+ { 0x1a, 0, 0, 0 }, 1, false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
@@ -744,7 +744,7 @@ static const UConverterStaticData _ASCIIStaticData={
sizeof(UConverterStaticData),
"US-ASCII",
367, UCNV_IBM, UCNV_US_ASCII, 1, 1,
- { 0x1a, 0, 0, 0 }, 1, FALSE, FALSE,
+ { 0x1a, 0, 0, 0 }, 1, false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvmbcs.cpp b/thirdparty/icu4c/common/ucnvmbcs.cpp
index 420aa02af5..0e753c8ffb 100644
--- a/thirdparty/icu4c/common/ucnvmbcs.cpp
+++ b/thirdparty/icu4c/common/ucnvmbcs.cpp
@@ -373,7 +373,7 @@
* @param value contains 1..4 bytes of the first byte sequence, right-aligned
* @param codePoints resulting Unicode code points, or negative if a byte sequence does
* not map to anything
- * @return TRUE to continue enumeration, FALSE to stop
+ * @return true to continue enumeration, false to stop
*/
typedef UBool U_CALLCONV
UConverterEnumToUCallback(const void *context, uint32_t value, UChar32 codePoints[32]);
@@ -514,7 +514,7 @@ static const UConverterImpl _MBCSImpl={
const UConverterSharedData _MBCSData={
sizeof(UConverterSharedData), 1,
- NULL, NULL, FALSE, TRUE, &_MBCSImpl,
+ NULL, NULL, false, true, &_MBCSImpl,
0, UCNV_MBCS_TABLE_INITIALIZER
};
@@ -668,7 +668,7 @@ enumToU(UConverterMBCSTable *mbcsTable, int8_t stateProps[],
value|(uint32_t)b,
callback, context,
pErrorCode)) {
- return FALSE;
+ return false;
}
}
codePoints[b&0x1f]=U_SENTINEL;
@@ -719,13 +719,13 @@ enumToU(UConverterMBCSTable *mbcsTable, int8_t stateProps[],
if(((++b)&0x1f)==0) {
if(anyCodePoints>=0) {
if(!callback(context, value|(uint32_t)(b-0x20), codePoints)) {
- return FALSE;
+ return false;
}
anyCodePoints=-1;
}
}
}
- return TRUE;
+ return true;
}
/*
@@ -1111,7 +1111,7 @@ _extFromU(UConverter *cnv, const UConverterSharedData *sharedData,
UErrorCode *pErrorCode) {
const int32_t *cx;
- cnv->useSubChar1=FALSE;
+ cnv->useSubChar1=false;
if( (cx=sharedData->mbcs.extIndexes)!=NULL &&
ucnv_extInitialMatchFromU(
@@ -1286,7 +1286,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
mbcsTable->stateTable[0][EBCDIC_LF]==MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_LF) &&
mbcsTable->stateTable[0][EBCDIC_NL]==MBCS_ENTRY_FINAL(0, MBCS_STATE_VALID_DIRECT_16, U_NL)
)) {
- return FALSE;
+ return false;
}
if(mbcsTable->outputType==MBCS_OUTPUT_1) {
@@ -1294,7 +1294,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
EBCDIC_RT_LF==MBCS_SINGLE_RESULT_FROM_U(table, results, U_LF) &&
EBCDIC_RT_NL==MBCS_SINGLE_RESULT_FROM_U(table, results, U_NL)
)) {
- return FALSE;
+ return false;
}
} else /* MBCS_OUTPUT_2_SISO */ {
stage2Entry=MBCS_STAGE_2_FROM_U(table, U_LF);
@@ -1302,7 +1302,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_LF)!=0 &&
EBCDIC_LF==MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_LF)
)) {
- return FALSE;
+ return false;
}
stage2Entry=MBCS_STAGE_2_FROM_U(table, U_NL);
@@ -1310,7 +1310,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
MBCS_FROM_U_IS_ROUNDTRIP(stage2Entry, U_NL)!=0 &&
EBCDIC_NL==MBCS_VALUE_2_FROM_STAGE_2(bytes, stage2Entry, U_NL)
)) {
- return FALSE;
+ return false;
}
}
@@ -1334,7 +1334,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
* ucnv_MBCSSizeofFromUBytes() function.
*/
*pErrorCode=U_INVALID_FORMAT_ERROR;
- return FALSE;
+ return false;
}
/*
@@ -1351,7 +1351,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
p=(uint8_t *)uprv_malloc(size);
if(p==NULL) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
/* copy and modify the to-Unicode state table */
@@ -1397,7 +1397,7 @@ _EBCDICSwapLFNL(UConverterSharedData *sharedData, UErrorCode *pErrorCode) {
if(newStateTable!=NULL) {
uprv_free(newStateTable);
}
- return TRUE;
+ return true;
}
/* reconstitute omitted fromUnicode data ------------------------------------ */
@@ -1477,7 +1477,7 @@ writeStage3Roundtrip(const void *context, uint32_t value, UChar32 codePoints[32]
/* set the roundtrip flag */
*stage2|=(1UL<<(16+(c&0xf)));
}
- return TRUE;
+ return true;
}
static void
@@ -1561,7 +1561,7 @@ ucnv_MBCSLoad(UConverterSharedData *sharedData,
_MBCSHeader *header=(_MBCSHeader *)raw;
uint32_t offset;
uint32_t headerLength;
- UBool noFromU=FALSE;
+ UBool noFromU=false;
if(header->version[0]==4) {
headerLength=MBCS_HEADER_V4_LENGTH;
@@ -1726,7 +1726,7 @@ ucnv_MBCSLoad(UConverterSharedData *sharedData,
}
mbcsTable->stateTable=(const int32_t (*)[256])newStateTable;
mbcsTable->countStates=(uint8_t)(count+1);
- mbcsTable->stateTableOwned=TRUE;
+ mbcsTable->stateTableOwned=true;
mbcsTable->outputType=MBCS_OUTPUT_DBCS_ONLY;
}
@@ -1805,7 +1805,7 @@ ucnv_MBCSLoad(UConverterSharedData *sharedData,
(header->version[2]>=(MBCS_FAST_MAX>>8))
)
) {
- mbcsTable->utf8Friendly=TRUE;
+ mbcsTable->utf8Friendly=true;
if(mbcsTable->countStates==1) {
/*
@@ -2411,13 +2411,13 @@ hasValidTrailBytes(const int32_t (*stateTable)[256], uint8_t state) {
if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
) {
- return TRUE;
+ return true;
}
entry=row[0x41];
if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
) {
- return TRUE;
+ return true;
}
/* Then test for final entries in this state. */
for(b=0; b<=0xff; ++b) {
@@ -2425,7 +2425,7 @@ hasValidTrailBytes(const int32_t (*stateTable)[256], uint8_t state) {
if( !MBCS_ENTRY_IS_TRANSITION(entry) &&
MBCS_ENTRY_FINAL_ACTION(entry)!=MBCS_STATE_ILLEGAL
) {
- return TRUE;
+ return true;
}
}
/* Then recurse for transition entries. */
@@ -2434,10 +2434,10 @@ hasValidTrailBytes(const int32_t (*stateTable)[256], uint8_t state) {
if( MBCS_ENTRY_IS_TRANSITION(entry) &&
hasValidTrailBytes(stateTable, (uint8_t)MBCS_ENTRY_TRANSITION_STATE(entry))
) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/*
@@ -2454,7 +2454,7 @@ isSingleOrLead(const int32_t (*stateTable)[256], uint8_t state, UBool isDBCSOnly
} else {
uint8_t action=(uint8_t)(MBCS_ENTRY_FINAL_ACTION(entry));
if(action==MBCS_STATE_CHANGE_ONLY && isDBCSOnly) {
- return FALSE; /* SI/SO are illegal for DBCS-only conversion */
+ return false; /* SI/SO are illegal for DBCS-only conversion */
} else {
return action!=MBCS_STATE_ILLEGAL;
}
@@ -5672,7 +5672,7 @@ ucnv_MBCSWriteSub(UConverterFromUnicodeArgs *pArgs,
}
/* reset the selector for the next code point */
- cnv->useSubChar1=FALSE;
+ cnv->useSubChar1=false;
if (cnv->sharedData->mbcs.outputType == MBCS_OUTPUT_2_SISO) {
p=buffer;
diff --git a/thirdparty/icu4c/common/ucnvscsu.cpp b/thirdparty/icu4c/common/ucnvscsu.cpp
index 7b580291e1..86e850a998 100644
--- a/thirdparty/icu4c/common/ucnvscsu.cpp
+++ b/thirdparty/icu4c/common/ucnvscsu.cpp
@@ -163,7 +163,7 @@ _SCSUReset(UConverter *cnv, UConverterResetChoice choice) {
/* reset toUnicode */
uprv_memcpy(scsu->toUDynamicOffsets, initialDynamicOffsets, 32);
- scsu->toUIsSingleByteMode=TRUE;
+ scsu->toUIsSingleByteMode=true;
scsu->toUState=readCommand;
scsu->toUQuoteWindow=scsu->toUDynamicWindow=0;
scsu->toUByteOne=0;
@@ -174,7 +174,7 @@ _SCSUReset(UConverter *cnv, UConverterResetChoice choice) {
/* reset fromUnicode */
uprv_memcpy(scsu->fromUDynamicOffsets, initialDynamicOffsets, 32);
- scsu->fromUIsSingleByteMode=TRUE;
+ scsu->fromUIsSingleByteMode=true;
scsu->fromUDynamicWindow=0;
scsu->nextWindowUseIndex=0;
@@ -371,7 +371,7 @@ singleByteMode:
state=quotePairOne;
} else if(b==SCU) {
sourceIndex=nextSourceIndex;
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
goto fastUnicode;
} else /* Srs */ {
/* callback(illegal) */
@@ -508,17 +508,17 @@ fastUnicode:
} else if(/* UC0<=b && */ b<=UC7) {
dynamicWindow=(int8_t)(b-UC0);
sourceIndex=nextSourceIndex;
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
goto fastSingle;
} else if(/* UD0<=b && */ b<=UD7) {
dynamicWindow=(int8_t)(b-UD0);
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
cnv->toUBytes[0]=b;
cnv->toULength=1;
state=defineOne;
goto singleByteMode;
} else if(b==UDX) {
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
cnv->toUBytes[0]=b;
cnv->toULength=1;
state=definePairOne;
@@ -695,7 +695,7 @@ singleByteMode:
} else if(b==SQU) {
state=quotePairOne;
} else if(b==SCU) {
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
goto fastUnicode;
} else /* Srs */ {
/* callback(illegal) */
@@ -805,17 +805,17 @@ fastUnicode:
state=quotePairTwo;
} else if(/* UC0<=b && */ b<=UC7) {
dynamicWindow=(int8_t)(b-UC0);
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
goto fastSingle;
} else if(/* UD0<=b && */ b<=UD7) {
dynamicWindow=(int8_t)(b-UD0);
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
cnv->toUBytes[0]=b;
cnv->toULength=1;
state=defineOne;
goto singleByteMode;
} else if(b==UDX) {
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
cnv->toUBytes[0]=b;
cnv->toULength=1;
state=definePairOne;
@@ -1159,7 +1159,7 @@ getTrailSingle:
goto outputBytes;
} else {
/* change to Unicode mode and output this (lead, trail) pair */
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
*target++=(uint8_t)SCU;
if(offsets!=NULL) {
*offsets++=sourceIndex;
@@ -1218,7 +1218,7 @@ getTrailSingle:
* switch to Unicode mode if this is the last character in the block
* or there is at least one more ideograph following immediately
*/
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
c|=SCU<<16;
length=3;
goto outputBytes;
@@ -1269,13 +1269,13 @@ getTrailSingle:
if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
/* ASCII digit or letter */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
length=2;
goto outputBytes;
} else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
/* there is a dynamic window that contains this character, change to it */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=window;
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(scsu, dynamicWindow);
@@ -1284,7 +1284,7 @@ getTrailSingle:
goto outputBytes;
} else if((code=getDynamicOffset(c, &offset))>=0) {
/* define a dynamic window with this character */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=getNextDynamicWindow(scsu);
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
useDynamicWindow(scsu, dynamicWindow);
@@ -1337,7 +1337,7 @@ getTrailUnicode:
* the following character is not uncompressible,
* change to the window
*/
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=window;
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(scsu, dynamicWindow);
@@ -1348,7 +1348,7 @@ getTrailUnicode:
(code=getDynamicOffset(c, &offset))>=0
) {
/* two supplementary characters in (probably) the same window - define an extended one */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
code-=0x200;
dynamicWindow=getNextDynamicWindow(scsu);
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
@@ -1645,7 +1645,7 @@ getTrailSingle:
goto outputBytes;
} else {
/* change to Unicode mode and output this (lead, trail) pair */
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
*target++=(uint8_t)SCU;
--targetCapacity;
c=((uint32_t)lead<<16)|trail;
@@ -1701,7 +1701,7 @@ getTrailSingle:
* switch to Unicode mode if this is the last character in the block
* or there is at least one more ideograph following immediately
*/
- isSingleByteMode=FALSE;
+ isSingleByteMode=false;
c|=SCU<<16;
length=3;
goto outputBytes;
@@ -1746,13 +1746,13 @@ getTrailSingle:
if(!(source<sourceLimit && (uint32_t)(*source-0x3400)<(0xd800-0x3400))) {
if(((uint32_t)(c-0x30)<10 || (uint32_t)(c-0x61)<26 || (uint32_t)(c-0x41)<26)) {
/* ASCII digit or letter */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
c|=((uint32_t)(UC0+dynamicWindow)<<8)|c;
length=2;
goto outputBytes;
} else if((window=getWindow(scsu->fromUDynamicOffsets, c))>=0) {
/* there is a dynamic window that contains this character, change to it */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=window;
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(scsu, dynamicWindow);
@@ -1761,7 +1761,7 @@ getTrailSingle:
goto outputBytes;
} else if((code=getDynamicOffset(c, &offset))>=0) {
/* define a dynamic window with this character */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=getNextDynamicWindow(scsu);
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
useDynamicWindow(scsu, dynamicWindow);
@@ -1813,7 +1813,7 @@ getTrailUnicode:
* the following character is not uncompressible,
* change to the window
*/
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
dynamicWindow=window;
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow];
useDynamicWindow(scsu, dynamicWindow);
@@ -1824,7 +1824,7 @@ getTrailUnicode:
(code=getDynamicOffset(c, &offset))>=0
) {
/* two supplementary characters in (probably) the same window - define an extended one */
- isSingleByteMode=TRUE;
+ isSingleByteMode=true;
code-=0x200;
dynamicWindow=getNextDynamicWindow(scsu);
currentOffset=scsu->fromUDynamicOffsets[dynamicWindow]=offset;
@@ -1991,7 +1991,7 @@ _SCSUSafeClone(const UConverter *cnv,
uprv_memcpy(&localClone->mydata, cnv->extraInfo, sizeof(SCSUData));
localClone->cnv.extraInfo = &localClone->mydata;
- localClone->cnv.isExtraLocal = TRUE;
+ localClone->cnv.isExtraLocal = true;
return &localClone->cnv;
}
@@ -2033,7 +2033,7 @@ static const UConverterStaticData _SCSUStaticData={
* substitution string.
*/
{ 0x0e, 0xff, 0xfd, 0 }, 3,
- FALSE, FALSE,
+ false, false,
0,
0,
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } /* reserved */
diff --git a/thirdparty/icu4c/common/ucnvsel.cpp b/thirdparty/icu4c/common/ucnvsel.cpp
index 2dff5ac1bc..15ee596a23 100644
--- a/thirdparty/icu4c/common/ucnvsel.cpp
+++ b/thirdparty/icu4c/common/ucnvsel.cpp
@@ -142,7 +142,7 @@ static void generateSelectorData(UConverterSelector* result,
result->trie = upvec_compactToUTrie2WithRowIndexes(upvec, status);
result->pv = upvec_cloneArray(upvec, &result->pvCount, NULL, status);
result->pvCount *= columns; // number of uint32_t = rows * columns
- result->ownPv = TRUE;
+ result->ownPv = true;
}
/* open a selector. If converterListSize is 0, build for all converters.
@@ -212,7 +212,7 @@ ucnvsel_open(const char* const* converterList, int32_t converterListSize,
--encodingStrPadding;
}
- newSelector->ownEncodingStrings = TRUE;
+ newSelector->ownEncodingStrings = true;
newSelector->encodingsCount = converterListSize;
UPropsVectors *upvec = upvec_open((converterListSize+31)/32, status);
generateSelectorData(newSelector.getAlias(), upvec, excludedCodePoints, whichSet, status);
diff --git a/thirdparty/icu4c/common/ucol_swp.cpp b/thirdparty/icu4c/common/ucol_swp.cpp
index 1af19863fa..59704ff8f6 100644
--- a/thirdparty/icu4c/common/ucol_swp.cpp
+++ b/thirdparty/icu4c/common/ucol_swp.cpp
@@ -34,7 +34,7 @@ U_CAPI UBool U_EXPORT2
ucol_looksLikeCollationBinary(const UDataSwapper *ds,
const void *inData, int32_t length) {
if(ds==NULL || inData==NULL || length<-1) {
- return FALSE;
+ return false;
}
// First check for format version 4+ which has a standard data header.
@@ -46,7 +46,7 @@ ucol_looksLikeCollationBinary(const UDataSwapper *ds,
info.dataFormat[1]==0x43 &&
info.dataFormat[2]==0x6f &&
info.dataFormat[3]==0x6c) {
- return TRUE;
+ return true;
}
}
@@ -64,7 +64,7 @@ ucol_looksLikeCollationBinary(const UDataSwapper *ds,
if(length<0) {
header.size=udata_readInt32(ds, inHeader->size);
} else if((length<(42*4) || length<(header.size=udata_readInt32(ds, inHeader->size)))) {
- return FALSE;
+ return false;
}
header.magic=ds->readUInt32(inHeader->magic);
@@ -73,14 +73,14 @@ ucol_looksLikeCollationBinary(const UDataSwapper *ds,
inHeader->formatVersion[0]==3 /*&&
inHeader->formatVersion[1]>=0*/
)) {
- return FALSE;
+ return false;
}
if(inHeader->isBigEndian!=ds->inIsBigEndian || inHeader->charSetFamily!=ds->inCharset) {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
namespace {
diff --git a/thirdparty/icu4c/common/ucptrie_impl.h b/thirdparty/icu4c/common/ucptrie_impl.h
index 048353c80d..a7a80a8f08 100644
--- a/thirdparty/icu4c/common/ucptrie_impl.h
+++ b/thirdparty/icu4c/common/ucptrie_impl.h
@@ -54,80 +54,76 @@ struct UCPTrieHeader {
uint16_t shiftedHighStart;
};
+// Constants for use with UCPTrieHeader.options.
+constexpr uint16_t UCPTRIE_OPTIONS_DATA_LENGTH_MASK = 0xf000;
+constexpr uint16_t UCPTRIE_OPTIONS_DATA_NULL_OFFSET_MASK = 0xf00;
+constexpr uint16_t UCPTRIE_OPTIONS_RESERVED_MASK = 0x38;
+constexpr uint16_t UCPTRIE_OPTIONS_VALUE_BITS_MASK = 7;
+
/**
- * Constants for use with UCPTrieHeader.options.
- * @internal
+ * Value for index3NullOffset which indicates that there is no index-3 null block.
+ * Bit 15 is unused for this value because this bit is used if the index-3 contains
+ * 18-bit indexes.
*/
-enum {
- UCPTRIE_OPTIONS_DATA_LENGTH_MASK = 0xf000,
- UCPTRIE_OPTIONS_DATA_NULL_OFFSET_MASK = 0xf00,
- UCPTRIE_OPTIONS_RESERVED_MASK = 0x38,
- UCPTRIE_OPTIONS_VALUE_BITS_MASK = 7,
- /**
- * Value for index3NullOffset which indicates that there is no index-3 null block.
- * Bit 15 is unused for this value because this bit is used if the index-3 contains
- * 18-bit indexes.
- */
- UCPTRIE_NO_INDEX3_NULL_OFFSET = 0x7fff,
- UCPTRIE_NO_DATA_NULL_OFFSET = 0xfffff
-};
+constexpr int32_t UCPTRIE_NO_INDEX3_NULL_OFFSET = 0x7fff;
+constexpr int32_t UCPTRIE_NO_DATA_NULL_OFFSET = 0xfffff;
// Internal constants.
-enum {
- /** The length of the BMP index table. 1024=0x400 */
- UCPTRIE_BMP_INDEX_LENGTH = 0x10000 >> UCPTRIE_FAST_SHIFT,
- UCPTRIE_SMALL_LIMIT = 0x1000,
- UCPTRIE_SMALL_INDEX_LENGTH = UCPTRIE_SMALL_LIMIT >> UCPTRIE_FAST_SHIFT,
+/** The length of the BMP index table. 1024=0x400 */
+constexpr int32_t UCPTRIE_BMP_INDEX_LENGTH = 0x10000 >> UCPTRIE_FAST_SHIFT;
- /** Shift size for getting the index-3 table offset. */
- UCPTRIE_SHIFT_3 = 4,
+constexpr int32_t UCPTRIE_SMALL_LIMIT = 0x1000;
+constexpr int32_t UCPTRIE_SMALL_INDEX_LENGTH = UCPTRIE_SMALL_LIMIT >> UCPTRIE_FAST_SHIFT;
- /** Shift size for getting the index-2 table offset. */
- UCPTRIE_SHIFT_2 = 5 + UCPTRIE_SHIFT_3,
+/** Shift size for getting the index-3 table offset. */
+constexpr int32_t UCPTRIE_SHIFT_3 = 4;
- /** Shift size for getting the index-1 table offset. */
- UCPTRIE_SHIFT_1 = 5 + UCPTRIE_SHIFT_2,
+/** Shift size for getting the index-2 table offset. */
+constexpr int32_t UCPTRIE_SHIFT_2 = 5 + UCPTRIE_SHIFT_3;
- /**
- * Difference between two shift sizes,
- * for getting an index-2 offset from an index-3 offset. 5=9-4
- */
- UCPTRIE_SHIFT_2_3 = UCPTRIE_SHIFT_2 - UCPTRIE_SHIFT_3,
+/** Shift size for getting the index-1 table offset. */
+constexpr int32_t UCPTRIE_SHIFT_1 = 5 + UCPTRIE_SHIFT_2;
- /**
- * Difference between two shift sizes,
- * for getting an index-1 offset from an index-2 offset. 5=14-9
- */
- UCPTRIE_SHIFT_1_2 = UCPTRIE_SHIFT_1 - UCPTRIE_SHIFT_2,
+/**
+ * Difference between two shift sizes,
+ * for getting an index-2 offset from an index-3 offset. 5=9-4
+ */
+constexpr int32_t UCPTRIE_SHIFT_2_3 = UCPTRIE_SHIFT_2 - UCPTRIE_SHIFT_3;
- /**
- * Number of index-1 entries for the BMP. (4)
- * This part of the index-1 table is omitted from the serialized form.
- */
- UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> UCPTRIE_SHIFT_1,
+/**
+ * Difference between two shift sizes,
+ * for getting an index-1 offset from an index-2 offset. 5=14-9
+ */
+constexpr int32_t UCPTRIE_SHIFT_1_2 = UCPTRIE_SHIFT_1 - UCPTRIE_SHIFT_2;
- /** Number of entries in an index-2 block. 32=0x20 */
- UCPTRIE_INDEX_2_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_1_2,
+/**
+ * Number of index-1 entries for the BMP. (4)
+ * This part of the index-1 table is omitted from the serialized form.
+ */
+constexpr int32_t UCPTRIE_OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> UCPTRIE_SHIFT_1;
- /** Mask for getting the lower bits for the in-index-2-block offset. */
- UCPTRIE_INDEX_2_MASK = UCPTRIE_INDEX_2_BLOCK_LENGTH - 1,
+/** Number of entries in an index-2 block. 32=0x20 */
+constexpr int32_t UCPTRIE_INDEX_2_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_1_2;
- /** Number of code points per index-2 table entry. 512=0x200 */
- UCPTRIE_CP_PER_INDEX_2_ENTRY = 1 << UCPTRIE_SHIFT_2,
+/** Mask for getting the lower bits for the in-index-2-block offset. */
+constexpr int32_t UCPTRIE_INDEX_2_MASK = UCPTRIE_INDEX_2_BLOCK_LENGTH - 1;
- /** Number of entries in an index-3 block. 32=0x20 */
- UCPTRIE_INDEX_3_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_2_3,
+/** Number of code points per index-2 table entry. 512=0x200 */
+constexpr int32_t UCPTRIE_CP_PER_INDEX_2_ENTRY = 1 << UCPTRIE_SHIFT_2;
- /** Mask for getting the lower bits for the in-index-3-block offset. */
- UCPTRIE_INDEX_3_MASK = UCPTRIE_INDEX_3_BLOCK_LENGTH - 1,
+/** Number of entries in an index-3 block. 32=0x20 */
+constexpr int32_t UCPTRIE_INDEX_3_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_2_3;
- /** Number of entries in a small data block. 16=0x10 */
- UCPTRIE_SMALL_DATA_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_3,
+/** Mask for getting the lower bits for the in-index-3-block offset. */
+constexpr int32_t UCPTRIE_INDEX_3_MASK = UCPTRIE_INDEX_3_BLOCK_LENGTH - 1;
+
+/** Number of entries in a small data block. 16=0x10 */
+constexpr int32_t UCPTRIE_SMALL_DATA_BLOCK_LENGTH = 1 << UCPTRIE_SHIFT_3;
+
+/** Mask for getting the lower bits for the in-small-data-block offset. */
+constexpr int32_t UCPTRIE_SMALL_DATA_MASK = UCPTRIE_SMALL_DATA_BLOCK_LENGTH - 1;
- /** Mask for getting the lower bits for the in-small-data-block offset. */
- UCPTRIE_SMALL_DATA_MASK = UCPTRIE_SMALL_DATA_BLOCK_LENGTH - 1
-};
typedef UChar32
UCPTrieGetRange(const void *trie, UChar32 start,
diff --git a/thirdparty/icu4c/common/ucurr.cpp b/thirdparty/icu4c/common/ucurr.cpp
index 6e489e0563..928d049fb5 100644
--- a/thirdparty/icu4c/common/ucurr.cpp
+++ b/thirdparty/icu4c/common/ucurr.cpp
@@ -97,11 +97,11 @@ static const char CURRENCYPLURALS[] = "CurrencyPlurals";
// ISO codes mapping table
static const UHashtable* gIsoCodes = NULL;
-static icu::UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gIsoCodesInitOnce {};
// Currency symbol equivalances
static const icu::Hashtable* gCurrSymbolsEquiv = NULL;
-static icu::UInitOnce gCurrSymbolsEquivInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCurrSymbolsEquivInitOnce {};
U_NAMESPACE_BEGIN
@@ -238,7 +238,7 @@ isoCodes_cleanup(void)
gIsoCodes = NULL;
}
gIsoCodesInitOnce.reset();
- return TRUE;
+ return true;
}
/**
@@ -250,7 +250,7 @@ currSymbolsEquiv_cleanup(void)
delete const_cast<icu::Hashtable *>(gCurrSymbolsEquiv);
gCurrSymbolsEquiv = NULL;
gCurrSymbolsEquivInitOnce.reset();
- return TRUE;
+ return true;
}
/**
@@ -349,7 +349,7 @@ _findMetaData(const UChar* currency, UErrorCode& ec) {
static void
idForLocale(const char* locale, char* countryAndVariant, int capacity, UErrorCode* ec)
{
- ulocimp_getRegionForSupplementalData(locale, FALSE, countryAndVariant, capacity, ec);
+ ulocimp_getRegionForSupplementalData(locale, false, countryAndVariant, capacity, ec);
}
// ------------------------------------------
@@ -409,7 +409,7 @@ struct CReg : public icu::UMemory {
}
static UBool unreg(UCurrRegistryKey key) {
- UBool found = FALSE;
+ UBool found = false;
umtx_lock(&gCRegLock);
CReg** p = &gCRegHead;
@@ -417,7 +417,7 @@ struct CReg : public icu::UMemory {
if (*p == key) {
*p = ((CReg*)key)->next;
delete (CReg*)key;
- found = TRUE;
+ found = true;
break;
}
p = &((*p)->next);
@@ -476,7 +476,7 @@ ucurr_unregister(UCurrRegistryKey key, UErrorCode* status)
if (status && U_SUCCESS(*status)) {
return CReg::unreg(key);
}
- return FALSE;
+ return false;
}
#endif /* UCONFIG_NO_SERVICE */
@@ -503,7 +503,7 @@ static UBool U_CALLCONV currency_cleanup(void) {
isoCodes_cleanup();
currSymbolsEquiv_cleanup();
- return TRUE;
+ return true;
}
U_CDECL_END
@@ -566,9 +566,32 @@ ucurr_forLocale(const char* locale,
UResourceBundle *rb = ures_openDirect(U_ICUDATA_CURR, CURRENCY_DATA, &localStatus);
UResourceBundle *cm = ures_getByKey(rb, CURRENCY_MAP, rb, &localStatus);
UResourceBundle *countryArray = ures_getByKey(rb, id, cm, &localStatus);
- UResourceBundle *currencyReq = ures_getByIndex(countryArray, 0, NULL, &localStatus);
- s = ures_getStringByKey(currencyReq, "id", &resLen, &localStatus);
- ures_close(currencyReq);
+ // https://unicode-org.atlassian.net/browse/ICU-21997
+ // Prefer to use currencies that are legal tender.
+ if (U_SUCCESS(localStatus)) {
+ int32_t arrayLength = ures_getSize(countryArray);
+ for (int32_t i = 0; i < arrayLength; ++i) {
+ LocalUResourceBundlePointer currencyReq(
+ ures_getByIndex(countryArray, i, nullptr, &localStatus));
+ // The currency is legal tender if it is *not* marked with tender{"false"}.
+ UErrorCode tenderStatus = localStatus;
+ const UChar *tender =
+ ures_getStringByKey(currencyReq.getAlias(), "tender", nullptr, &tenderStatus);
+ bool isTender = U_FAILURE(tenderStatus) || u_strcmp(tender, u"false") != 0;
+ if (!isTender && s != nullptr) {
+ // We already have a non-tender currency. Ignore all following non-tender ones.
+ continue;
+ }
+ // Fetch the currency code.
+ s = ures_getStringByKey(currencyReq.getAlias(), "id", &resLen, &localStatus);
+ if (isTender) {
+ break;
+ }
+ }
+ if (U_SUCCESS(localStatus) && s == nullptr) {
+ localStatus = U_MISSING_RESOURCE_ERROR;
+ }
+ }
ures_close(countryArray);
}
@@ -598,12 +621,12 @@ ucurr_forLocale(const char* locale,
* Modify the given locale name by removing the rightmost _-delimited
* element. If there is none, empty the string ("" == root).
* NOTE: The string "root" is not recognized; do not use it.
- * @return TRUE if the fallback happened; FALSE if locale is already
+ * @return true if the fallback happened; false if locale is already
* root ("").
*/
static UBool fallback(char *loc) {
if (!*loc) {
- return FALSE;
+ return false;
}
UErrorCode status = U_ZERO_ERROR;
if (uprv_strcmp(loc, "en_GB") == 0) {
@@ -623,7 +646,7 @@ static UBool fallback(char *loc) {
}
*i = 0;
*/
- return TRUE;
+ return true;
}
@@ -729,7 +752,7 @@ ucurr_getName(const UChar* currency,
// We no longer support choice format data in names. Data should not contain
// choice patterns.
if (isChoiceFormat != NULL) {
- *isChoiceFormat = FALSE;
+ *isChoiceFormat = false;
}
if (U_SUCCESS(ec2)) {
U_ASSERT(s != NULL);
@@ -896,7 +919,7 @@ getCurrencyNameCount(const char* loc, int32_t* total_currency_name_count, int32_
s = ures_getStringByIndex(names, UCURR_SYMBOL_NAME, &len, &ec2);
++(*total_currency_symbol_count); // currency symbol
if (currencySymbolsEquiv != NULL) {
- *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(TRUE, s, len));
+ *total_currency_symbol_count += countEquivalent(*currencySymbolsEquiv, UnicodeString(true, s, len));
}
++(*total_currency_symbol_count); // iso code
++(*total_currency_name_count); // long name
@@ -1017,7 +1040,7 @@ collectCurrencyNames(const char* locale,
(*currencySymbols)[(*total_currency_symbol_count)++].currencyNameLen = len;
// Add equivalent symbols
if (currencySymbolsEquiv != NULL) {
- UnicodeString str(TRUE, s, len);
+ UnicodeString str(true, s, len);
icu::EquivIterator iter(*currencySymbolsEquiv, str);
const UnicodeString *symbol;
while ((symbol = iter.next()) != NULL) {
@@ -1401,7 +1424,7 @@ currency_cache_cleanup(void) {
currCache[i] = 0;
}
}
- return TRUE;
+ return true;
}
@@ -1928,6 +1951,7 @@ static const struct CurrencyList {
{"SHP", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SIT", UCURR_COMMON|UCURR_DEPRECATED},
{"SKK", UCURR_COMMON|UCURR_DEPRECATED},
+ {"SLE", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SLL", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SOS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"SRD", UCURR_COMMON|UCURR_NON_DEPRECATED},
@@ -1965,6 +1989,7 @@ static const struct CurrencyList {
{"UYW", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"UZS", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VEB", UCURR_COMMON|UCURR_DEPRECATED},
+ {"VED", UCURR_UNCOMMON|UCURR_NON_DEPRECATED},
{"VEF", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VES", UCURR_COMMON|UCURR_NON_DEPRECATED},
{"VND", UCURR_COMMON|UCURR_NON_DEPRECATED},
@@ -2220,19 +2245,19 @@ U_CAPI UBool U_EXPORT2
ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) {
umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
if (U_FAILURE(*eErrorCode)) {
- return FALSE;
+ return false;
}
IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
if (result == NULL) {
- return FALSE;
+ return false;
} else if (from > to) {
*eErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
} else if ((from > result->to) || (to < result->from)) {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
static const icu::Hashtable* getCurrSymbolsEquiv() {
@@ -2537,7 +2562,7 @@ static const UEnumeration defaultKeywordValues = {
U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key, const char *locale, UBool commonlyUsed, UErrorCode* status) {
// Resolve region
char prefRegion[ULOC_COUNTRY_CAPACITY];
- ulocimp_getRegionForSupplementalData(locale, TRUE, prefRegion, sizeof(prefRegion), status);
+ ulocimp_getRegionForSupplementalData(locale, true, prefRegion, sizeof(prefRegion), status);
// Read value from supplementalData
UList *values = ulist_createEmptyList(status);
@@ -2570,7 +2595,7 @@ U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key,
break;
}
const char *region = ures_getKey(&bundlekey);
- UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? TRUE : FALSE;
+ UBool isPrefRegion = uprv_strcmp(region, prefRegion) == 0 ? true : false;
if (!isPrefRegion && commonlyUsed) {
// With commonlyUsed=true, we do not put
// currencies for other regions in the
@@ -2595,7 +2620,7 @@ U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key,
}
#if U_CHARSET_FAMILY==U_ASCII_FAMILY
- ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, TRUE, status);
+ ures_getUTF8StringByKey(&curbndl, "id", curID, &curIDLength, true, status);
/* optimize - use the utf-8 string */
#else
{
@@ -2613,19 +2638,19 @@ U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key,
if (U_FAILURE(*status)) {
break;
}
- UBool hasTo = FALSE;
+ UBool hasTo = false;
ures_getByKey(&curbndl, "to", &to, status);
if (U_FAILURE(*status)) {
// Do nothing here...
*status = U_ZERO_ERROR;
} else {
- hasTo = TRUE;
+ hasTo = true;
}
if (isPrefRegion && !hasTo && !ulist_containsString(values, curID, (int32_t)uprv_strlen(curID))) {
// Currently active currency for the target country
- ulist_addItemEndList(values, curID, TRUE, status);
+ ulist_addItemEndList(values, curID, true, status);
} else if (!ulist_containsString(otherValues, curID, (int32_t)uprv_strlen(curID)) && !commonlyUsed) {
- ulist_addItemEndList(otherValues, curID, TRUE, status);
+ ulist_addItemEndList(otherValues, curID, true, status);
} else {
uprv_free(curID);
}
@@ -2638,7 +2663,7 @@ U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key,
// This could happen if no valid region is supplied in the input
// locale. In this case, we use the CLDR's default.
uenum_close(en);
- en = ucurr_getKeywordValuesForLocale(key, "und", TRUE, status);
+ en = ucurr_getKeywordValuesForLocale(key, "und", true, status);
}
} else {
// Consolidate the list
@@ -2648,7 +2673,7 @@ U_CAPI UEnumeration *U_EXPORT2 ucurr_getKeywordValuesForLocale(const char *key,
if (!ulist_containsString(values, value, (int32_t)uprv_strlen(value))) {
char *tmpValue = (char *)uprv_malloc(sizeof(char) * ULOC_KEYWORDS_CAPACITY);
uprv_memcpy(tmpValue, value, uprv_strlen(value) + 1);
- ulist_addItemEndList(values, tmpValue, TRUE, status);
+ ulist_addItemEndList(values, tmpValue, true, status);
if (U_FAILURE(*status)) {
break;
}
diff --git a/thirdparty/icu4c/common/udata.cpp b/thirdparty/icu4c/common/udata.cpp
index ec9c999cea..2bc74c9789 100644
--- a/thirdparty/icu4c/common/udata.cpp
+++ b/thirdparty/icu4c/common/udata.cpp
@@ -106,10 +106,10 @@ static UDataMemory *udata_findCachedData(const char *path, UErrorCode &err);
*/
static UDataMemory *gCommonICUDataArray[10] = { NULL }; // Access protected by icu global mutex.
-static u_atomic_int32_t gHaveTriedToLoadCommonData = ATOMIC_INT32_T_INITIALIZER(0); // See extendICUData().
+static u_atomic_int32_t gHaveTriedToLoadCommonData {0}; // See extendICUData().
static UHashtable *gCommonDataCache = NULL; /* Global hash table of opened ICU data files. */
-static icu::UInitOnce gCommonDataCacheInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCommonDataCacheInitOnce {};
#if !defined(ICU_DATA_DIR_WINDOWS)
static UDataFileAccess gDataFileAccess = UDATA_DEFAULT_ACCESS; // Access not synchronized.
@@ -136,25 +136,25 @@ udata_cleanup(void)
}
gHaveTriedToLoadCommonData = 0;
- return TRUE; /* Everything was cleaned up */
+ return true; /* Everything was cleaned up */
}
static UBool U_CALLCONV
findCommonICUDataByName(const char *inBasename, UErrorCode &err)
{
- UBool found = FALSE;
+ UBool found = false;
int32_t i;
UDataMemory *pData = udata_findCachedData(inBasename, err);
if (U_FAILURE(err) || pData == NULL)
- return FALSE;
+ return false;
{
Mutex lock;
for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) {
if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHeader == pData->pHeader)) {
/* The data pointer is already in the array. */
- found = TRUE;
+ found = true;
break;
}
}
@@ -174,9 +174,9 @@ setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to ca
{
UDataMemory *newCommonData = UDataMemory_createNewInstance(pErr);
int32_t i;
- UBool didUpdate = FALSE;
+ UBool didUpdate = false;
if (U_FAILURE(*pErr)) {
- return FALSE;
+ return false;
}
/* For the assignment, other threads must cleanly see either the old */
@@ -188,7 +188,7 @@ setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to ca
for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) {
if (gCommonICUDataArray[i] == NULL) {
gCommonICUDataArray[i] = newCommonData;
- didUpdate = TRUE;
+ didUpdate = true;
break;
} else if (gCommonICUDataArray[i]->pHeader == pData->pHeader) {
/* The same data pointer is already in the array. */
@@ -216,7 +216,7 @@ setCommonICUDataPointer(const void *pData, UBool /*warn*/, UErrorCode *pErrorCod
UDataMemory_init(&tData);
UDataMemory_setData(&tData, pData);
udata_checkCommonData(&tData, pErrorCode);
- return setCommonICUData(&tData, FALSE, pErrorCode);
+ return setCommonICUData(&tData, false, pErrorCode);
}
#endif
@@ -429,7 +429,7 @@ private:
CharString pathBuffer; /* output path for this it'ion */
CharString packageStub; /* example: "/icudt28b". Will ignore that leaf in set paths. */
- UBool checkLastFour; /* if TRUE then allow paths such as '/foo/myapp.dat'
+ UBool checkLastFour; /* if true then allow paths such as '/foo/myapp.dat'
* to match, checks last 4 chars of suffix with
* last 4 of path, then previous chars. */
};
@@ -501,7 +501,7 @@ UDataPathIterator::UDataPathIterator(const char *inPath, const char *pkg,
suffix.data(),
itemPath.data(),
nextPath,
- checkLastFour?"TRUE":"false");
+ checkLastFour?"true":"false");
#endif
}
@@ -568,7 +568,7 @@ const char *UDataPathIterator::next(UErrorCode *pErrorCode)
/* check for .dat files */
pathBasename = findBasename(pathBuffer.data());
- if(checkLastFour == TRUE &&
+ if(checkLastFour == true &&
(pathLen>=4) &&
uprv_strncmp(pathBuffer.data() +(pathLen-4), suffix.data(), 4)==0 && /* suffix matches */
uprv_strncmp(findBasename(pathBuffer.data()), basename, basenameLen)==0 && /* base matches */
@@ -711,15 +711,15 @@ openCommonData(const char *path, /* Path from OpenChoice? */
*/
/*
if (uprv_getICUData_collation) {
- setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCode);
+ setCommonICUDataPointer(uprv_getICUData_collation(), false, pErrorCode);
}
if (uprv_getICUData_conversion) {
- setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorCode);
+ setCommonICUDataPointer(uprv_getICUData_conversion(), false, pErrorCode);
}
*/
#if !defined(ICU_DATA_DIR_WINDOWS)
// When using the Windows system data, we expect only a single data file.
- setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode);
+ setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, false, pErrorCode);
{
Mutex lock;
return gCommonICUDataArray[commonDataIndex];
@@ -761,9 +761,9 @@ openCommonData(const char *path, /* Path from OpenChoice? */
* Hunt it down, trying all the path locations
*/
- UDataPathIterator iter(u_getDataDirectory(), inBasename, path, ".dat", TRUE, pErrorCode);
+ UDataPathIterator iter(u_getDataDirectory(), inBasename, path, ".dat", true, pErrorCode);
- while ((UDataMemory_isLoaded(&tData)==FALSE) && (pathBuffer = iter.next(pErrorCode)) != NULL)
+ while ((UDataMemory_isLoaded(&tData)==false) && (pathBuffer = iter.next(pErrorCode)) != NULL)
{
#ifdef UDATA_DEBUG
fprintf(stderr, "ocd: trying path %s - ", pathBuffer);
@@ -822,7 +822,7 @@ static UBool extendICUData(UErrorCode *pErr)
{
UDataMemory *pData;
UDataMemory copyPData;
- UBool didUpdate = FALSE;
+ UBool didUpdate = false;
/*
* There is a chance for a race condition here.
@@ -859,7 +859,7 @@ static UBool extendICUData(UErrorCode *pErr)
didUpdate = /* no longer using this result */
setCommonICUData(&copyPData,/* The new common data. */
- FALSE, /* No warnings if write didn't happen */
+ false, /* No warnings if write didn't happen */
pErr); /* setCommonICUData honors errors; NOP if error set */
}
@@ -906,7 +906,7 @@ udata_setCommonData(const void *data, UErrorCode *pErrorCode) {
/* we have good data */
/* Set it up as the ICU Common Data. */
- setCommonICUData(&dataMemory, TRUE, pErrorCode);
+ setCommonICUData(&dataMemory, true, pErrorCode);
}
/*---------------------------------------------------------------------------
@@ -999,7 +999,7 @@ static UDataMemory *doLoadFromIndividualFiles(const char *pkgName,
/* look in ind. files: package\nam.typ ========================= */
/* init path iterator for individual files */
- UDataPathIterator iter(dataPath, pkgName, path, tocEntryPathSuffix, FALSE, pErrorCode);
+ UDataPathIterator iter(dataPath, pkgName, path, tocEntryPathSuffix, false, pErrorCode);
while ((pathBuffer = iter.next(pErrorCode)) != NULL)
{
@@ -1055,7 +1055,7 @@ static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName
const DataHeader *pHeader;
UDataMemory *pCommonData;
int32_t commonDataIndex;
- UBool checkedExtendedICUData = FALSE;
+ UBool checkedExtendedICUData = false;
/* try to get common data. The loop is for platforms such as the 390 that do
* not initially load the full set of ICU data. If the lookup of an ICU data item
* fails, the full (but slower to load) set is loaded, the and the loop repeats,
@@ -1104,7 +1104,7 @@ static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName
} else if (pCommonData != NULL) {
++commonDataIndex; /* try the next data package */
} else if ((!checkedExtendedICUData) && extendICUData(subErrorCode)) {
- checkedExtendedICUData = TRUE;
+ checkedExtendedICUData = true;
/* try this data package slot again: it changed from NULL to non-NULL */
} else {
return NULL;
@@ -1169,7 +1169,7 @@ doOpenChoice(const char *path, const char *type, const char *name,
UErrorCode subErrorCode=U_ZERO_ERROR;
const char *treeChar;
- UBool isICUData = FALSE;
+ UBool isICUData = false;
FileTracer::traceOpen(path, type, name);
@@ -1182,7 +1182,7 @@ doOpenChoice(const char *path, const char *type, const char *name,
uprv_strlen(U_ICUDATA_NAME U_TREE_SEPARATOR_STRING)) ||
!uprv_strncmp(path, U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING, /* "ICUDATA-" */
uprv_strlen(U_ICUDATA_ALIAS U_TREE_SEPARATOR_STRING))) {
- isICUData = TRUE;
+ isICUData = true;
}
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR) /* Windows: try "foo\bar" and "foo/bar" */
diff --git a/thirdparty/icu4c/common/udatamem.cpp b/thirdparty/icu4c/common/udatamem.cpp
index 6bf7c01235..0f80de28eb 100644
--- a/thirdparty/icu4c/common/udatamem.cpp
+++ b/thirdparty/icu4c/common/udatamem.cpp
@@ -49,7 +49,7 @@ U_CFUNC UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr) {
*pErr = U_MEMORY_ALLOCATION_ERROR; }
else {
UDataMemory_init(This);
- This->heapAllocated = TRUE;
+ This->heapAllocated = true;
}
return This;
}
diff --git a/thirdparty/icu4c/common/udatamem.h b/thirdparty/icu4c/common/udatamem.h
index a05dd69756..3db2af43aa 100644
--- a/thirdparty/icu4c/common/udatamem.h
+++ b/thirdparty/icu4c/common/udatamem.h
@@ -44,7 +44,7 @@ struct UDataMemory {
int32_t length; /* Length of the data in bytes; -1 if unknown. */
};
-U_CFUNC UDataMemory *UDataMemory_createNewInstance(UErrorCode *pErr);
+U_CAPI UDataMemory* U_EXPORT2 UDataMemory_createNewInstance(UErrorCode *pErr);
U_CFUNC void UDatamemory_assign (UDataMemory *dest, UDataMemory *source);
U_CFUNC void UDataMemory_init (UDataMemory *This);
U_CFUNC UBool UDataMemory_isLoaded(const UDataMemory *This);
diff --git a/thirdparty/icu4c/common/uhash.cpp b/thirdparty/icu4c/common/uhash.cpp
index 2e331b7172..a04f9606c5 100644
--- a/thirdparty/icu4c/common/uhash.cpp
+++ b/thirdparty/icu4c/common/uhash.cpp
@@ -265,7 +265,7 @@ _uhash_init(UHashtable *result,
result->valueComparator = valueComp;
result->keyDeleter = NULL;
result->valueDeleter = NULL;
- result->allocated = FALSE;
+ result->allocated = false;
_uhash_internalSetResizePolicy(result, U_GROW);
_uhash_allocate(result, primeIndex, status);
@@ -294,7 +294,7 @@ _uhash_create(UHashFunction *keyHash,
}
_uhash_init(result, keyHash, keyComp, valueComp, primeIndex, status);
- result->allocated = TRUE;
+ result->allocated = true;
if (U_FAILURE(*status)) {
uprv_free(result);
@@ -949,7 +949,7 @@ uhash_equals(const UHashtable* hash1, const UHashtable* hash2){
int32_t count1, count2, pos, i;
if(hash1==hash2){
- return TRUE;
+ return true;
}
/*
@@ -967,15 +967,15 @@ uhash_equals(const UHashtable* hash1, const UHashtable* hash2){
{
/*
Normally we would return an error here about incompatible hash tables,
- but we return FALSE instead.
+ but we return false instead.
*/
- return FALSE;
+ return false;
}
count1 = uhash_count(hash1);
count2 = uhash_count(hash2);
if(count1!=count2){
- return FALSE;
+ return false;
}
pos=UHASH_FIRST;
@@ -989,11 +989,11 @@ uhash_equals(const UHashtable* hash1, const UHashtable* hash2){
*/
const UHashElement* elem2 = _uhash_find(hash2, key1, hash2->keyHasher(key1));
const UHashTok val2 = elem2->value;
- if(hash1->valueComparator(val1, val2)==FALSE){
- return FALSE;
+ if(hash1->valueComparator(val1, val2)==false){
+ return false;
}
}
- return TRUE;
+ return true;
}
/********************************************************************
@@ -1005,10 +1005,10 @@ uhash_compareUChars(const UHashTok key1, const UHashTok key2) {
const UChar *p1 = (const UChar*) key1.pointer;
const UChar *p2 = (const UChar*) key2.pointer;
if (p1 == p2) {
- return TRUE;
+ return true;
}
if (p1 == NULL || p2 == NULL) {
- return FALSE;
+ return false;
}
while (*p1 != 0 && *p1 == *p2) {
++p1;
@@ -1022,10 +1022,10 @@ uhash_compareChars(const UHashTok key1, const UHashTok key2) {
const char *p1 = (const char*) key1.pointer;
const char *p2 = (const char*) key2.pointer;
if (p1 == p2) {
- return TRUE;
+ return true;
}
if (p1 == NULL || p2 == NULL) {
- return FALSE;
+ return false;
}
while (*p1 != 0 && *p1 == *p2) {
++p1;
@@ -1039,10 +1039,10 @@ uhash_compareIChars(const UHashTok key1, const UHashTok key2) {
const char *p1 = (const char*) key1.pointer;
const char *p2 = (const char*) key2.pointer;
if (p1 == p2) {
- return TRUE;
+ return true;
}
if (p1 == NULL || p2 == NULL) {
- return FALSE;
+ return false;
}
while (*p1 != 0 && uprv_tolower(*p1) == uprv_tolower(*p2)) {
++p1;
diff --git a/thirdparty/icu4c/common/uidna.cpp b/thirdparty/icu4c/common/uidna.cpp
index ac2f9c3c8c..1cbdeec327 100644
--- a/thirdparty/icu4c/common/uidna.cpp
+++ b/thirdparty/icu4c/common/uidna.cpp
@@ -58,15 +58,15 @@ toASCIILower(UChar ch){
inline static UBool
startsWithPrefix(const UChar* src , int32_t srcLength){
if(srcLength < ACE_PREFIX_LENGTH){
- return FALSE;
+ return false;
}
for(int8_t i=0; i< ACE_PREFIX_LENGTH; i++){
if(toASCIILower(src[i]) != ACE_PREFIX[i]){
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
@@ -132,9 +132,9 @@ static inline UBool isLabelSeparator(UChar ch){
case 0x3002:
case 0xFF0E:
case 0xFF61:
- return TRUE;
+ return true;
default:
- return FALSE;
+ return false;
}
}
@@ -149,7 +149,7 @@ getNextSeparator(UChar *src, int32_t srcLength,
for(i=0 ; ;i++){
if(src[i] == 0){
*limit = src + i; // point to null
- *done = TRUE;
+ *done = true;
return i;
}
if(isLabelSeparator(src[i])){
@@ -169,7 +169,7 @@ getNextSeparator(UChar *src, int32_t srcLength,
// we have not found the delimiter
// if(i==srcLength)
*limit = src+srcLength;
- *done = TRUE;
+ *done = true;
return i;
}
@@ -177,7 +177,7 @@ getNextSeparator(UChar *src, int32_t srcLength,
static inline UBool isLDHChar(UChar ch){
// high runner case
if(ch>0x007A){
- return FALSE;
+ return false;
}
//[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A]
if( (ch==0x002D) ||
@@ -185,9 +185,9 @@ static inline UBool isLDHChar(UChar ch){
(0x0041 <= ch && ch <= 0x005A) ||
(0x0061 <= ch && ch <= 0x007A)
){
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static int32_t
@@ -212,9 +212,9 @@ _internal_toASCII(const UChar* src, int32_t srcLength,
UBool* caseFlags = NULL;
// the source contains all ascii codepoints
- UBool srcIsASCII = TRUE;
+ UBool srcIsASCII = true;
// assume the source contains all LDH codepoints
- UBool srcIsLDH = TRUE;
+ UBool srcIsLDH = true;
int32_t j=0;
@@ -239,13 +239,13 @@ _internal_toASCII(const UChar* src, int32_t srcLength,
// step 1
for( j=0;j<srcLength;j++){
if(src[j] > 0x7F){
- srcIsASCII = FALSE;
+ srcIsASCII = false;
}
b1[b1Len++] = src[j];
}
// step 2 is performed only if the source contains non ASCII
- if(srcIsASCII == FALSE){
+ if(srcIsASCII == false){
// step 2
b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
@@ -277,29 +277,29 @@ _internal_toASCII(const UChar* src, int32_t srcLength,
}
// for step 3 & 4
- srcIsASCII = TRUE;
+ srcIsASCII = true;
for( j=0;j<b1Len;j++){
// check if output of usprep_prepare is all ASCII
if(b1[j] > 0x7F){
- srcIsASCII = FALSE;
- }else if(isLDHChar(b1[j])==FALSE){ // if the char is in ASCII range verify that it is an LDH character
- srcIsLDH = FALSE;
+ srcIsASCII = false;
+ }else if(isLDHChar(b1[j])==false){ // if the char is in ASCII range verify that it is an LDH character
+ srcIsLDH = false;
failPos = j;
}
}
- if(useSTD3ASCIIRules == TRUE){
+ if(useSTD3ASCIIRules == true){
// verify 3a and 3b
// 3(a) Verify the absence of non-LDH ASCII code points; that is, the
// absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
// 3(b) Verify the absence of leading and trailing hyphen-minus; that
// is, the absence of U+002D at the beginning and end of the
// sequence.
- if( srcIsLDH == FALSE /* source at this point should not contain anyLDH characters */
+ if( srcIsLDH == false /* source at this point should not contain anyLDH characters */
|| b1[0] == HYPHEN || b1[b1Len-1] == HYPHEN){
*status = U_IDNA_STD3_ASCII_RULES_ERROR;
/* populate the parseError struct */
- if(srcIsLDH==FALSE){
+ if(srcIsLDH==false){
// failPos is always set the index of failure
uprv_syntaxError(b1,failPos, b1Len,parseError);
}else if(b1[0] == HYPHEN){
@@ -331,7 +331,7 @@ _internal_toASCII(const UChar* src, int32_t srcLength,
// do not preserve the case flags for now!
// TODO: Preserve the case while implementing the RFE
// caseFlags = (UBool*) uprv_malloc(b1Len * sizeof(UBool));
- // uprv_memset(caseFlags,TRUE,b1Len);
+ // uprv_memset(caseFlags,true,b1Len);
b2Len = u_strToPunycode(b1,b1Len,b2,b2Capacity,caseFlags, status);
@@ -416,8 +416,8 @@ _internal_toUnicode(const UChar* src, int32_t srcLength,
UBool* caseFlags = NULL;
- UBool srcIsASCII = TRUE;
- /*UBool srcIsLDH = TRUE;
+ UBool srcIsASCII = true;
+ /*UBool srcIsLDH = true;
int32_t failPos =0;*/
// step 1: find out if all the codepoints in src are ASCII
@@ -425,12 +425,12 @@ _internal_toUnicode(const UChar* src, int32_t srcLength,
srcLength = 0;
for(;src[srcLength]!=0;){
if(src[srcLength]> 0x7f){
- srcIsASCII = FALSE;
- }/*else if(isLDHChar(src[srcLength])==FALSE){
+ srcIsASCII = false;
+ }/*else if(isLDHChar(src[srcLength])==false){
// here we do not assemble surrogates
// since we know that LDH code points
// are in the ASCII range only
- srcIsLDH = FALSE;
+ srcIsLDH = false;
failPos = srcLength;
}*/
srcLength++;
@@ -438,13 +438,13 @@ _internal_toUnicode(const UChar* src, int32_t srcLength,
}else if(srcLength > 0){
for(int32_t j=0; j<srcLength; j++){
if(src[j]> 0x7f){
- srcIsASCII = FALSE;
+ srcIsASCII = false;
break;
- }/*else if(isLDHChar(src[j])==FALSE){
+ }/*else if(isLDHChar(src[j])==false){
// here we do not assemble surrogates
// since we know that LDH code points
// are in the ASCII range only
- srcIsLDH = FALSE;
+ srcIsLDH = false;
failPos = j;
}*/
}
@@ -452,7 +452,7 @@ _internal_toUnicode(const UChar* src, int32_t srcLength,
return 0;
}
- if(srcIsASCII == FALSE){
+ if(srcIsASCII == false){
// step 2: process the string
b1Len = usprep_prepare(nameprep, src, srcLength, b1, b1Capacity, namePrepOptions, parseError, status);
if(*status == U_BUFFER_OVERFLOW_ERROR){
@@ -548,13 +548,13 @@ _internal_toUnicode(const UChar* src, int32_t srcLength,
else{
// See the start of this if statement for why this is commented out.
// verify that STD3 ASCII rules are satisfied
- /*if(useSTD3ASCIIRules == TRUE){
- if( srcIsLDH == FALSE // source contains some non-LDH characters
+ /*if(useSTD3ASCIIRules == true){
+ if( srcIsLDH == false // source contains some non-LDH characters
|| src[0] == HYPHEN || src[srcLength-1] == HYPHEN){
*status = U_IDNA_STD3_ASCII_RULES_ERROR;
// populate the parseError struct
- if(srcIsLDH==FALSE){
+ if(srcIsLDH==false){
// failPos is always set the index of failure
uprv_syntaxError(src,failPos, srcLength,parseError);
}else if(src[0] == HYPHEN){
@@ -695,7 +695,7 @@ uidna_IDNToASCII( const UChar *src, int32_t srcLength,
int32_t remainingLen = srcLength;
int32_t remainingDestCapacity = destCapacity;
int32_t labelLen = 0, labelReqLength = 0;
- UBool done = FALSE;
+ UBool done = false;
for(;;){
@@ -731,7 +731,7 @@ uidna_IDNToASCII( const UChar *src, int32_t srcLength,
remainingDestCapacity = 0;
}
- if(done == TRUE){
+ if(done == true){
break;
}
@@ -788,7 +788,7 @@ uidna_IDNToUnicode( const UChar* src, int32_t srcLength,
int32_t remainingLen = srcLength;
int32_t remainingDestCapacity = destCapacity;
int32_t labelLen = 0, labelReqLength = 0;
- UBool done = FALSE;
+ UBool done = false;
for(;;){
@@ -800,7 +800,7 @@ uidna_IDNToUnicode( const UChar* src, int32_t srcLength,
// is returned immediately in that step.
// </quote>
// _internal_toUnicode will copy the label.
- /*if(labelLen==0 && done==FALSE){
+ /*if(labelLen==0 && done==false){
*status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
break;
}*/
@@ -829,7 +829,7 @@ uidna_IDNToUnicode( const UChar* src, int32_t srcLength,
remainingDestCapacity = 0;
}
- if(done == TRUE){
+ if(done == true){
break;
}
diff --git a/thirdparty/icu4c/common/uinit.cpp b/thirdparty/icu4c/common/uinit.cpp
index 624431be02..dc3867b17e 100644
--- a/thirdparty/icu4c/common/uinit.cpp
+++ b/thirdparty/icu4c/common/uinit.cpp
@@ -26,11 +26,11 @@
U_NAMESPACE_BEGIN
-static UInitOnce gICUInitOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gICUInitOnce {};
static UBool U_CALLCONV uinit_cleanup() {
gICUInitOnce.reset();
- return TRUE;
+ return true;
}
static void U_CALLCONV
diff --git a/thirdparty/icu4c/common/uinvchar.cpp b/thirdparty/icu4c/common/uinvchar.cpp
index 52b8906568..ffce3ec158 100644
--- a/thirdparty/icu4c/common/uinvchar.cpp
+++ b/thirdparty/icu4c/common/uinvchar.cpp
@@ -207,7 +207,7 @@ u_UCharsToChars(const UChar *us, char *cs, int32_t length) {
while(length>0) {
u=*us++;
if(!UCHAR_IS_INVARIANT(u)) {
- U_ASSERT(FALSE); /* Variant characters were used. These are not portable in ICU. */
+ U_ASSERT(false); /* Variant characters were used. These are not portable in ICU. */
u=0;
}
*cs++=(char)UCHAR_TO_CHAR(u);
@@ -245,18 +245,18 @@ uprv_isInvariantString(const char *s, int32_t length) {
*/
#if U_CHARSET_FAMILY==U_ASCII_FAMILY
if(!UCHAR_IS_INVARIANT(c)) {
- return FALSE; /* found a variant char */
+ return false; /* found a variant char */
}
#elif U_CHARSET_FAMILY==U_EBCDIC_FAMILY
c=CHAR_TO_UCHAR(c);
if(c==0 || !UCHAR_IS_INVARIANT(c)) {
- return FALSE; /* found a variant char */
+ return false; /* found a variant char */
}
#else
# error U_CHARSET_FAMILY is not valid
#endif
}
- return TRUE;
+ return true;
}
U_CAPI UBool U_EXPORT2
@@ -284,10 +284,10 @@ uprv_isInvariantUString(const UChar *s, int32_t length) {
* for strings with variant characters
*/
if(!UCHAR_IS_INVARIANT(c)) {
- return FALSE; /* found a variant char */
+ return false; /* found a variant char */
}
}
- return TRUE;
+ return true;
}
/* UDataSwapFn implementations used in udataswp.c ------- */
diff --git a/thirdparty/icu4c/common/uiter.cpp b/thirdparty/icu4c/common/uiter.cpp
index b9252d81c2..c4ab7d6d56 100644
--- a/thirdparty/icu4c/common/uiter.cpp
+++ b/thirdparty/icu4c/common/uiter.cpp
@@ -47,7 +47,7 @@ noopMove(UCharIterator * /*iter*/, int32_t /*delta*/, UCharIteratorOrigin /*orig
static UBool U_CALLCONV
noopHasNext(UCharIterator * /*iter*/) {
- return FALSE;
+ return false;
}
static UChar32 U_CALLCONV
@@ -678,24 +678,24 @@ utf8IteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin)
case UITER_ZERO:
case UITER_START:
pos=delta;
- havePos=TRUE;
+ havePos=true;
/* iter->index<0 (unknown) is possible */
break;
case UITER_CURRENT:
if(iter->index>=0) {
pos=iter->index+delta;
- havePos=TRUE;
+ havePos=true;
} else {
/* the current UTF-16 index is unknown after setState(), use only delta */
pos=0;
- havePos=FALSE;
+ havePos=false;
}
break;
case UITER_LIMIT:
case UITER_LENGTH:
if(iter->length>=0) {
pos=iter->length+delta;
- havePos=TRUE;
+ havePos=true;
} else {
/* pin to the end, avoid counting the length */
iter->index=-1;
@@ -706,7 +706,7 @@ utf8IteratorMove(UCharIterator *iter, int32_t delta, UCharIteratorOrigin origin)
} else {
/* the current UTF-16 index is unknown, use only delta */
pos=0;
- havePos=FALSE;
+ havePos=false;
}
}
break;
diff --git a/thirdparty/icu4c/common/ulist.cpp b/thirdparty/icu4c/common/ulist.cpp
index c5180431c3..57344715de 100644
--- a/thirdparty/icu4c/common/ulist.cpp
+++ b/thirdparty/icu4c/common/ulist.cpp
@@ -160,12 +160,12 @@ U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data,
for (pointer = list->head; pointer != NULL; pointer = pointer->next) {
if (length == (int32_t)uprv_strlen((const char *)pointer->data)) {
if (uprv_memcmp(data, pointer->data, length) == 0) {
- return TRUE;
+ return true;
}
}
}
}
- return FALSE;
+ return false;
}
U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data) {
@@ -175,11 +175,11 @@ U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data) {
if (uprv_strcmp(data, (const char *)pointer->data) == 0) {
ulist_removeItem(list, pointer);
// Remove only the first occurrence, like Java LinkedList.remove(Object).
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
U_CAPI void *U_EXPORT2 ulist_getNext(UList *list) {
diff --git a/thirdparty/icu4c/common/uloc.cpp b/thirdparty/icu4c/common/uloc.cpp
index 99c6a0af39..1da2abc361 100644
--- a/thirdparty/icu4c/common/uloc.cpp
+++ b/thirdparty/icu4c/common/uloc.cpp
@@ -102,7 +102,7 @@ static const char * const LANGUAGES[] = {
"asa", "ase", "ast", "av", "avk", "awa", "ay", "az",
"ba", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj",
"be", "bej", "bem", "bew", "bez", "bfd", "bfq", "bg",
- "bgn", "bho", "bi", "bik", "bin", "bjn", "bkm", "bla",
+ "bgc", "bgn", "bho", "bi", "bik", "bin", "bjn", "bkm", "bla",
"bm", "bn", "bo", "bpy", "bqi", "br", "bra", "brh",
"brx", "bs", "bss", "bua", "bug", "bum", "byn", "byv",
"ca", "cad", "car", "cay", "cch", "ccp", "ce", "ceb", "cgg",
@@ -219,7 +219,7 @@ static const char * const LANGUAGES_3[] = {
"asa", "ase", "ast", "ava", "avk", "awa", "aym", "aze",
"bak", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj",
"bel", "bej", "bem", "bew", "bez", "bfd", "bfq", "bul",
- "bgn", "bho", "bis", "bik", "bin", "bjn", "bkm", "bla",
+ "bgc", "bgn", "bho", "bis", "bik", "bin", "bjn", "bkm", "bla",
"bam", "ben", "bod", "bpy", "bqi", "bre", "bra", "brh",
"brx", "bos", "bss", "bua", "bug", "bum", "byn", "byv",
"cat", "cad", "car", "cay", "cch", "ccp", "che", "ceb", "cgg",
@@ -502,20 +502,20 @@ static int32_t getShortestSubtagLength(const char *localeID) {
int32_t length = localeIDLength;
int32_t tmpLength = 0;
int32_t i;
- UBool reset = TRUE;
+ UBool reset = true;
for (i = 0; i < localeIDLength; i++) {
if (localeID[i] != '_' && localeID[i] != '-') {
if (reset) {
tmpLength = 0;
- reset = FALSE;
+ reset = false;
}
tmpLength++;
} else {
if (tmpLength != 0 && tmpLength < length) {
length = tmpLength;
}
- reset = TRUE;
+ reset = true;
}
}
@@ -620,7 +620,7 @@ ulocimp_getKeywords(const char *localeID,
if(prev == '@') { /* start of keyword definition */
/* we will grab pairs, trim spaces, lowercase keywords, sort and return */
do {
- UBool duplicate = FALSE;
+ UBool duplicate = false;
/* skip leading spaces */
while(*pos == ' ') {
pos++;
@@ -693,7 +693,7 @@ ulocimp_getKeywords(const char *localeID,
/* If this is a duplicate keyword, then ignore it */
for (j=0; j<numKeywords; ++j) {
if (uprv_strcmp(keywordList[j].keyword, keywordList[numKeywords].keyword) == 0) {
- duplicate = TRUE;
+ duplicate = true;
break;
}
}
@@ -704,7 +704,7 @@ ulocimp_getKeywords(const char *localeID,
/* now we have a list of keywords */
/* we need to sort it */
- uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
+ uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, false, status);
/* Now construct the keyword part */
for(i = 0; i < numKeywords; i++) {
@@ -881,7 +881,7 @@ uloc_setKeywordValue(const char* keywordName,
char* startSearchHere = NULL;
char* keywordStart = NULL;
CharString updatedKeysAndValues;
- UBool handledInputKeyAndValue = FALSE;
+ UBool handledInputKeyAndValue = false;
char keyValuePrefix = '@';
if(U_FAILURE(*status)) {
@@ -1020,7 +1020,7 @@ uloc_setKeywordValue(const char* keywordName,
updatedKeysAndValues.append('=', *status);
updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
} /* else removing this entry, don't emit anything */
- handledInputKeyAndValue = TRUE;
+ handledInputKeyAndValue = true;
} else {
/* input keyword sorts earlier than current entry, add before current entry */
if (rc < 0 && keywordValueLen > 0 && !handledInputKeyAndValue) {
@@ -1030,7 +1030,7 @@ uloc_setKeywordValue(const char* keywordName,
updatedKeysAndValues.append(keywordNameBuffer, keywordNameLen, *status);
updatedKeysAndValues.append('=', *status);
updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
- handledInputKeyAndValue = TRUE;
+ handledInputKeyAndValue = true;
}
/* copy the current entry */
updatedKeysAndValues.append(keyValuePrefix, *status);
@@ -1046,7 +1046,7 @@ uloc_setKeywordValue(const char* keywordName,
updatedKeysAndValues.append(keywordNameBuffer, keywordNameLen, *status);
updatedKeysAndValues.append('=', *status);
updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
- handledInputKeyAndValue = TRUE;
+ handledInputKeyAndValue = true;
}
keywordStart = nextSeparator;
} /* end loop searching */
@@ -1089,7 +1089,7 @@ uloc_setKeywordValue(const char* keywordName,
#define _isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
-/*returns TRUE if one of the special prefixes is here (s=string)
+/*returns true if one of the special prefixes is here (s=string)
'x-' or 'i-' */
#define _isIDPrefix(s) (_isPrefixLetter(s[0])&&_isIDSeparator(s[1]))
@@ -1270,7 +1270,7 @@ _getVariant(const char *localeID,
char prev,
ByteSink& sink,
UBool needSeparator) {
- UBool hasVariant = FALSE;
+ UBool hasVariant = false;
/* get one or more variant tags and separate them with '_' */
if(_isIDSeparator(prev)) {
@@ -1278,12 +1278,12 @@ _getVariant(const char *localeID,
while(!_isTerminator(*localeID)) {
if (needSeparator) {
sink.Append("_", 1);
- needSeparator = FALSE;
+ needSeparator = false;
}
char c = (char)uprv_toupper(*localeID);
if (c == '-') c = '_';
sink.Append(&c, 1);
- hasVariant = TRUE;
+ hasVariant = true;
localeID++;
}
}
@@ -1300,7 +1300,7 @@ _getVariant(const char *localeID,
while(!_isTerminator(*localeID)) {
if (needSeparator) {
sink.Append("_", 1);
- needSeparator = FALSE;
+ needSeparator = false;
}
char c = (char)uprv_toupper(*localeID);
if (c == '-' || c == ',') c = '_';
@@ -1453,7 +1453,7 @@ uloc_openKeywords(const char* localeID,
if((tmpLocaleID = locale_getKeywordsStart(tmpLocaleID)) != NULL) {
CharString keywords;
CharStringByteSink sink(&keywords);
- ulocimp_getKeywords(tmpLocaleID+1, '@', sink, FALSE, status);
+ ulocimp_getKeywords(tmpLocaleID+1, '@', sink, false, status);
if (U_FAILURE(*status)) {
return NULL;
}
@@ -1573,7 +1573,7 @@ _canonicalize(const char* localeID,
variantSize = -tag.length();
{
CharStringByteSink s(&tag);
- _getVariant(tmpLocaleID+1, *tmpLocaleID, s, FALSE);
+ _getVariant(tmpLocaleID+1, *tmpLocaleID, s, false);
}
variantSize += tag.length();
if (variantSize > 0) {
@@ -1585,13 +1585,13 @@ _canonicalize(const char* localeID,
/* Copy POSIX-style charset specifier, if any [mr.utf8] */
if (!OPTION_SET(options, _ULOC_CANONICALIZE) && *tmpLocaleID == '.') {
- UBool done = FALSE;
+ UBool done = false;
do {
char c = *tmpLocaleID;
switch (c) {
case 0:
case '@':
- done = TRUE;
+ done = true;
break;
default:
tag.append(c, *err);
@@ -1664,7 +1664,7 @@ _canonicalize(const char* localeID,
(!separatorIndicator || separatorIndicator > keywordAssign)) {
sink.Append("@", 1);
++fieldCount;
- ulocimp_getKeywords(tmpLocaleID+1, '@', sink, TRUE, err);
+ ulocimp_getKeywords(tmpLocaleID+1, '@', sink, true, err);
}
}
}
@@ -1847,7 +1847,7 @@ uloc_getVariant(const char* localeID,
}
CheckedArrayByteSink sink(variant, variantCapacity);
- _getVariant(tmpLocaleID+1, *tmpLocaleID, sink, FALSE);
+ _getVariant(tmpLocaleID+1, *tmpLocaleID, sink, false);
i = sink.NumberOfBytesAppended();
@@ -2158,11 +2158,11 @@ isWellFormedLegacyKey(const char* legacyKey)
const char* p = legacyKey;
while (*p) {
if (!UPRV_ISALPHANUM(*p)) {
- return FALSE;
+ return false;
}
p++;
}
- return TRUE;
+ return true;
}
static UBool
@@ -2173,13 +2173,13 @@ isWellFormedLegacyType(const char* legacyType)
while (*p) {
if (*p == '_' || *p == '/' || *p == '-') {
if (alphaNumLen == 0) {
- return FALSE;
+ return false;
}
alphaNumLen = 0;
} else if (UPRV_ISALPHANUM(*p)) {
alphaNumLen++;
} else {
- return FALSE;
+ return false;
}
p++;
}
diff --git a/thirdparty/icu4c/common/uloc_keytype.cpp b/thirdparty/icu4c/common/uloc_keytype.cpp
index 580244124e..12dc300492 100644
--- a/thirdparty/icu4c/common/uloc_keytype.cpp
+++ b/thirdparty/icu4c/common/uloc_keytype.cpp
@@ -24,7 +24,7 @@
#include "udataswp.h" /* for InvChar functions */
static UHashtable* gLocExtKeyMap = NULL;
-static icu::UInitOnce gLocExtKeyMapInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gLocExtKeyMapInitOnce {};
// bit flags for special types
typedef enum {
@@ -69,7 +69,7 @@ uloc_key_type_cleanup(void) {
gKeyTypeStringPool = NULL;
gLocExtKeyMapInitOnce.reset();
- return TRUE;
+ return true;
}
U_CDECL_END
@@ -356,9 +356,9 @@ init() {
UErrorCode sts = U_ZERO_ERROR;
umtx_initOnce(gLocExtKeyMapInitOnce, &initFromResourceBundle, sts);
if (U_FAILURE(sts)) {
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
static UBool
@@ -368,7 +368,7 @@ isSpecialTypeCodepoints(const char* val) {
while (*p) {
if (*p == '-') {
if (subtagLen < 4 || subtagLen > 6) {
- return FALSE;
+ return false;
}
subtagLen = 0;
} else if ((*p >= '0' && *p <= '9') ||
@@ -376,7 +376,7 @@ isSpecialTypeCodepoints(const char* val) {
(*p >= 'a' && *p <= 'f')) { // also in EBCDIC
subtagLen++;
} else {
- return FALSE;
+ return false;
}
p++;
}
@@ -390,13 +390,13 @@ isSpecialTypeReorderCode(const char* val) {
while (*p) {
if (*p == '-') {
if (subtagLen < 3 || subtagLen > 8) {
- return FALSE;
+ return false;
}
subtagLen = 0;
} else if (uprv_isASCIILetter(*p)) {
subtagLen++;
} else {
- return FALSE;
+ return false;
}
p++;
}
@@ -412,7 +412,7 @@ isSpecialTypeRgKeyValue(const char* val) {
(subtagLen >= 2 && (*p == 'Z' || *p == 'z')) ) {
subtagLen++;
} else {
- return FALSE;
+ return false;
}
p++;
}
@@ -448,10 +448,10 @@ ulocimp_toLegacyKey(const char* key) {
U_CFUNC const char*
ulocimp_toBcpType(const char* key, const char* type, UBool* isKnownKey, UBool* isSpecialType) {
if (isKnownKey != NULL) {
- *isKnownKey = FALSE;
+ *isKnownKey = false;
}
if (isSpecialType != NULL) {
- *isSpecialType = FALSE;
+ *isSpecialType = false;
}
if (!init()) {
@@ -461,14 +461,14 @@ ulocimp_toBcpType(const char* key, const char* type, UBool* isKnownKey, UBool* i
LocExtKeyData* keyData = (LocExtKeyData*)uhash_get(gLocExtKeyMap, key);
if (keyData != NULL) {
if (isKnownKey != NULL) {
- *isKnownKey = TRUE;
+ *isKnownKey = true;
}
LocExtType* t = (LocExtType*)uhash_get(keyData->typeMap.getAlias(), type);
if (t != NULL) {
return t->bcpId;
}
if (keyData->specialTypes != SPECIALTYPE_NONE) {
- UBool matched = FALSE;
+ UBool matched = false;
if (keyData->specialTypes & SPECIALTYPE_CODEPOINTS) {
matched = isSpecialTypeCodepoints(type);
}
@@ -480,7 +480,7 @@ ulocimp_toBcpType(const char* key, const char* type, UBool* isKnownKey, UBool* i
}
if (matched) {
if (isSpecialType != NULL) {
- *isSpecialType = TRUE;
+ *isSpecialType = true;
}
return type;
}
@@ -493,10 +493,10 @@ ulocimp_toBcpType(const char* key, const char* type, UBool* isKnownKey, UBool* i
U_CFUNC const char*
ulocimp_toLegacyType(const char* key, const char* type, UBool* isKnownKey, UBool* isSpecialType) {
if (isKnownKey != NULL) {
- *isKnownKey = FALSE;
+ *isKnownKey = false;
}
if (isSpecialType != NULL) {
- *isSpecialType = FALSE;
+ *isSpecialType = false;
}
if (!init()) {
@@ -506,14 +506,14 @@ ulocimp_toLegacyType(const char* key, const char* type, UBool* isKnownKey, UBool
LocExtKeyData* keyData = (LocExtKeyData*)uhash_get(gLocExtKeyMap, key);
if (keyData != NULL) {
if (isKnownKey != NULL) {
- *isKnownKey = TRUE;
+ *isKnownKey = true;
}
LocExtType* t = (LocExtType*)uhash_get(keyData->typeMap.getAlias(), type);
if (t != NULL) {
return t->legacyId;
}
if (keyData->specialTypes != SPECIALTYPE_NONE) {
- UBool matched = FALSE;
+ UBool matched = false;
if (keyData->specialTypes & SPECIALTYPE_CODEPOINTS) {
matched = isSpecialTypeCodepoints(type);
}
@@ -525,7 +525,7 @@ ulocimp_toLegacyType(const char* key, const char* type, UBool* isKnownKey, UBool
}
if (matched) {
if (isSpecialType != NULL) {
- *isSpecialType = TRUE;
+ *isSpecialType = true;
}
return type;
}
diff --git a/thirdparty/icu4c/common/uloc_tag.cpp b/thirdparty/icu4c/common/uloc_tag.cpp
index 0150e94cef..01a0e0028f 100644
--- a/thirdparty/icu4c/common/uloc_tag.cpp
+++ b/thirdparty/icu4c/common/uloc_tag.cpp
@@ -378,10 +378,10 @@ _isAlphaString(const char* s, int32_t len) {
int32_t i;
for (i = 0; i < len; i++) {
if (!ISALPHA(*(s + i))) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -389,10 +389,10 @@ _isNumericString(const char* s, int32_t len) {
int32_t i;
for (i = 0; i < len; i++) {
if (!ISNUMERIC(*(s + i))) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -400,10 +400,10 @@ _isAlphaNumericString(const char* s, int32_t len) {
int32_t i;
for (i = 0; i < len; i++) {
if (!ISALPHA(*(s + i)) && !ISNUMERIC(*(s + i))) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -412,9 +412,9 @@ _isAlphaNumericStringLimitedLength(const char* s, int32_t len, int32_t min, int3
len = (int32_t)uprv_strlen(s);
}
if (len >= min && len <= max && _isAlphaNumericString(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC UBool
@@ -428,9 +428,9 @@ ultag_isLanguageSubtag(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len >= 2 && len <= 8 && _isAlphaString(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static UBool
@@ -443,9 +443,9 @@ _isExtlangSubtag(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len == 3 && _isAlphaString(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC UBool
@@ -457,9 +457,9 @@ ultag_isScriptSubtag(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len == 4 && _isAlphaString(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC UBool
@@ -472,12 +472,12 @@ ultag_isRegionSubtag(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len == 2 && _isAlphaString(s, len)) {
- return TRUE;
+ return true;
}
if (len == 3 && _isNumericString(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static UBool
@@ -490,12 +490,12 @@ _isVariantSubtag(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (_isAlphaNumericStringLimitedLength(s, len, 5, 8)) {
- return TRUE;
+ return true;
}
if (len == 4 && ISNUMERIC(*s) && _isAlphaNumericString(s + 1, 3)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static UBool
@@ -510,10 +510,10 @@ _isSepListOf(UBool (*test)(const char*, int32_t), const char* s, int32_t len) {
while ((p - s) < len) {
if (*p == SEP) {
if (pSubtag == NULL) {
- return FALSE;
+ return false;
}
if (!test(pSubtag, (int32_t)(p - pSubtag))) {
- return FALSE;
+ return false;
}
pSubtag = NULL;
} else if (pSubtag == NULL) {
@@ -522,7 +522,7 @@ _isSepListOf(UBool (*test)(const char*, int32_t), const char* s, int32_t len) {
p++;
}
if (pSubtag == NULL) {
- return FALSE;
+ return false;
}
return test(pSubtag, (int32_t)(p - pSubtag));
}
@@ -557,9 +557,9 @@ _isExtensionSingleton(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len == 1 && (ISALPHA(*s) || ISNUMERIC(*s)) && (uprv_tolower(*s) != PRIVATEUSE)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
static UBool
@@ -610,9 +610,9 @@ ultag_isUnicodeLocaleKey(const char* s, int32_t len) {
len = (int32_t)uprv_strlen(s);
}
if (len == 2 && (ISALPHA(*s) || ISNUMERIC(*s)) && ISALPHA(s[1])) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC UBool
@@ -641,9 +641,9 @@ _isTKey(const char* s, int32_t len)
len = (int32_t)uprv_strlen(s);
}
if (len == 2 && ISALPHA(*s) && ISNUMERIC(*(s + 1))) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CAPI const char * U_EXPORT2
@@ -694,23 +694,23 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len)
case kStart:
if (ultag_isLanguageSubtag(s, len) && len != 4) {
state = kGotLanguage;
- return TRUE;
+ return true;
}
if (_isTKey(s, len)) {
state = kGotTKey;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
case kGotLanguage:
if (ultag_isScriptSubtag(s, len)) {
state = kGotScript;
- return TRUE;
+ return true;
}
U_FALLTHROUGH;
case kGotScript:
if (ultag_isRegionSubtag(s, len)) {
state = kGotRegion;
- return TRUE;
+ return true;
}
U_FALLTHROUGH;
case kGotRegion:
@@ -718,30 +718,30 @@ _isTransformedExtensionSubtag(int32_t& state, const char* s, int32_t len)
case kGotVariant:
if (_isVariantSubtag(s, len)) {
state = kGotVariant;
- return TRUE;
+ return true;
}
if (_isTKey(s, len)) {
state = kGotTKey;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
case kGotTKey:
if (_isTValue(s, len)) {
state = kGotTValue;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
case kGotTValue:
if (_isTKey(s, len)) {
state = kGotTKey;
- return TRUE;
+ return true;
}
if (_isTValue(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- return FALSE;
+ return false;
}
static UBool
@@ -755,32 +755,32 @@ _isUnicodeExtensionSubtag(int32_t& state, const char* s, int32_t len)
case kStart:
if (ultag_isUnicodeLocaleKey(s, len)) {
state = kGotKey;
- return TRUE;
+ return true;
}
if (ultag_isUnicodeLocaleAttribute(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
case kGotKey:
if (ultag_isUnicodeLocaleKey(s, len)) {
- return TRUE;
+ return true;
}
if (_isUnicodeLocaleTypeSubtag(s, len)) {
state = kGotType;
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
case kGotType:
if (ultag_isUnicodeLocaleKey(s, len)) {
state = kGotKey;
- return TRUE;
+ return true;
}
if (_isUnicodeLocaleTypeSubtag(s, len)) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
- return FALSE;
+ return false;
}
static UBool
@@ -798,7 +798,7 @@ _isStatefulSepListOf(UBool (*test)(int32_t&, const char*, int32_t), const char*
for (p = s; len > 0; p++, len--) {
if (*p == SEP) {
if (!test(state, start, subtagLen)) {
- return FALSE;
+ return false;
}
subtagLen = 0;
start = p + 1;
@@ -808,9 +808,9 @@ _isStatefulSepListOf(UBool (*test)(int32_t&, const char*, int32_t), const char*
}
if (test(state, start, subtagLen) && state >= 0) {
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC UBool
@@ -835,7 +835,7 @@ ultag_isUnicodeExtensionSubtags(const char* s, int32_t len) {
static UBool
_addVariantToList(VariantListEntry **first, VariantListEntry *var) {
- UBool bAdded = TRUE;
+ UBool bAdded = true;
if (*first == NULL) {
var->next = NULL;
@@ -847,7 +847,7 @@ _addVariantToList(VariantListEntry **first, VariantListEntry *var) {
/* variants order should be preserved */
prev = NULL;
cur = *first;
- while (TRUE) {
+ while (true) {
if (cur == NULL) {
prev->next = var;
var->next = NULL;
@@ -858,7 +858,7 @@ _addVariantToList(VariantListEntry **first, VariantListEntry *var) {
cmp = uprv_compareInvCharsAsAscii(var->variant, cur->variant);
if (cmp == 0) {
/* duplicated variant */
- bAdded = FALSE;
+ bAdded = false;
break;
}
prev = cur;
@@ -871,7 +871,7 @@ _addVariantToList(VariantListEntry **first, VariantListEntry *var) {
static UBool
_addAttributeToList(AttributeListEntry **first, AttributeListEntry *attr) {
- UBool bAdded = TRUE;
+ UBool bAdded = true;
if (*first == NULL) {
attr->next = NULL;
@@ -883,7 +883,7 @@ _addAttributeToList(AttributeListEntry **first, AttributeListEntry *attr) {
/* reorder variants in alphabetical order */
prev = NULL;
cur = *first;
- while (TRUE) {
+ while (true) {
if (cur == NULL) {
prev->next = attr;
attr->next = NULL;
@@ -901,7 +901,7 @@ _addAttributeToList(AttributeListEntry **first, AttributeListEntry *attr) {
}
if (cmp == 0) {
/* duplicated variant */
- bAdded = FALSE;
+ bAdded = false;
break;
}
prev = cur;
@@ -915,7 +915,7 @@ _addAttributeToList(AttributeListEntry **first, AttributeListEntry *attr) {
static UBool
_addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool localeToBCP) {
- UBool bAdded = TRUE;
+ UBool bAdded = true;
if (*first == NULL) {
ext->next = NULL;
@@ -927,7 +927,7 @@ _addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool l
/* reorder variants in alphabetical order */
prev = NULL;
cur = *first;
- while (TRUE) {
+ while (true) {
if (cur == NULL) {
prev->next = ext;
ext->next = NULL;
@@ -979,7 +979,7 @@ _addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool l
}
if (cmp == 0) {
/* duplicated extension key */
- bAdded = FALSE;
+ bAdded = false;
break;
}
prev = cur;
@@ -1164,7 +1164,7 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
if (len > 0) {
char *p, *pVar;
- UBool bNext = TRUE;
+ UBool bNext = true;
VariantListEntry *var;
VariantListEntry *varFirst = NULL;
@@ -1173,7 +1173,7 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
while (bNext) {
if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
if (*p == 0) {
- bNext = FALSE;
+ bNext = false;
} else {
*p = 0; /* terminate */
}
@@ -1211,7 +1211,7 @@ _appendVariantsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
} else {
/* Special handling for POSIX variant, need to remember that we had it and then */
/* treat it like an extension later. */
- *hadPosix = TRUE;
+ *hadPosix = true;
}
} else if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -1288,7 +1288,7 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
int32_t keylen;
UBool isBcpUExt;
- while (TRUE) {
+ while (true) {
key = uenum_next(keywordEnum.getAlias(), NULL, status);
if (key == NULL) {
break;
@@ -1322,7 +1322,7 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
if (uprv_strcmp(key, LOCALE_ATTRIBUTE_KEY) == 0) {
if (len > 0) {
int32_t i = 0;
- while (TRUE) {
+ while (true) {
attrBufLength = 0;
for (; i < len; i++) {
if (buf[i] != '-') {
@@ -1448,7 +1448,7 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
ext->key = bcpKey;
ext->value = bcpValue;
- if (!_addExtensionToList(&firstExt, ext, TRUE)) {
+ if (!_addExtensionToList(&firstExt, ext, true)) {
if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
break;
@@ -1467,18 +1467,18 @@ _appendKeywordsToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool st
ext->key = POSIX_KEY;
ext->value = POSIX_VALUE;
- if (!_addExtensionToList(&firstExt, ext, TRUE)) {
+ if (!_addExtensionToList(&firstExt, ext, true)) {
// Silently ignore errors.
}
}
if (U_SUCCESS(*status) && (firstExt != NULL || firstAttr != NULL)) {
- UBool startLDMLExtension = FALSE;
+ UBool startLDMLExtension = false;
for (ext = firstExt; ext; ext = ext->next) {
if (!startLDMLExtension && uprv_strlen(ext->key) > 1) {
/* first LDML u singlton extension */
sink.Append("-u", 2);
- startLDMLExtension = TRUE;
+ startLDMLExtension = true;
}
/* write out the sorted BCP47 attributes, extensions and private use */
@@ -1520,7 +1520,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
int32_t len;
/* Reset the posixVariant value */
- *posixVariant = FALSE;
+ *posixVariant = false;
pTag = ldmlext;
pKwds = NULL;
@@ -1604,7 +1604,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
kwd->key = LOCALE_ATTRIBUTE_KEY;
kwd->value = value->data();
- if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+ if (!_addExtensionToList(&kwdFirst, kwd, false)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
@@ -1616,14 +1616,14 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
const char *pBcpType = NULL; /* beginning of u extension type subtag(s) */
int32_t bcpKeyLen = 0;
int32_t bcpTypeLen = 0;
- UBool isDone = FALSE;
+ UBool isDone = false;
pTag = pKwds;
/* BCP47 representation of LDML key/type pairs */
while (!isDone) {
const char *pNextBcpKey = NULL;
int32_t nextBcpKeyLen = 0;
- UBool emitKeyword = FALSE;
+ UBool emitKeyword = false;
if (*pTag) {
/* locate next separator char */
@@ -1631,7 +1631,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
if (ultag_isUnicodeLocaleKey(pTag, len)) {
if (pBcpKey) {
- emitKeyword = TRUE;
+ emitKeyword = true;
pNextBcpKey = pTag;
nextBcpKeyLen = len;
} else {
@@ -1657,8 +1657,8 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
}
} else {
/* processing last one */
- emitKeyword = TRUE;
- isDone = TRUE;
+ emitKeyword = true;
+ isDone = true;
}
if (emitKeyword) {
@@ -1744,7 +1744,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
/* Special handling for u-va-posix, since we want to treat this as a variant,
not as a keyword */
if (!variantExists && !uprv_strcmp(pKey, POSIX_KEY) && !uprv_strcmp(pType, POSIX_VALUE) ) {
- *posixVariant = TRUE;
+ *posixVariant = true;
} else {
/* create an ExtensionListEntry for this keyword */
kwd = extPool.create();
@@ -1756,7 +1756,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
kwd->key = pKey;
kwd->value = pType;
- if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+ if (!_addExtensionToList(&kwdFirst, kwd, false)) {
// duplicate keyword is allowed, Only the first
// is honored.
}
@@ -1773,7 +1773,7 @@ _appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendT
kwd = kwdFirst;
while (kwd != NULL) {
nextKwd = kwd->next;
- _addExtensionToList(appendTo, kwd, FALSE);
+ _addExtensionToList(appendTo, kwd, false);
kwd = nextKwd;
}
}
@@ -1788,7 +1788,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
const char *key, *type;
icu::MemoryPool<ExtensionListEntry> extPool;
icu::MemoryPool<icu::CharString> kwdBuf;
- UBool posixVariant = FALSE;
+ UBool posixVariant = false;
if (U_FAILURE(*status)) {
return;
@@ -1803,7 +1803,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
if (*key == LDMLEXT) {
/* Determine if variants already exists */
if (ultag_getVariantsSize(langtag)) {
- posixVariant = TRUE;
+ posixVariant = true;
}
_appendLDMLExtensionAsKeywords(type, &kwdFirst, extPool, kwdBuf, &posixVariant, status);
@@ -1818,7 +1818,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
}
kwd->key = key;
kwd->value = type;
- if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+ if (!_addExtensionToList(&kwdFirst, kwd, false)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
break;
}
@@ -1835,7 +1835,7 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
} else {
kwd->key = PRIVATEUSE_KEY;
kwd->value = type;
- if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
+ if (!_addExtensionToList(&kwdFirst, kwd, false)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
}
}
@@ -1851,12 +1851,12 @@ _appendKeywords(ULanguageTag* langtag, icu::ByteSink& sink, UErrorCode* status)
if (U_SUCCESS(*status) && kwdFirst != NULL) {
/* write out the sorted keywords */
- UBool firstValue = TRUE;
+ UBool firstValue = true;
kwd = kwdFirst;
do {
if (firstValue) {
sink.Append("@", 1);
- firstValue = FALSE;
+ firstValue = false;
} else {
sink.Append(";", 1);
}
@@ -1899,17 +1899,17 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool
if (len > 0) {
char *p, *pPriv;
- UBool bNext = TRUE;
- UBool firstValue = TRUE;
+ UBool bNext = true;
+ UBool firstValue = true;
UBool writeValue;
pPriv = NULL;
p = buf;
while (bNext) {
- writeValue = FALSE;
+ writeValue = false;
if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
if (*p == 0) {
- bNext = FALSE;
+ bNext = false;
} else {
*p = 0; /* terminate */
}
@@ -1923,10 +1923,10 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool
if (_isPrivateuseValueSubtag(pPriv, -1)) {
if (firstValue) {
if (!_isVariantSubtag(pPriv, -1)) {
- writeValue = TRUE;
+ writeValue = true;
}
} else {
- writeValue = TRUE;
+ writeValue = true;
}
} else if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -1959,7 +1959,7 @@ _appendPrivateuseToLanguageTag(const char* localeID, icu::ByteSink& sink, UBool
tmpAppend[reslen++] = SEP;
}
- firstValue = FALSE;
+ firstValue = false;
}
len = (int32_t)uprv_strlen(pPriv);
@@ -2026,7 +2026,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
ExtensionListEntry *pExtension;
char *pExtValueSubtag, *pExtValueSubtagEnd;
int32_t i;
- UBool privateuseVar = FALSE;
+ UBool privateuseVar = false;
int32_t legacyLen = 0;
if (parsedLen != NULL) {
@@ -2124,7 +2124,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
if (*redundantTagEnd == '\0' || *redundantTagEnd == SEP) {
const char* preferredTag = REDUNDANT[i + 1];
size_t preferredTagLen = uprv_strlen(preferredTag);
- uprv_strncpy(t->buf, preferredTag, preferredTagLen);
+ uprv_memcpy(t->buf, preferredTag, preferredTagLen);
if (*redundantTagEnd == SEP) {
uprv_memmove(tagBuf + preferredTagLen,
redundantTagEnd,
@@ -2276,7 +2276,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
/* insert the extension to the list */
- if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+ if (_addExtensionToList(&(t->extensions), pExtension, false)) {
pLastGoodPosition = pExtValueSubtagEnd;
} else {
/* stop parsing here */
@@ -2339,7 +2339,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
/* insert the extension to the list */
- if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+ if (_addExtensionToList(&(t->extensions), pExtension, false)) {
pLastGoodPosition = pExtValueSubtagEnd;
pExtension = NULL;
} else {
@@ -2380,7 +2380,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
if (uprv_strncmp(pSubtag, PRIVUSE_VARIANT_PREFIX, uprv_strlen(PRIVUSE_VARIANT_PREFIX)) == 0) {
*pSep = 0;
next = VART;
- privateuseVar = TRUE;
+ privateuseVar = true;
break;
} else if (_isPrivateuseValueSubtag(pSubtag, subtagLen)) {
pLastGoodPosition = pSep;
@@ -2417,7 +2417,7 @@ ultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* sta
*pExtValueSubtagEnd = 0;
pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
/* insert the extension to the list */
- if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
+ if (_addExtensionToList(&(t->extensions), pExtension, false)) {
pLastGoodPosition = pExtValueSubtagEnd;
} else {
uprv_free(pExtension);
@@ -2535,7 +2535,7 @@ static int32_t
ultag_getVariantsSize(const ULanguageTag* langtag) {
int32_t size = 0;
VariantListEntry *cur = langtag->variants;
- while (TRUE) {
+ while (true) {
if (cur == NULL) {
break;
}
@@ -2581,7 +2581,7 @@ static int32_t
ultag_getExtensionsSize(const ULanguageTag* langtag) {
int32_t size = 0;
ExtensionListEntry *cur = langtag->extensions;
- while (TRUE) {
+ while (true) {
if (cur == NULL) {
break;
}
@@ -2648,7 +2648,7 @@ ulocimp_toLanguageTag(const char* localeID,
icu::CharString canonical;
int32_t reslen;
UErrorCode tmpStatus = U_ZERO_ERROR;
- UBool hadPosix = FALSE;
+ UBool hadPosix = false;
const char* pKeywordStart;
/* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "". See #6835 */
@@ -2699,7 +2699,7 @@ ulocimp_toLanguageTag(const char* localeID,
pKeywordStart = locale_getKeywordsStart(canonical.data());
if (pKeywordStart == canonical.data()) {
int kwdCnt = 0;
- UBool done = FALSE;
+ UBool done = false;
icu::LocalUEnumerationPointer kwdEnum(uloc_openKeywords(canonical.data(), &tmpStatus));
if (U_SUCCESS(tmpStatus)) {
@@ -2720,15 +2720,15 @@ ulocimp_toLanguageTag(const char* localeID,
/* return private use only tag */
sink.Append("und-x-", 6);
sink.Append(buf.data(), buf.length());
- done = TRUE;
+ done = true;
} else if (strict) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
- done = TRUE;
+ done = true;
}
/* if not strict mode, then "und" will be returned */
} else {
*status = U_ILLEGAL_ARGUMENT_ERROR;
- done = TRUE;
+ done = true;
}
}
}
@@ -2782,11 +2782,11 @@ ulocimp_forLanguageTag(const char* langtag,
icu::ByteSink& sink,
int32_t* parsedLength,
UErrorCode* status) {
- UBool isEmpty = TRUE;
+ UBool isEmpty = true;
const char *subtag, *p;
int32_t len;
int32_t i, n;
- UBool noRegion = TRUE;
+ UBool noRegion = true;
icu::LocalULanguageTagPointer lt(ultag_parse(langtag, tagLen, parsedLength, status));
if (U_FAILURE(*status)) {
@@ -2799,7 +2799,7 @@ ulocimp_forLanguageTag(const char* langtag,
len = (int32_t)uprv_strlen(subtag);
if (len > 0) {
sink.Append(subtag, len);
- isEmpty = FALSE;
+ isEmpty = false;
}
}
@@ -2808,7 +2808,7 @@ ulocimp_forLanguageTag(const char* langtag,
len = (int32_t)uprv_strlen(subtag);
if (len > 0) {
sink.Append("_", 1);
- isEmpty = FALSE;
+ isEmpty = false;
/* write out the script in title case */
char c = uprv_toupper(*subtag);
@@ -2821,7 +2821,7 @@ ulocimp_forLanguageTag(const char* langtag,
len = (int32_t)uprv_strlen(subtag);
if (len > 0) {
sink.Append("_", 1);
- isEmpty = FALSE;
+ isEmpty = false;
/* write out the region in upper case */
p = subtag;
@@ -2830,7 +2830,7 @@ ulocimp_forLanguageTag(const char* langtag,
sink.Append(&c, 1);
p++;
}
- noRegion = FALSE;
+ noRegion = false;
}
/* variants */
@@ -2839,7 +2839,7 @@ ulocimp_forLanguageTag(const char* langtag,
if (n > 0) {
if (noRegion) {
sink.Append("_", 1);
- isEmpty = FALSE;
+ isEmpty = false;
}
for (i = 0; i < n; i++) {
diff --git a/thirdparty/icu4c/common/umapfile.cpp b/thirdparty/icu4c/common/umapfile.cpp
index 3e714876a4..145582ea97 100644
--- a/thirdparty/icu4c/common/umapfile.cpp
+++ b/thirdparty/icu4c/common/umapfile.cpp
@@ -107,10 +107,10 @@ typedef HANDLE MemoryMap;
U_CFUNC UBool
uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
UDataMemory_init(pData); /* Clear the output struct. */
- return FALSE; /* no file access */
+ return false; /* no file access */
}
U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
@@ -126,7 +126,7 @@ typedef HANDLE MemoryMap;
)
{
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
HANDLE map = nullptr;
@@ -150,12 +150,12 @@ typedef HANDLE MemoryMap;
u_strFromUTF8(reinterpret_cast<UChar*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
if (*status == U_STRING_NOT_TERMINATED_WARNING) {
// Report back an error instead of a warning.
*status = U_BUFFER_OVERFLOW_ERROR;
- return FALSE;
+ return false;
}
file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
@@ -168,7 +168,7 @@ typedef HANDLE MemoryMap;
if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
- return FALSE;
+ return false;
}
// Note: We use NULL/nullptr for lpAttributes parameter below.
@@ -183,17 +183,17 @@ typedef HANDLE MemoryMap;
if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
*status = U_MEMORY_ALLOCATION_ERROR;
}
- return FALSE;
+ return false;
}
/* map a view of the file into our address space */
pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
if (pData->pHeader == nullptr) {
CloseHandle(map);
- return FALSE;
+ return false;
}
pData->map = map;
- return TRUE;
+ return true;
}
U_CFUNC void
@@ -217,21 +217,21 @@ typedef HANDLE MemoryMap;
void *data;
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
UDataMemory_init(pData); /* Clear the output struct. */
/* determine the length of the file */
if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
- return FALSE;
+ return false;
}
length=mystat.st_size;
/* open the file */
fd=open(path, O_RDONLY);
if(fd==-1) {
- return FALSE;
+ return false;
}
/* get a view of the mapping */
@@ -243,7 +243,7 @@ typedef HANDLE MemoryMap;
close(fd); /* no longer needed */
if(data==MAP_FAILED) {
// Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
- return FALSE;
+ return false;
}
pData->map = (char *)data + length;
@@ -252,7 +252,7 @@ typedef HANDLE MemoryMap;
#if U_PLATFORM == U_PF_IPHONE
posix_madvise(data, length, POSIX_MADV_RANDOM);
#endif
- return TRUE;
+ return true;
}
U_CFUNC void
@@ -291,21 +291,21 @@ typedef HANDLE MemoryMap;
void *p;
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
UDataMemory_init(pData); /* Clear the output struct. */
/* open the input file */
file=fopen(path, "rb");
if(file==nullptr) {
- return FALSE;
+ return false;
}
/* get the file length */
fileLength=umap_fsize(file);
if(ferror(file) || fileLength<=20) {
fclose(file);
- return FALSE;
+ return false;
}
/* allocate the memory to hold the file data */
@@ -313,21 +313,21 @@ typedef HANDLE MemoryMap;
if(p==nullptr) {
fclose(file);
*status = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
/* read the file */
if(fileLength!=fread(p, 1, fileLength, file)) {
uprv_free(p);
fclose(file);
- return FALSE;
+ return false;
}
fclose(file);
pData->map=p;
pData->pHeader=(const DataHeader *)p;
pData->mapAddr=p;
- return TRUE;
+ return true;
}
U_CFUNC void
@@ -427,7 +427,7 @@ typedef HANDLE MemoryMap;
void *val=0;
if (U_FAILURE(*status)) {
- return FALSE;
+ return false;
}
inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
@@ -447,14 +447,14 @@ typedef HANDLE MemoryMap;
/* determine the length of the file */
if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
- return FALSE;
+ return false;
}
length=mystat.st_size;
/* open the file */
fd=open(path, O_RDONLY);
if(fd==-1) {
- return FALSE;
+ return false;
}
/* get a view of the mapping */
@@ -462,12 +462,12 @@ typedef HANDLE MemoryMap;
close(fd); /* no longer needed */
if(data==MAP_FAILED) {
// Possibly check the errorno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
- return FALSE;
+ return false;
}
pData->map = (char *)data + length;
pData->pHeader=(const DataHeader *)data;
pData->mapAddr = data;
- return TRUE;
+ return true;
}
# ifdef OS390BATCH
@@ -503,16 +503,16 @@ typedef HANDLE MemoryMap;
val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
if(val == 0) {
/* failed... so keep looking */
- return FALSE;
+ return false;
}
# ifdef UDATA_DEBUG
fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
# endif
pData->pHeader=(const DataHeader *)val;
- return TRUE;
+ return true;
} else {
- return FALSE; /* no handle */
+ return false; /* no handle */
}
}
diff --git a/thirdparty/icu4c/common/umapfile.h b/thirdparty/icu4c/common/umapfile.h
index adc265203d..042e71374c 100644
--- a/thirdparty/icu4c/common/umapfile.h
+++ b/thirdparty/icu4c/common/umapfile.h
@@ -29,7 +29,7 @@
#include "unicode/udata.h"
#include "putilimp.h"
-U_CFUNC UBool uprv_mapFile(UDataMemory *pdm, const char *path, UErrorCode *status);
+U_CAPI UBool U_EXPORT2 uprv_mapFile(UDataMemory *pdm, const char *path, UErrorCode *status);
U_CFUNC void uprv_unmapFile(UDataMemory *pData);
/* MAP_NONE: no memory mapping, no file access at all */
diff --git a/thirdparty/icu4c/common/umutex.h b/thirdparty/icu4c/common/umutex.h
index 8d76b3f3e6..1b8332409c 100644
--- a/thirdparty/icu4c/common/umutex.h
+++ b/thirdparty/icu4c/common/umutex.h
@@ -71,7 +71,6 @@ U_NAMESPACE_BEGIN
****************************************************************************/
typedef std::atomic<int32_t> u_atomic_int32_t;
-#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
return var.load(std::memory_order_acquire);
@@ -96,18 +95,15 @@ inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
*
*************************************************************************************************/
-struct UInitOnce {
- u_atomic_int32_t fState;
- UErrorCode fErrCode;
+struct U_COMMON_API UInitOnce {
+ u_atomic_int32_t fState {0};
+ UErrorCode fErrCode {U_ZERO_ERROR};
void reset() {fState = 0;}
UBool isReset() {return umtx_loadAcquire(fState) == 0;}
// Note: isReset() is used by service registration code.
// Thread safety of this usage needs review.
};
-#define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
-
-
U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
diff --git a/thirdparty/icu4c/common/unames.cpp b/thirdparty/icu4c/common/unames.cpp
index 5776058f95..b0ac991e1b 100644
--- a/thirdparty/icu4c/common/unames.cpp
+++ b/thirdparty/icu4c/common/unames.cpp
@@ -105,7 +105,7 @@ typedef struct {
static UDataMemory *uCharNamesData=NULL;
static UCharNames *uCharNames=NULL;
-static icu::UInitOnce gCharNamesInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCharNamesInitOnce {};
/*
* Maximum length of character names (regular & 1.0).
@@ -173,7 +173,7 @@ static UBool U_CALLCONV unames_cleanup(void)
}
gCharNamesInitOnce.reset();
gMaxNameLength=0;
- return TRUE;
+ return true;
}
static UBool U_CALLCONV
@@ -371,7 +371,7 @@ compareName(UCharNames *names,
if(c!=';') {
/* implicit letter */
if((char)c!=*otherName++) {
- return FALSE;
+ return false;
}
} else {
/* finished */
@@ -388,7 +388,7 @@ compareName(UCharNames *names,
if(c!=';') {
/* explicit letter */
if((char)c!=*otherName++) {
- return FALSE;
+ return false;
}
} else {
/* stop, but skip the semicolon if we are seeking
@@ -407,7 +407,7 @@ compareName(UCharNames *names,
uint8_t *tokenString=tokenStrings+token;
while((c=*tokenString++)!=0) {
if((char)c!=*otherName++) {
- return FALSE;
+ return false;
}
}
}
@@ -616,7 +616,7 @@ enumGroupNames(UCharNames *names, const uint16_t *group,
/* here, we assume that the buffer is large enough */
if(length>0) {
if(!fn(context, start, nameChoice, buffer, length)) {
- return FALSE;
+ return false;
}
}
++start;
@@ -626,12 +626,12 @@ enumGroupNames(UCharNames *names, const uint16_t *group,
while(start<=end) {
if(compareName(names, s+offsets[start&GROUP_MASK], lengths[start&GROUP_MASK], nameChoice, otherName)) {
((FindName *)context)->code=start;
- return FALSE;
+ return false;
}
++start;
}
}
- return TRUE;
+ return true;
}
/*
@@ -653,14 +653,14 @@ enumExtNames(UChar32 start, UChar32 end,
/* here, we assume that the buffer is large enough */
if(length>0) {
if(!fn(context, start, U_EXTENDED_CHAR_NAME, buffer, length)) {
- return FALSE;
+ return false;
}
}
++start;
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -684,7 +684,7 @@ enumNames(UCharNames *names,
extLimit=limit;
}
if(!enumExtNames(start, extLimit-1, fn, context)) {
- return FALSE;
+ return false;
}
start=extLimit;
}
@@ -705,7 +705,7 @@ enumNames(UCharNames *names,
if(!enumGroupNames(names, group,
start, ((UChar32)startGroupMSB<<GROUP_SHIFT)+LINES_PER_GROUP-1,
fn, context, nameChoice)) {
- return FALSE;
+ return false;
}
group=NEXT_GROUP(group); /* continue with the next group */
}
@@ -718,7 +718,7 @@ enumNames(UCharNames *names,
end = limit;
}
if (!enumExtNames(start, end - 1, fn, context)) {
- return FALSE;
+ return false;
}
}
group=nextGroup;
@@ -729,7 +729,7 @@ enumNames(UCharNames *names,
const uint16_t *nextGroup;
start=(UChar32)group[GROUP_MSB]<<GROUP_SHIFT;
if(!enumGroupNames(names, group, start, start+LINES_PER_GROUP-1, fn, context, nameChoice)) {
- return FALSE;
+ return false;
}
nextGroup=NEXT_GROUP(group);
if (nextGroup < groupLimit && nextGroup[GROUP_MSB] > group[GROUP_MSB] + 1 && nameChoice == U_EXTENDED_CHAR_NAME) {
@@ -738,7 +738,7 @@ enumNames(UCharNames *names,
end = limit;
}
if (!enumExtNames((group[GROUP_MSB] + 1) << GROUP_SHIFT, end - 1, fn, context)) {
- return FALSE;
+ return false;
}
}
group=nextGroup;
@@ -753,7 +753,7 @@ enumNames(UCharNames *names,
start = next;
}
} else {
- return TRUE;
+ return true;
}
}
@@ -766,7 +766,7 @@ enumNames(UCharNames *names,
return enumExtNames(start, limit - 1, fn, context);
}
- return TRUE;
+ return true;
}
static uint16_t
@@ -941,7 +941,7 @@ enumAlgNames(AlgorithmicRange *range,
uint16_t length;
if(nameChoice!=U_UNICODE_CHAR_NAME && nameChoice!=U_EXTENDED_CHAR_NAME) {
- return TRUE;
+ return true;
}
switch(range->type) {
@@ -952,12 +952,12 @@ enumAlgNames(AlgorithmicRange *range,
/* get the full name of the start character */
length=getAlgName(range, (uint32_t)start, nameChoice, buffer, sizeof(buffer));
if(length<=0) {
- return TRUE;
+ return true;
}
/* call the enumerator function with this first character */
if(!fn(context, start, nameChoice, buffer, length)) {
- return FALSE;
+ return false;
}
/* go to the end of the name; all these names have the same length */
@@ -984,7 +984,7 @@ enumAlgNames(AlgorithmicRange *range,
}
if(!fn(context, start, nameChoice, buffer, length)) {
- return FALSE;
+ return false;
}
}
break;
@@ -1018,7 +1018,7 @@ enumAlgNames(AlgorithmicRange *range,
/* call the enumerator function with this first character */
if(!fn(context, start, nameChoice, buffer, length)) {
- return FALSE;
+ return false;
}
/* enumerate the rest of the names */
@@ -1056,7 +1056,7 @@ enumAlgNames(AlgorithmicRange *range,
*t=0;
if(!fn(context, start, nameChoice, buffer, length)) {
- return FALSE;
+ return false;
}
}
break;
@@ -1066,7 +1066,7 @@ enumAlgNames(AlgorithmicRange *range,
break;
}
- return TRUE;
+ return true;
}
/*
@@ -1416,11 +1416,11 @@ calcNameSetsLengths(UErrorCode *pErrorCode) {
int32_t i, maxNameLength;
if(gMaxNameLength!=0) {
- return TRUE;
+ return true;
}
if(!isDataLoaded(pErrorCode)) {
- return FALSE;
+ return false;
}
/* set hex digits, used in various names, and <>-, used in extended names */
@@ -1437,7 +1437,7 @@ calcNameSetsLengths(UErrorCode *pErrorCode) {
/* set sets and lengths from group names, set global maximum values */
calcGroupNameSetsLengths(maxNameLength);
- return TRUE;
+ return true;
}
U_NAMESPACE_END
@@ -1809,7 +1809,7 @@ makeTokenMap(const UDataSwapper *ds,
/* enter the converted character into the map and mark it used */
map[c1]=c2;
- usedOutChar[c2]=TRUE;
+ usedOutChar[c2]=true;
}
}
diff --git a/thirdparty/icu4c/common/unicode/bytestrie.h b/thirdparty/icu4c/common/unicode/bytestrie.h
index 271a81d1b4..8fe66780f5 100644
--- a/thirdparty/icu4c/common/unicode/bytestrie.h
+++ b/thirdparty/icu4c/common/unicode/bytestrie.h
@@ -394,7 +394,7 @@ private:
pos_(bytes_), remainingMatchLength_(-1) {}
// No assignment operator.
- BytesTrie &operator=(const BytesTrie &other);
+ BytesTrie &operator=(const BytesTrie &other) = delete;
inline void stop() {
pos_=NULL;
diff --git a/thirdparty/icu4c/common/unicode/bytestriebuilder.h b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
index 382f5e0095..ec9c625473 100644
--- a/thirdparty/icu4c/common/unicode/bytestriebuilder.h
+++ b/thirdparty/icu4c/common/unicode/bytestriebuilder.h
@@ -129,8 +129,8 @@ public:
private:
friend class ::BytesTrieTest;
- BytesTrieBuilder(const BytesTrieBuilder &other); // no copy constructor
- BytesTrieBuilder &operator=(const BytesTrieBuilder &other); // no assignment operator
+ BytesTrieBuilder(const BytesTrieBuilder &other) = delete; // no copy constructor
+ BytesTrieBuilder &operator=(const BytesTrieBuilder &other) = delete; // no assignment operator
void buildBytes(UStringTrieBuildOption buildOption, UErrorCode &errorCode);
diff --git a/thirdparty/icu4c/common/unicode/caniter.h b/thirdparty/icu4c/common/unicode/caniter.h
index 6e57ef5e3b..db400a531b 100644
--- a/thirdparty/icu4c/common/unicode/caniter.h
+++ b/thirdparty/icu4c/common/unicode/caniter.h
@@ -150,20 +150,20 @@ public:
private:
// ===================== PRIVATES ==============================
// private default constructor
- CanonicalIterator();
+ CanonicalIterator() = delete;
/**
* Copy constructor. Private for now.
* @internal (private)
*/
- CanonicalIterator(const CanonicalIterator& other);
+ CanonicalIterator(const CanonicalIterator& other) = delete;
/**
* Assignment operator. Private for now.
* @internal (private)
*/
- CanonicalIterator& operator=(const CanonicalIterator& other);
+ CanonicalIterator& operator=(const CanonicalIterator& other) = delete;
// fields
UnicodeString source;
diff --git a/thirdparty/icu4c/common/unicode/dtintrv.h b/thirdparty/icu4c/common/unicode/dtintrv.h
index 46a94ce349..8c172eb7a5 100644
--- a/thirdparty/icu4c/common/unicode/dtintrv.h
+++ b/thirdparty/icu4c/common/unicode/dtintrv.h
@@ -131,7 +131,7 @@ private:
/**
* Default constructor, not implemented.
*/
- DateInterval();
+ DateInterval() = delete;
UDate fromDate;
UDate toDate;
diff --git a/thirdparty/icu4c/common/unicode/idna.h b/thirdparty/icu4c/common/unicode/idna.h
index 1305dc6048..1c57205bae 100644
--- a/thirdparty/icu4c/common/unicode/idna.h
+++ b/thirdparty/icu4c/common/unicode/idna.h
@@ -305,8 +305,8 @@ public:
private:
friend class UTS46;
- IDNAInfo(const IDNAInfo &other); // no copying
- IDNAInfo &operator=(const IDNAInfo &other); // no copying
+ IDNAInfo(const IDNAInfo &other) = delete; // no copying
+ IDNAInfo &operator=(const IDNAInfo &other) = delete; // no copying
void reset() {
errors=labelErrors=0;
diff --git a/thirdparty/icu4c/common/unicode/normlzr.h b/thirdparty/icu4c/common/unicode/normlzr.h
index 93661990fe..14b2469885 100644
--- a/thirdparty/icu4c/common/unicode/normlzr.h
+++ b/thirdparty/icu4c/common/unicode/normlzr.h
@@ -740,8 +740,8 @@ private:
// Private functions
//-------------------------------------------------------------------------
- Normalizer(); // default constructor not implemented
- Normalizer &operator=(const Normalizer &that); // assignment operator not implemented
+ Normalizer() = delete; // default constructor not implemented
+ Normalizer &operator=(const Normalizer &that) = delete; // assignment operator not implemented
// Private utility methods for iteration
// For documentation, see the source code
diff --git a/thirdparty/icu4c/common/unicode/platform.h b/thirdparty/icu4c/common/unicode/platform.h
index b7e514442c..1605226a79 100644
--- a/thirdparty/icu4c/common/unicode/platform.h
+++ b/thirdparty/icu4c/common/unicode/platform.h
@@ -168,7 +168,7 @@
# define U_PLATFORM U_PF_LINUX
#elif defined(__APPLE__) && defined(__MACH__)
# include <TargetConditionals.h>
-# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE /* variant of TARGET_OS_MAC */
+# if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && (defined(TARGET_OS_MACCATALYST) && !TARGET_OS_MACCATALYST) /* variant of TARGET_OS_MAC */
# define U_PLATFORM U_PF_IPHONE
# else
# define U_PLATFORM U_PF_DARWIN
@@ -848,6 +848,21 @@ namespace std {
#endif
/**
+ * \def U_HIDDEN
+ * This is used to mark internal structs declared within external classes,
+ * to prevent the internal structs from having the same visibility as the
+ * class within which they are declared.
+ * @internal
+ */
+#ifdef U_HIDDEN
+ /* Use the predefined value. */
+#elif defined(__GNUC__)
+# define U_HIDDEN __attribute__((visibility("hidden")))
+#else
+# define U_HIDDEN
+#endif
+
+/**
* \def U_CALLCONV
* Similar to U_CDECL_BEGIN/U_CDECL_END, this qualifier is necessary
* in callback function typedefs to make sure that the calling convention
diff --git a/thirdparty/icu4c/common/unicode/rbbi.h b/thirdparty/icu4c/common/unicode/rbbi.h
index 0bad0d3897..d878243e3f 100644
--- a/thirdparty/icu4c/common/unicode/rbbi.h
+++ b/thirdparty/icu4c/common/unicode/rbbi.h
@@ -649,13 +649,6 @@ private:
// implementation
//=======================================================================
/**
- * Dumps caches and performs other actions associated with a complete change
- * in text or iteration position.
- * @internal (private)
- */
- void reset(void);
-
- /**
* Common initialization function, used by constructors and bufferClone.
* @internal (private)
*/
diff --git a/thirdparty/icu4c/common/unicode/resbund.h b/thirdparty/icu4c/common/unicode/resbund.h
index 7441592a0f..6e26a40591 100644
--- a/thirdparty/icu4c/common/unicode/resbund.h
+++ b/thirdparty/icu4c/common/unicode/resbund.h
@@ -484,7 +484,7 @@ public:
static UClassID U_EXPORT2 getStaticClassID();
private:
- ResourceBundle(); // default constructor not implemented
+ ResourceBundle() = delete; // default constructor not implemented
UResourceBundle *fResource;
void constructForLocale(const UnicodeString& path, const Locale& locale, UErrorCode& error);
diff --git a/thirdparty/icu4c/common/unicode/schriter.h b/thirdparty/icu4c/common/unicode/schriter.h
index 9dac099967..a2ab17982d 100644
--- a/thirdparty/icu4c/common/unicode/schriter.h
+++ b/thirdparty/icu4c/common/unicode/schriter.h
@@ -173,14 +173,6 @@ protected:
StringCharacterIterator();
/**
- * Sets the iterator to iterate over the provided string.
- * @param newText The string to be iterated over
- * @param newTextLength The length of the String
- * @stable ICU 2.0
- */
- void setText(const char16_t* newText, int32_t newTextLength);
-
- /**
* Copy of the iterated string object.
* @stable ICU 2.0
*/
diff --git a/thirdparty/icu4c/common/unicode/ubiditransform.h b/thirdparty/icu4c/common/unicode/ubiditransform.h
index 2dd7564010..24433aa8ac 100644
--- a/thirdparty/icu4c/common/unicode/ubiditransform.h
+++ b/thirdparty/icu4c/common/unicode/ubiditransform.h
@@ -28,7 +28,7 @@
/**
* \file
- * \brief Bidi Transformations
+ * \brief C API: Bidi Transformations
*/
/**
diff --git a/thirdparty/icu4c/common/unicode/uchar.h b/thirdparty/icu4c/common/unicode/uchar.h
index 253e6db173..6bb68e62a9 100644
--- a/thirdparty/icu4c/common/unicode/uchar.h
+++ b/thirdparty/icu4c/common/unicode/uchar.h
@@ -60,7 +60,7 @@ U_CDECL_BEGIN
* @see u_getUnicodeVersion
* @stable ICU 2.0
*/
-#define U_UNICODE_VERSION "14.0"
+#define U_UNICODE_VERSION "15.0"
/**
* \file
@@ -483,57 +483,55 @@ typedef enum UProperty {
* @stable ICU 62
*/
UCHAR_EXTENDED_PICTOGRAPHIC=64,
-#ifndef U_HIDE_DRAFT_API
/**
* Binary property of strings Basic_Emoji.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_BASIC_EMOJI=65,
/**
* Binary property of strings Emoji_Keycap_Sequence.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_EMOJI_KEYCAP_SEQUENCE=66,
/**
* Binary property of strings RGI_Emoji_Modifier_Sequence.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_RGI_EMOJI_MODIFIER_SEQUENCE=67,
/**
* Binary property of strings RGI_Emoji_Flag_Sequence.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_RGI_EMOJI_FLAG_SEQUENCE=68,
/**
* Binary property of strings RGI_Emoji_Tag_Sequence.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_RGI_EMOJI_TAG_SEQUENCE=69,
/**
* Binary property of strings RGI_Emoji_ZWJ_Sequence.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_RGI_EMOJI_ZWJ_SEQUENCE=70,
/**
* Binary property of strings RGI_Emoji.
* See https://www.unicode.org/reports/tr51/#Emoji_Sets
*
- * @draft ICU 70
+ * @stable ICU 70
*/
UCHAR_RGI_EMOJI=71,
-#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the last constant for binary Unicode properties.
@@ -1885,6 +1883,23 @@ enum UBlockCode {
/** @stable ICU 70 */
UBLOCK_ZNAMENNY_MUSICAL_NOTATION = 320, /*[1CF00]*/
+ // New blocks in Unicode 15.0
+
+ /** @stable ICU 72 */
+ UBLOCK_ARABIC_EXTENDED_C = 321, /*[10EC0]*/
+ /** @stable ICU 72 */
+ UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_H = 322, /*[31350]*/
+ /** @stable ICU 72 */
+ UBLOCK_CYRILLIC_EXTENDED_D = 323, /*[1E030]*/
+ /** @stable ICU 72 */
+ UBLOCK_DEVANAGARI_EXTENDED_A = 324, /*[11B00]*/
+ /** @stable ICU 72 */
+ UBLOCK_KAKTOVIK_NUMERALS = 325, /*[1D2C0]*/
+ /** @stable ICU 72 */
+ UBLOCK_KAWI = 326, /*[11F00]*/
+ /** @stable ICU 72 */
+ UBLOCK_NAG_MUNDARI = 327, /*[1E4D0]*/
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UBlockCode value.
@@ -1892,7 +1907,7 @@ enum UBlockCode {
*
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- UBLOCK_COUNT = 321,
+ UBLOCK_COUNT = 328,
#endif // U_HIDE_DEPRECATED_API
/** @stable ICU 2.0 */
@@ -2680,8 +2695,6 @@ typedef enum UVerticalOrientation {
U_CAPI UBool U_EXPORT2
u_hasBinaryProperty(UChar32 c, UProperty which);
-#ifndef U_HIDE_DRAFT_API
-
/**
* Returns true if the property is true for the string.
* Same as u_hasBinaryProperty(single code point, which)
@@ -2704,13 +2717,11 @@ u_hasBinaryProperty(UChar32 c, UProperty which);
* @see u_getBinaryPropertySet
* @see u_getIntPropertyValue
* @see u_getUnicodeVersion
- * @draft ICU 70
+ * @stable ICU 70
*/
U_CAPI UBool U_EXPORT2
u_stringHasBinaryProperty(const UChar *s, int32_t length, UProperty which);
-#endif // U_HIDE_DRAFT_API
-
/**
* Returns a frozen USet for a binary property.
* The library retains ownership over the returned object.
diff --git a/thirdparty/icu4c/common/unicode/ucharstrie.h b/thirdparty/icu4c/common/unicode/ucharstrie.h
index b6f9e3e075..064244a74c 100644
--- a/thirdparty/icu4c/common/unicode/ucharstrie.h
+++ b/thirdparty/icu4c/common/unicode/ucharstrie.h
@@ -409,7 +409,7 @@ private:
pos_(uchars_), remainingMatchLength_(-1) {}
// No assignment operator.
- UCharsTrie &operator=(const UCharsTrie &other);
+ UCharsTrie &operator=(const UCharsTrie &other) = delete;
inline void stop() {
pos_=NULL;
diff --git a/thirdparty/icu4c/common/unicode/ucharstriebuilder.h b/thirdparty/icu4c/common/unicode/ucharstriebuilder.h
index e0cb0acdc5..5c8aa33ffb 100644
--- a/thirdparty/icu4c/common/unicode/ucharstriebuilder.h
+++ b/thirdparty/icu4c/common/unicode/ucharstriebuilder.h
@@ -133,8 +133,8 @@ public:
}
private:
- UCharsTrieBuilder(const UCharsTrieBuilder &other); // no copy constructor
- UCharsTrieBuilder &operator=(const UCharsTrieBuilder &other); // no assignment operator
+ UCharsTrieBuilder(const UCharsTrieBuilder &other) = delete; // no copy constructor
+ UCharsTrieBuilder &operator=(const UCharsTrieBuilder &other) = delete; // no assignment operator
void buildUChars(UStringTrieBuildOption buildOption, UErrorCode &errorCode);
diff --git a/thirdparty/icu4c/common/unicode/ucnv_cb.h b/thirdparty/icu4c/common/unicode/ucnv_cb.h
index 41845d1bca..b4ef99208b 100644
--- a/thirdparty/icu4c/common/unicode/ucnv_cb.h
+++ b/thirdparty/icu4c/common/unicode/ucnv_cb.h
@@ -15,8 +15,8 @@
*/
/**
- * \file
- * \brief C UConverter functions to aid the writers of callbacks
+ * \file
+ * \brief C API: UConverter functions to aid the writers of callbacks
*
* <h2> Callback API for UConverter </h2>
*
diff --git a/thirdparty/icu4c/common/unicode/ucnv_err.h b/thirdparty/icu4c/common/unicode/ucnv_err.h
index a13d01db09..c743e5614f 100644
--- a/thirdparty/icu4c/common/unicode/ucnv_err.h
+++ b/thirdparty/icu4c/common/unicode/ucnv_err.h
@@ -12,7 +12,7 @@
/**
* \file
- * \brief C UConverter predefined error callbacks
+ * \brief C API: UConverter predefined error callbacks
*
* <h2>Error Behaviour Functions</h2>
* Defines some error behaviour functions called by ucnv_{from,to}Unicode
diff --git a/thirdparty/icu4c/common/unicode/ucnvsel.h b/thirdparty/icu4c/common/unicode/ucnvsel.h
index 3d7d3327f7..9373ec951b 100644
--- a/thirdparty/icu4c/common/unicode/ucnvsel.h
+++ b/thirdparty/icu4c/common/unicode/ucnvsel.h
@@ -36,6 +36,7 @@
/**
* \file
+ * \brief C API: Encoding/charset encoding selector
*
* A converter selector is built with a set of encoding/charset names
* and given an input string returns the set of names of the
diff --git a/thirdparty/icu4c/common/unicode/ucpmap.h b/thirdparty/icu4c/common/unicode/ucpmap.h
index 31e1365cac..a740bd160f 100644
--- a/thirdparty/icu4c/common/unicode/ucpmap.h
+++ b/thirdparty/icu4c/common/unicode/ucpmap.h
@@ -13,8 +13,7 @@ U_CDECL_BEGIN
/**
* \file
- *
- * This file defines an abstract map from Unicode code points to integer values.
+ * \brief C API: This file defines an abstract map from Unicode code points to integer values.
*
* @see UCPMap
* @see UCPTrie
diff --git a/thirdparty/icu4c/common/unicode/ucptrie.h b/thirdparty/icu4c/common/unicode/ucptrie.h
index e2547ae2ee..dadef79c51 100644
--- a/thirdparty/icu4c/common/unicode/ucptrie.h
+++ b/thirdparty/icu4c/common/unicode/ucptrie.h
@@ -19,8 +19,7 @@ U_CDECL_BEGIN
/**
* \file
- *
- * This file defines an immutable Unicode code point trie.
+ * \brief C API: This file defines an immutable Unicode code point trie.
*
* @see UCPTrie
* @see UMutableCPTrie
diff --git a/thirdparty/icu4c/common/unicode/uloc.h b/thirdparty/icu4c/common/unicode/uloc.h
index b0bdbe1b87..21179c1b62 100644
--- a/thirdparty/icu4c/common/unicode/uloc.h
+++ b/thirdparty/icu4c/common/unicode/uloc.h
@@ -26,9 +26,9 @@
#include "unicode/utypes.h"
#include "unicode/uenum.h"
-/**
+/**
* \file
- * \brief C API: Locale
+ * \brief C API: Locale ID functionality similar to C++ class Locale
*
* <h2> ULoc C API for Locale </h2>
* A <code>Locale</code> represents a specific geographical, political,
diff --git a/thirdparty/icu4c/common/unicode/umachine.h b/thirdparty/icu4c/common/unicode/umachine.h
index 09c887c80e..6640606272 100644
--- a/thirdparty/icu4c/common/unicode/umachine.h
+++ b/thirdparty/icu4c/common/unicode/umachine.h
@@ -282,14 +282,8 @@ typedef int8_t UBool;
*/
#ifdef U_DEFINE_FALSE_AND_TRUE
// Use the predefined value.
-#elif defined(U_COMBINED_IMPLEMENTATION) || \
- defined(U_COMMON_IMPLEMENTATION) || defined(U_I18N_IMPLEMENTATION) || \
- defined(U_IO_IMPLEMENTATION) || defined(U_LAYOUTEX_IMPLEMENTATION) || \
- defined(U_TOOLUTIL_IMPLEMENTATION)
- // Inside ICU: Keep FALSE & TRUE available.
-# define U_DEFINE_FALSE_AND_TRUE 1
#else
- // Outside ICU: Avoid collision with non-macro definitions of FALSE & TRUE.
+ // Default to avoiding collision with non-macro definitions of FALSE & TRUE.
# define U_DEFINE_FALSE_AND_TRUE 0
#endif
diff --git a/thirdparty/icu4c/common/unicode/umisc.h b/thirdparty/icu4c/common/unicode/umisc.h
index 213290b9af..4e9dda7450 100644
--- a/thirdparty/icu4c/common/unicode/umisc.h
+++ b/thirdparty/icu4c/common/unicode/umisc.h
@@ -21,9 +21,9 @@
/**
* \file
- * \brief C API:misc definitions
+ * \brief C API: Miscellaneous definitions
*
- * This file contains miscellaneous definitions for the C APIs.
+ * This file contains miscellaneous definitions for the C APIs.
*/
U_CDECL_BEGIN
diff --git a/thirdparty/icu4c/common/unicode/umutablecptrie.h b/thirdparty/icu4c/common/unicode/umutablecptrie.h
index 3b950055da..d60fd61819 100644
--- a/thirdparty/icu4c/common/unicode/umutablecptrie.h
+++ b/thirdparty/icu4c/common/unicode/umutablecptrie.h
@@ -21,8 +21,7 @@ U_CDECL_BEGIN
/**
* \file
- *
- * This file defines a mutable Unicode code point trie.
+ * \brief C API: This file defines a mutable Unicode code point trie.
*
* @see UCPTrie
* @see UMutableCPTrie
diff --git a/thirdparty/icu4c/common/unicode/uniset.h b/thirdparty/icu4c/common/unicode/uniset.h
index 310c7c8d20..33e35c4def 100644
--- a/thirdparty/icu4c/common/unicode/uniset.h
+++ b/thirdparty/icu4c/common/unicode/uniset.h
@@ -794,13 +794,11 @@ public:
*/
virtual UBool isEmpty(void) const;
-#ifndef U_HIDE_DRAFT_API
/**
* @return true if this set contains multi-character strings or the empty string.
- * @draft ICU 70
+ * @stable ICU 70
*/
UBool hasStrings() const;
-#endif // U_HIDE_DRAFT_API
/**
* Returns true if this set contains the given character.
@@ -1678,8 +1676,6 @@ private:
UnicodeString& rebuiltPat,
UErrorCode& ec);
- static const UnicodeSet* getInclusions(int32_t src, UErrorCode &status);
-
/**
* A filter that returns true if the given code point should be
* included in the UnicodeSet being constructed.
@@ -1700,11 +1696,6 @@ private:
const UnicodeSet* inclusions,
UErrorCode &status);
- // UCPMap is now stable ICU 63
- void applyIntPropertyValue(const UCPMap *map,
- UCPMapValueFilter *filter, const void *context,
- UErrorCode &errorCode);
-
/**
* Set the new pattern to cache.
*/
diff --git a/thirdparty/icu4c/common/unicode/urename.h b/thirdparty/icu4c/common/unicode/urename.h
index d9f9b8f336..d3e23b8fa7 100644
--- a/thirdparty/icu4c/common/unicode/urename.h
+++ b/thirdparty/icu4c/common/unicode/urename.h
@@ -925,6 +925,12 @@
#define udatpg_setDateTimeFormatForStyle U_ICU_ENTRY_POINT_RENAME(udatpg_setDateTimeFormatForStyle)
#define udatpg_setDecimal U_ICU_ENTRY_POINT_RENAME(udatpg_setDecimal)
#define udict_swap U_ICU_ENTRY_POINT_RENAME(udict_swap)
+#define udispopt_fromGrammaticalCaseIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_fromGrammaticalCaseIdentifier)
+#define udispopt_fromNounClassIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_fromNounClassIdentifier)
+#define udispopt_fromPluralCategoryIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_fromPluralCategoryIdentifier)
+#define udispopt_getGrammaticalCaseIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_getGrammaticalCaseIdentifier)
+#define udispopt_getNounClassIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_getNounClassIdentifier)
+#define udispopt_getPluralCategoryIdentifier U_ICU_ENTRY_POINT_RENAME(udispopt_getPluralCategoryIdentifier)
#define udtitvfmt_close U_ICU_ENTRY_POINT_RENAME(udtitvfmt_close)
#define udtitvfmt_closeResult U_ICU_ENTRY_POINT_RENAME(udtitvfmt_closeResult)
#define udtitvfmt_format U_ICU_ENTRY_POINT_RENAME(udtitvfmt_format)
@@ -1247,6 +1253,7 @@
#define unum_getLocaleByType U_ICU_ENTRY_POINT_RENAME(unum_getLocaleByType)
#define unum_getSymbol U_ICU_ENTRY_POINT_RENAME(unum_getSymbol)
#define unum_getTextAttribute U_ICU_ENTRY_POINT_RENAME(unum_getTextAttribute)
+#define unum_hasAttribute U_ICU_ENTRY_POINT_RENAME(unum_hasAttribute)
#define unum_open U_ICU_ENTRY_POINT_RENAME(unum_open)
#define unum_parse U_ICU_ENTRY_POINT_RENAME(unum_parse)
#define unum_parseDecimal U_ICU_ENTRY_POINT_RENAME(unum_parseDecimal)
diff --git a/thirdparty/icu4c/common/unicode/uscript.h b/thirdparty/icu4c/common/unicode/uscript.h
index 6cb1532808..dc97ab2ba5 100644
--- a/thirdparty/icu4c/common/unicode/uscript.h
+++ b/thirdparty/icu4c/common/unicode/uscript.h
@@ -495,6 +495,11 @@ typedef enum UScriptCode {
/** @stable ICU 70 */
USCRIPT_VITHKUQI = 197,/* Vith */
+ /** @stable ICU 72 */
+ USCRIPT_KAWI = 198,/* Kawi */
+ /** @stable ICU 72 */
+ USCRIPT_NAG_MUNDARI = 199,/* Nagm */
+
#ifndef U_HIDE_DEPRECATED_API
/**
* One more than the highest normal UScriptCode value.
@@ -502,7 +507,7 @@ typedef enum UScriptCode {
*
* @deprecated ICU 58 The numeric value may change over time, see ICU ticket #12420.
*/
- USCRIPT_CODE_LIMIT = 198
+ USCRIPT_CODE_LIMIT = 200
#endif // U_HIDE_DEPRECATED_API
} UScriptCode;
diff --git a/thirdparty/icu4c/common/unicode/uset.h b/thirdparty/icu4c/common/unicode/uset.h
index 33332f2d36..5dd890e148 100644
--- a/thirdparty/icu4c/common/unicode/uset.h
+++ b/thirdparty/icu4c/common/unicode/uset.h
@@ -850,15 +850,13 @@ uset_removeAllStrings(USet* set);
U_CAPI UBool U_EXPORT2
uset_isEmpty(const USet* set);
-#ifndef U_HIDE_DRAFT_API
/**
* @param set the set
* @return true if this set contains multi-character strings or the empty string.
- * @draft ICU 70
+ * @stable ICU 70
*/
U_CAPI UBool U_EXPORT2
uset_hasStrings(const USet *set);
-#endif // U_HIDE_DRAFT_API
/**
* Returns true if the given USet contains the given character.
@@ -941,18 +939,16 @@ uset_charAt(const USet* set, int32_t charIndex);
U_CAPI int32_t U_EXPORT2
uset_size(const USet* set);
-#ifndef U_HIDE_DRAFT_API
/**
* @param set the set
* @return the number of ranges in this set.
- * @draft ICU 70
+ * @stable ICU 70
* @see uset_getItemCount
* @see uset_getItem
* @see uset_size
*/
U_CAPI int32_t U_EXPORT2
uset_getRangeCount(const USet *set);
-#endif // U_HIDE_DRAFT_API
/**
* Returns the number of items in this set. An item is either a range
diff --git a/thirdparty/icu4c/common/unicode/usetiter.h b/thirdparty/icu4c/common/unicode/usetiter.h
index 5834c308e4..34992d94b7 100644
--- a/thirdparty/icu4c/common/unicode/usetiter.h
+++ b/thirdparty/icu4c/common/unicode/usetiter.h
@@ -164,14 +164,13 @@ class U_COMMON_API UnicodeSetIterator U_FINAL : public UObject {
*/
const UnicodeString& getString();
-#ifndef U_HIDE_DRAFT_API
/**
* Skips over the remaining code points/ranges, if any.
* A following call to next() or nextRange() will yield a string, if there is one.
* No-op if next() would return false, or if it would yield a string anyway.
*
* @return *this
- * @draft ICU 70
+ * @stable ICU 70
* @see UnicodeSet#strings()
*/
inline UnicodeSetIterator &skipToStrings() {
@@ -181,7 +180,6 @@ class U_COMMON_API UnicodeSetIterator U_FINAL : public UObject {
nextElement = 0;
return *this;
}
-#endif // U_HIDE_DRAFT_API
/**
* Advances the iteration position to the next element in the set,
diff --git a/thirdparty/icu4c/common/unicode/utf_old.h b/thirdparty/icu4c/common/unicode/utf_old.h
index 160f5ad0a9..6b868c7280 100644
--- a/thirdparty/icu4c/common/unicode/utf_old.h
+++ b/thirdparty/icu4c/common/unicode/utf_old.h
@@ -293,10 +293,10 @@ typedef int32_t UTextOffset;
#ifdef U_UTF8_IMPL
// No forward declaration if compiling utf_impl.cpp, which defines utf8_countTrailBytes.
#elif defined(U_STATIC_IMPLEMENTATION) || defined(U_COMMON_IMPLEMENTATION)
-U_CFUNC const uint8_t utf8_countTrailBytes[];
+U_CAPI const uint8_t utf8_countTrailBytes[];
#else
-U_CFUNC U_IMPORT const uint8_t utf8_countTrailBytes[]; /* U_IMPORT2? */ /*U_IMPORT*/
-#endif
+U_CFUNC U_IMPORT const uint8_t utf8_countTrailBytes[];
+#endif
/**
* Count the trail bytes for a UTF-8 lead byte.
diff --git a/thirdparty/icu4c/common/unicode/uvernum.h b/thirdparty/icu4c/common/unicode/uvernum.h
index 2706e0b060..a93f3509ef 100644
--- a/thirdparty/icu4c/common/unicode/uvernum.h
+++ b/thirdparty/icu4c/common/unicode/uvernum.h
@@ -31,19 +31,12 @@
* renaming macro, and copyright
*
* The following files need to be updated as well, which can be done
- * by running the UNIX makefile target 'update-windows-makefiles' in icu/source.
+ * by running the UNIX makefile target 'update-windows-makefiles' in icu4c/source.
*
- *
- * source/common/common_uwp.vcxproj
- * source/common/common.vcxproj - update 'Output file name' on the link tab so
- * that it contains the new major/minor combination
- * source/i18n/i18n.vcxproj - same as for the common.vcxproj
- * source/i18n/i18n_uwp.vcxproj - same as for the common_uwp.vcxproj
- * source/layoutex/layoutex.vcproj - same
- * source/stubdata/stubdata.vcproj - same as for the common.vcxproj
- * source/io/io.vcproj - same as for the common.vcxproj
+ * source/allinone/Build.Windows.IcuVersion.props - Update the IcuMajorVersion
* source/data/makedata.mak - change U_ICUDATA_NAME so that it contains
- * the new major/minor combination and the Unicode version.
+ * the new major/minor combination, and UNICODE_VERSION
+ * for the Unicode version.
*/
#ifndef UVERNUM_H
@@ -60,7 +53,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION_MAJOR_NUM 71
+#define U_ICU_VERSION_MAJOR_NUM 72
/** The current ICU minor version as an integer.
* This value will change in the subsequent releases of ICU
@@ -86,7 +79,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SUFFIX _71
+#define U_ICU_VERSION_SUFFIX _72
/**
* \def U_DEF2_ICU_ENTRY_POINT_RENAME
@@ -139,7 +132,7 @@
* This value will change in the subsequent releases of ICU
* @stable ICU 2.4
*/
-#define U_ICU_VERSION "71.1"
+#define U_ICU_VERSION "72.1"
/**
* The current ICU library major version number as a string, for library name suffixes.
@@ -152,13 +145,13 @@
*
* @stable ICU 2.6
*/
-#define U_ICU_VERSION_SHORT "71"
+#define U_ICU_VERSION_SHORT "72"
#ifndef U_HIDE_INTERNAL_API
/** Data version in ICU4C.
* @internal ICU 4.4 Internal Use Only
**/
-#define U_ICU_DATA_VERSION "71.1"
+#define U_ICU_DATA_VERSION "72.1"
#endif /* U_HIDE_INTERNAL_API */
/*===========================================================================
diff --git a/thirdparty/icu4c/common/unifiedcache.cpp b/thirdparty/icu4c/common/unifiedcache.cpp
index 493ab79f6d..cfb000b2c8 100644
--- a/thirdparty/icu4c/common/unifiedcache.cpp
+++ b/thirdparty/icu4c/common/unifiedcache.cpp
@@ -22,7 +22,7 @@
static icu::UnifiedCache *gCache = NULL;
static std::mutex *gCacheMutex = nullptr;
static std::condition_variable *gInProgressValueAddedCond;
-static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCacheInitOnce {};
static const int32_t MAX_EVICT_ITERATIONS = 10;
static const int32_t DEFAULT_MAX_UNUSED = 1000;
@@ -38,27 +38,27 @@ static UBool U_CALLCONV unifiedcache_cleanup() {
gCacheMutex = nullptr;
gInProgressValueAddedCond->~condition_variable();
gInProgressValueAddedCond = nullptr;
- return TRUE;
+ return true;
}
U_CDECL_END
U_NAMESPACE_BEGIN
-U_CAPI int32_t U_EXPORT2
+int32_t U_EXPORT2
ucache_hashKeys(const UHashTok key) {
const CacheKeyBase *ckey = (const CacheKeyBase *) key.pointer;
return ckey->hashCode();
}
-U_CAPI UBool U_EXPORT2
+UBool U_EXPORT2
ucache_compareKeys(const UHashTok key1, const UHashTok key2) {
const CacheKeyBase *p1 = (const CacheKeyBase *) key1.pointer;
const CacheKeyBase *p2 = (const CacheKeyBase *) key2.pointer;
return *p1 == *p2;
}
-U_CAPI void U_EXPORT2
+void U_EXPORT2
ucache_deleteKey(void *obj) {
CacheKeyBase *p = (CacheKeyBase *) obj;
delete p;
@@ -161,7 +161,7 @@ void UnifiedCache::flush() const {
// Use a loop in case cache items that are flushed held hard references to
// other cache items making those additional cache items eligible for
// flushing.
- while (_flush(FALSE));
+ while (_flush(false));
}
void UnifiedCache::handleUnreferencedObject() const {
@@ -225,7 +225,7 @@ UnifiedCache::~UnifiedCache() {
// each other and entries with hard references from outside the cache.
// Nothing we can do about these so proceed to wipe out the cache.
std::lock_guard<std::mutex> lock(*gCacheMutex);
- _flush(TRUE);
+ _flush(true);
}
uhash_close(fHashtable);
fHashtable = nullptr;
@@ -244,7 +244,7 @@ UnifiedCache::_nextElement() const {
}
UBool UnifiedCache::_flush(UBool all) const {
- UBool result = FALSE;
+ UBool result = false;
int32_t origSize = uhash_count(fHashtable);
for (int32_t i = 0; i < origSize; ++i) {
const UHashElement *element = _nextElement();
@@ -257,7 +257,7 @@ UBool UnifiedCache::_flush(UBool all) const {
U_ASSERT(sharedObject->cachePtr == this);
uhash_removeElement(fHashtable, element);
removeSoftRef(sharedObject); // Deletes the sharedObject when softRefCount goes to zero.
- result = TRUE;
+ result = true;
}
}
return result;
@@ -365,14 +365,14 @@ UBool UnifiedCache::_poll(
// fetch out the contents and return them.
if (element != NULL) {
_fetch(element, value, status);
- return TRUE;
+ return true;
}
// The hash table contained nothing for this key.
// Insert an inProgress place holder value.
// Our caller will create the final value and update the hash table.
_putNew(key, fNoValue, U_ZERO_ERROR, status);
- return FALSE;
+ return false;
}
void UnifiedCache::_get(
@@ -471,7 +471,7 @@ UBool UnifiedCache::_isEvictable(const UHashElement *element) const
// Entries that are under construction are never evictable
if (_inProgress(theValue, theKey->fCreationStatus)) {
- return FALSE;
+ return false;
}
// We can evict entries that are either not a primary or have just
diff --git a/thirdparty/icu4c/common/unifiedcache.h b/thirdparty/icu4c/common/unifiedcache.h
index 07a734b8bd..4b9222124a 100644
--- a/thirdparty/icu4c/common/unifiedcache.h
+++ b/thirdparty/icu4c/common/unifiedcache.h
@@ -354,8 +354,8 @@ class U_COMMON_API UnifiedCache : public UnifiedCacheBase {
mutable int64_t fAutoEvictedCount;
SharedObject *fNoValue;
- UnifiedCache(const UnifiedCache &other);
- UnifiedCache &operator=(const UnifiedCache &other);
+ UnifiedCache(const UnifiedCache &other) = delete;
+ UnifiedCache &operator=(const UnifiedCache &other) = delete;
/**
* Flushes the contents of the cache. If cache values hold references to other
diff --git a/thirdparty/icu4c/common/uniset.cpp b/thirdparty/icu4c/common/uniset.cpp
index 92a81a1a02..4faace525c 100644
--- a/thirdparty/icu4c/common/uniset.cpp
+++ b/thirdparty/icu4c/common/uniset.cpp
@@ -82,7 +82,7 @@ static int32_t _dbgCount = 0;
static inline void _dbgct(UnicodeSet* set) {
UnicodeString str;
- set->toPattern(str, TRUE);
+ set->toPattern(str, true);
char buf[40];
str.extract(0, 39, buf, "");
printf("DEBUG UnicodeSet: ct 0x%08X; %d %s\n", set, ++_dbgCount, buf);
@@ -90,7 +90,7 @@ static inline void _dbgct(UnicodeSet* set) {
static inline void _dbgdt(UnicodeSet* set) {
UnicodeString str;
- set->toPattern(str, TRUE);
+ set->toPattern(str, true);
char buf[40];
str.extract(0, 39, buf, "");
printf("DEBUG UnicodeSet: dt 0x%08X; %d %s\n", set, --_dbgCount, buf);
@@ -204,7 +204,7 @@ UnicodeSet::~UnicodeSet() {
* Assigns this object to be a copy of another.
*/
UnicodeSet& UnicodeSet::operator=(const UnicodeSet& o) {
- return copyFrom(o, FALSE);
+ return copyFrom(o, false);
}
UnicodeSet& UnicodeSet::copyFrom(const UnicodeSet& o, UBool asThawed) {
@@ -265,7 +265,7 @@ UnicodeSet* UnicodeSet::clone() const {
}
UnicodeSet *UnicodeSet::cloneAsThawed() const {
- return new UnicodeSet(*this, TRUE);
+ return new UnicodeSet(*this, true);
}
/**
@@ -352,7 +352,7 @@ UBool UnicodeSet::contains(UChar32 c) const {
return stringSpan->contains(c);
}
if (c >= UNICODESET_HIGH) { // Don't need to check LOW bound
- return FALSE;
+ return false;
}
int32_t i = findCodePoint(c);
return (UBool)(i & 1); // return true if odd
@@ -447,7 +447,7 @@ UBool UnicodeSet::containsAll(const UnicodeSet& c) const {
int32_t n = c.getRangeCount();
for (int i=0; i<n; ++i) {
if (!contains(c.getRangeStart(i), c.getRangeEnd(i))) {
- return FALSE;
+ return false;
}
}
return !c.hasStrings() || (strings != nullptr && strings->containsAll(*c.strings));
@@ -493,7 +493,7 @@ UBool UnicodeSet::containsNone(const UnicodeSet& c) const {
int32_t n = c.getRangeCount();
for (int32_t i=0; i<n; ++i) {
if (!containsNone(c.getRangeStart(i), c.getRangeEnd(i))) {
- return FALSE;
+ return false;
}
}
return strings == nullptr || !c.hasStrings() || strings->containsNone(*c.strings);
@@ -531,10 +531,10 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
UChar32 high = getRangeEnd(i);
if ((low & ~0xFF) == (high & ~0xFF)) {
if ((low & 0xFF) <= v && v <= (high & 0xFF)) {
- return TRUE;
+ return true;
}
} else if ((low & 0xFF) <= v || v <= (high & 0xFF)) {
- return TRUE;
+ return true;
}
}
if (hasStrings()) {
@@ -545,11 +545,11 @@ UBool UnicodeSet::matchesIndexValue(uint8_t v) const {
}
UChar32 c = s.char32At(0);
if ((c & 0xFF) == v) {
- return TRUE;
+ return true;
}
}
}
- return FALSE;
+ return false;
}
/**
@@ -1603,24 +1603,24 @@ int32_t UnicodeSet::serialize(uint16_t *dest, int32_t destCapacity, UErrorCode&
//----------------------------------------------------------------
/**
- * Allocate our strings vector and return TRUE if successful.
+ * Allocate our strings vector and return true if successful.
*/
UBool UnicodeSet::allocateStrings(UErrorCode &status) {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
strings = new UVector(uprv_deleteUObject,
uhash_compareUnicodeString, 1, status);
if (strings == NULL) { // Check for memory allocation error.
status = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
if (U_FAILURE(status)) {
delete strings;
strings = NULL;
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
int32_t UnicodeSet::nextCapacity(int32_t minCapacity) {
diff --git a/thirdparty/icu4c/common/uniset_closure.cpp b/thirdparty/icu4c/common/uniset_closure.cpp
index 882231ba1a..d7dab2a17b 100644
--- a/thirdparty/icu4c/common/uniset_closure.cpp
+++ b/thirdparty/icu4c/common/uniset_closure.cpp
@@ -74,7 +74,7 @@ UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
if (options & USET_IGNORE_SPACE) {
// Skip over trailing whitespace
- ICU_Utility::skipWhitespace(pattern, i, TRUE);
+ ICU_Utility::skipWhitespace(pattern, i, true);
}
if (i != pattern.length()) {
@@ -141,7 +141,7 @@ addCaseMapping(UnicodeSet &set, int32_t result, const UChar *full, UnicodeString
set.add(result);
} else {
// add a string case mapping from full with length result
- str.setTo((UBool)FALSE, full, result);
+ str.setTo((UBool)false, full, result);
set.add(str);
}
}
diff --git a/thirdparty/icu4c/common/uniset_props.cpp b/thirdparty/icu4c/common/uniset_props.cpp
index 49d6caabc7..48c0a26a71 100644
--- a/thirdparty/icu4c/common/uniset_props.cpp
+++ b/thirdparty/icu4c/common/uniset_props.cpp
@@ -62,7 +62,7 @@ U_CDECL_BEGIN
static UBool U_CALLCONV uset_cleanup();
static UnicodeSet *uni32Singleton;
-static icu::UInitOnce uni32InitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce uni32InitOnce {};
/**
* Cleanup function for UnicodeSet
@@ -71,7 +71,7 @@ static UBool U_CALLCONV uset_cleanup(void) {
delete uni32Singleton;
uni32Singleton = NULL;
uni32InitOnce.reset();
- return TRUE;
+ return true;
}
U_CDECL_END
@@ -170,7 +170,7 @@ UnicodeSet& UnicodeSet::applyPattern(const UnicodeString& pattern,
int32_t i = pos.getIndex();
// Skip over trailing whitespace
- ICU_Utility::skipWhitespace(pattern, i, TRUE);
+ ICU_Utility::skipWhitespace(pattern, i, true);
if (i != pattern.length()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
@@ -279,7 +279,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
}
UnicodeString patLocal, buf;
- UBool usePat = FALSE;
+ UBool usePat = false;
UnicodeSetPointer scratch;
RuleCharacterIterator::Pos backup;
@@ -289,7 +289,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
UChar32 lastChar = 0;
UChar op = 0;
- UBool invert = FALSE;
+ UBool invert = false;
clear();
@@ -299,7 +299,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
(lastItem == 2 && (op == 0 || op == u'-' || op == u'&')));
UChar32 c = 0;
- UBool literal = FALSE;
+ UBool literal = false;
UnicodeSet* nested = 0; // alias - do not delete
// -------- Check for property pattern
@@ -336,7 +336,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
if (c == u'^' && !literal) {
- invert = TRUE;
+ invert = true;
patLocal.append(u'^');
chars.getPos(backup); // prepare to backup
c = chars.next(opts, literal, ec);
@@ -345,7 +345,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// Fall through to handle special leading '-';
// otherwise restart loop for nested [], \p{}, etc.
if (c == u'-') {
- literal = TRUE;
+ literal = true;
// Fall through to handle literal '-' below
} else {
chars.setPos(backup); // backup
@@ -381,7 +381,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
return;
}
add(lastChar, lastChar);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
lastItem = 0;
op = 0;
}
@@ -408,11 +408,11 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (U_FAILURE(ec)) return;
break;
case 3: // `nested' already parsed
- nested->_toPattern(patLocal, FALSE);
+ nested->_toPattern(patLocal, false);
break;
}
- usePat = TRUE;
+ usePat = true;
if (mode == 0) {
// Entire pattern is a category; leave parse loop
@@ -454,7 +454,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
case u']':
if (lastItem == 1) {
add(lastChar, lastChar);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
}
// Treat final trailing '-' as a literal
if (op == u'-') {
@@ -508,17 +508,17 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
}
if (lastItem == 1) {
add(lastChar, lastChar);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
}
lastItem = 0;
buf.truncate(0);
{
- UBool ok = FALSE;
+ UBool ok = false;
while (!chars.atEnd()) {
c = chars.next(opts, literal, ec);
if (U_FAILURE(ec)) return;
if (c == u'}' && !literal) {
- ok = TRUE;
+ ok = true;
break;
}
buf.append(c);
@@ -534,7 +534,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
// processing
add(buf);
patLocal.append(u'{');
- _appendToPat(patLocal, buf, FALSE);
+ _appendToPat(patLocal, buf, false);
patLocal.append(u'}');
continue;
case SymbolTable::SYMBOL_REF:
@@ -557,10 +557,10 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (anchor && op == 0) {
if (lastItem == 1) {
add(lastChar, lastChar);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
}
add(U_ETHER);
- usePat = TRUE;
+ usePat = true;
patLocal.append((UChar) SymbolTable::SYMBOL_REF);
patLocal.append(u']');
mode = 2;
@@ -594,14 +594,14 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
return;
}
add(lastChar, c);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
patLocal.append(op);
- _appendToPat(patLocal, c, FALSE);
+ _appendToPat(patLocal, c, false);
lastItem = 0;
op = 0;
} else {
add(lastChar, lastChar);
- _appendToPat(patLocal, lastChar, FALSE);
+ _appendToPat(patLocal, lastChar, false);
lastChar = c;
}
break;
@@ -646,7 +646,7 @@ void UnicodeSet::applyPattern(RuleCharacterIterator& chars,
if (usePat) {
rebuiltPat.append(patLocal);
} else {
- _generatePattern(rebuiltPat, FALSE);
+ _generatePattern(rebuiltPat, false);
}
if (isBogus() && U_SUCCESS(ec)) {
// We likely ran out of memory. AHHH!
@@ -756,12 +756,12 @@ static UBool mungeCharName(char* dst, const char* src, int32_t dstCapacity) {
if (ch == ' ' && (j==0 || (j>0 && dst[j-1]==' '))) {
continue;
}
- if (j >= dstCapacity) return FALSE;
+ if (j >= dstCapacity) return false;
dst[j++] = ch;
}
if (j > 0 && dst[j-1] == ' ') --j;
dst[j] = 0;
- return TRUE;
+ return true;
}
} // namespace
@@ -789,7 +789,7 @@ UnicodeSet::applyIntPropertyValue(UProperty prop, int32_t value, UErrorCode& ec)
if (value == 0 || value == 1) {
const USet *set = u_getBinaryPropertySet(prop, &ec);
if (U_FAILURE(ec)) { return *this; }
- copyFrom(*UnicodeSet::fromUSet(set), TRUE);
+ copyFrom(*UnicodeSet::fromUSet(set), true);
if (value == 0) {
complement().removeAllStrings(); // code point complement
}
@@ -830,7 +830,7 @@ UnicodeSet::applyPropertyAlias(const UnicodeString& prop,
UProperty p;
int32_t v;
- UBool invert = FALSE;
+ UBool invert = false;
if (value.length() > 0) {
p = u_getPropertyEnum(pname.data());
@@ -948,7 +948,7 @@ UnicodeSet::applyPropertyAlias(const UnicodeString& prop,
// [:Assigned:]=[:^Cn:]
p = UCHAR_GENERAL_CATEGORY_MASK;
v = U_GC_CN_MASK;
- invert = TRUE;
+ invert = true;
} else {
FAIL(ec);
}
@@ -980,7 +980,7 @@ UBool UnicodeSet::resemblesPropertyPattern(const UnicodeString& pattern,
int32_t pos) {
// Patterns are at least 5 characters long
if ((pos+5) > pattern.length()) {
- return FALSE;
+ return false;
}
// Look for an opening [:, [:^, \p, or \P
@@ -997,8 +997,8 @@ UBool UnicodeSet::resemblesPropertyPattern(const UnicodeString& pattern,
*/
UBool UnicodeSet::resemblesPropertyPattern(RuleCharacterIterator& chars,
int32_t iterOpts) {
- // NOTE: literal will always be FALSE, because we don't parse escapes.
- UBool result = FALSE, literal;
+ // NOTE: literal will always be false, because we don't parse escapes.
+ UBool result = false, literal;
UErrorCode ec = U_ZERO_ERROR;
iterOpts &= ~RuleCharacterIterator::PARSE_ESCAPES;
RuleCharacterIterator::Pos pos;
@@ -1022,9 +1022,9 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
UErrorCode &ec) {
int32_t pos = ppos.getIndex();
- UBool posix = FALSE; // true for [:pat:], false for \p{pat} \P{pat} \N{pat}
- UBool isName = FALSE; // true for \N{pat}, o/w false
- UBool invert = FALSE;
+ UBool posix = false; // true for [:pat:], false for \p{pat} \P{pat} \N{pat}
+ UBool isName = false; // true for \N{pat}, o/w false
+ UBool invert = false;
if (U_FAILURE(ec)) return *this;
@@ -1036,12 +1036,12 @@ UnicodeSet& UnicodeSet::applyPropertyPattern(const UnicodeString& pattern,
// On entry, ppos should point to one of the following locations:
// Look for an opening [:, [:^, \p, or \P
if (isPOSIXOpen(pattern, pos)) {
- posix = TRUE;
+ posix = true;
pos += 2;
pos = ICU_Utility::skipWhitespace(pattern, pos);
if (pos < pattern.length() && pattern.charAt(pos) == u'^') {
++pos;
- invert = TRUE;
+ invert = true;
}
} else if (isPerlOpen(pattern, pos) || isNameOpen(pattern, pos)) {
UChar c = pattern.charAt(pos+1);
diff --git a/thirdparty/icu4c/common/unisetspan.cpp b/thirdparty/icu4c/common/unisetspan.cpp
index fe0d74f5b2..e4277c5be6 100644
--- a/thirdparty/icu4c/common/unisetspan.cpp
+++ b/thirdparty/icu4c/common/unisetspan.cpp
@@ -98,7 +98,7 @@ public:
i-=capacity;
}
if(list[i]) {
- list[i]=FALSE;
+ list[i]=false;
--length;
}
start=i;
@@ -111,7 +111,7 @@ public:
if(i>=capacity) {
i-=capacity;
}
- list[i]=TRUE;
+ list[i]=true;
++length;
}
@@ -132,7 +132,7 @@ public:
int32_t i=start, result;
while(++i<capacity) {
if(list[i]) {
- list[i]=FALSE;
+ list[i]=false;
--length;
result=i-start;
start=i;
@@ -148,7 +148,7 @@ public:
while(!list[i]) {
++i;
}
- list[i]=FALSE;
+ list[i]=false;
--length;
start=i;
return result+=i;
@@ -226,7 +226,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
int32_t stringsLength=strings.size();
int32_t i, spanLength;
- UBool someRelevant=FALSE;
+ UBool someRelevant=false;
for(i=0; i<stringsLength; ++i) {
const UnicodeString &string=*(const UnicodeString *)strings.elementAt(i);
const UChar *s16=string.getBuffer();
@@ -237,9 +237,9 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
UBool thisRelevant;
spanLength=spanSet.span(s16, length16, USET_SPAN_CONTAINED);
if(spanLength<length16) { // Relevant string.
- someRelevant=thisRelevant=TRUE;
+ someRelevant=thisRelevant=true;
} else {
- thisRelevant=FALSE;
+ thisRelevant=false;
}
if((which&UTF16) && length16>maxLength16) {
maxLength16=length16;
@@ -284,7 +284,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSet &set,
} else {
utf8Lengths=(int32_t *)uprv_malloc(allocSize);
if(utf8Lengths==NULL) {
- maxLength16=maxLength8=0; // Prevent usage by making needsStringSpanUTF16/8() return FALSE.
+ maxLength16=maxLength8=0; // Prevent usage by making needsStringSpanUTF16/8() return false.
return; // Out of memory.
}
}
@@ -399,7 +399,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSetStringSpan &otherStri
utf8Lengths(NULL), spanLengths(NULL), utf8(NULL),
utf8Length(otherStringSpan.utf8Length),
maxLength16(otherStringSpan.maxLength16), maxLength8(otherStringSpan.maxLength8),
- all(TRUE) {
+ all(true) {
if(otherStringSpan.pSpanNotSet==&otherStringSpan.spanSet) {
pSpanNotSet=&spanSet;
} else {
@@ -415,7 +415,7 @@ UnicodeSetStringSpan::UnicodeSetStringSpan(const UnicodeSetStringSpan &otherStri
} else {
utf8Lengths=(int32_t *)uprv_malloc(allocSize);
if(utf8Lengths==NULL) {
- maxLength16=maxLength8=0; // Prevent usage by making needsStringSpanUTF16/8() return FALSE.
+ maxLength16=maxLength8=0; // Prevent usage by making needsStringSpanUTF16/8() return false.
return; // Out of memory.
}
}
@@ -454,20 +454,20 @@ static inline UBool
matches16(const UChar *s, const UChar *t, int32_t length) {
do {
if(*s++!=*t++) {
- return FALSE;
+ return false;
}
} while(--length>0);
- return TRUE;
+ return true;
}
static inline UBool
matches8(const uint8_t *s, const uint8_t *t, int32_t length) {
do {
if(*s++!=*t++) {
- return FALSE;
+ return false;
}
} while(--length>0);
- return TRUE;
+ return true;
}
// Compare 16-bit Unicode strings (which may be malformed UTF-16)
diff --git a/thirdparty/icu4c/common/unistr.cpp b/thirdparty/icu4c/common/unistr.cpp
index c18665928d..4125d19472 100644
--- a/thirdparty/icu4c/common/unistr.cpp
+++ b/thirdparty/icu4c/common/unistr.cpp
@@ -197,7 +197,7 @@ UnicodeString::UnicodeString(UChar ch) {
UnicodeString::UnicodeString(UChar32 ch) {
fUnion.fFields.fLengthAndFlags = kShortString;
int32_t i = 0;
- UBool isError = FALSE;
+ UBool isError = false;
U16_APPEND(fUnion.fStackFields.fBuffer, i, US_STACKBUF_SIZE, ch, isError);
// We test isError so that the compiler does not complain that we don't.
// If isError then i==0 which is what we want anyway.
@@ -270,7 +270,7 @@ UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant) {
if(length<0) {
length=(int32_t)uprv_strlen(src);
}
- if(cloneArrayIfNeeded(length, length, FALSE)) {
+ if(cloneArrayIfNeeded(length, length, false)) {
u_charsToUChars(src, getArrayStart(), length);
setLength(length);
} else {
@@ -309,7 +309,7 @@ UnicodeString::UnicodeString(const UnicodeString& that) {
}
UnicodeString::UnicodeString(UnicodeString &&src) U_NOEXCEPT {
- copyFieldsFrom(src, TRUE);
+ copyFieldsFrom(src, true);
}
UnicodeString::UnicodeString(const UnicodeString& that,
@@ -370,7 +370,7 @@ UBool
UnicodeString::allocate(int32_t capacity) {
if(capacity <= US_STACKBUF_SIZE) {
fUnion.fFields.fLengthAndFlags = kShortString;
- return TRUE;
+ return true;
}
if(capacity <= kMaxCapacity) {
++capacity; // for the NUL
@@ -389,13 +389,13 @@ UnicodeString::allocate(int32_t capacity) {
fUnion.fFields.fArray = (UChar *)array;
fUnion.fFields.fCapacity = (int32_t)(numBytes / U_SIZEOF_UCHAR);
fUnion.fFields.fLengthAndFlags = kLongString;
- return TRUE;
+ return true;
}
}
fUnion.fFields.fLengthAndFlags = kIsBogus;
fUnion.fFields.fArray = 0;
fUnion.fFields.fCapacity = 0;
- return FALSE;
+ return false;
}
//========================================
@@ -476,7 +476,7 @@ UnicodeString UnicodeString::fromUTF32(const UChar32 *utf32, int32_t length) {
result.setToBogus();
}
break;
- } while(TRUE);
+ } while(true);
return result;
}
@@ -491,7 +491,7 @@ UnicodeString::operator=(const UnicodeString &src) {
UnicodeString &
UnicodeString::fastCopyFrom(const UnicodeString &src) {
- return copyFrom(src, TRUE);
+ return copyFrom(src, true);
}
UnicodeString &
@@ -576,7 +576,7 @@ UnicodeString &UnicodeString::operator=(UnicodeString &&src) U_NOEXCEPT {
// No explicit check for self move assignment, consistent with standard library.
// Self move assignment causes no crash nor leak but might make the object bogus.
releaseArray();
- copyFieldsFrom(src, TRUE);
+ copyFieldsFrom(src, true);
return *this;
}
@@ -610,9 +610,9 @@ void UnicodeString::copyFieldsFrom(UnicodeString &src, UBool setSrcToBogus) U_NO
void UnicodeString::swap(UnicodeString &other) U_NOEXCEPT {
UnicodeString temp; // Empty short string: Known not to need releaseArray().
// Copy fields without resetting source values in between.
- temp.copyFieldsFrom(*this, FALSE);
- this->copyFieldsFrom(other, FALSE);
- other.copyFieldsFrom(temp, FALSE);
+ temp.copyFieldsFrom(*this, false);
+ this->copyFieldsFrom(other, false);
+ other.copyFieldsFrom(temp, false);
// Set temp to an empty string so that other's memory is not released twice.
temp.fUnion.fFields.fLengthAndFlags = kShortString;
}
@@ -761,7 +761,7 @@ UnicodeString::doCompareCodePointOrder(int32_t start,
srcStart = srcLength = 0;
}
- int32_t diff = uprv_strCompare(getArrayStart() + start, length, (srcChars!=NULL)?(srcChars + srcStart):NULL, srcLength, FALSE, TRUE);
+ int32_t diff = uprv_strCompare(getArrayStart() + start, length, (srcChars!=NULL)?(srcChars + srcStart):NULL, srcLength, false, true);
/* translate the 32-bit result into an 8-bit one */
if(diff!=0) {
return (int8_t)(diff >> 15 | 1);
@@ -921,7 +921,7 @@ UnicodeString::tempSubString(int32_t start, int32_t len) const {
array=fUnion.fStackFields.fBuffer; // anything not NULL because that would make an empty string
len=-2; // bogus result string
}
- return UnicodeString(FALSE, array + start, len);
+ return UnicodeString(false, array + start, len);
}
int32_t
@@ -972,7 +972,7 @@ UnicodeString::toUTF8(ByteSink &sink) const {
if(length16 != 0) {
char stackBuffer[1024];
int32_t capacity = (int32_t)sizeof(stackBuffer);
- UBool utf8IsOwned = FALSE;
+ UBool utf8IsOwned = false;
char *utf8 = sink.GetAppendBuffer(length16 < capacity ? length16 : capacity,
3*length16,
stackBuffer, capacity,
@@ -987,7 +987,7 @@ UnicodeString::toUTF8(ByteSink &sink) const {
if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
utf8 = (char *)uprv_malloc(length8);
if(utf8 != NULL) {
- utf8IsOwned = TRUE;
+ utf8IsOwned = true;
errorCode = U_ZERO_ERROR;
u_strToUTF8WithSub(utf8, length8, &length8,
getBuffer(), length16,
@@ -1225,7 +1225,7 @@ UnicodeString::getTerminatedBuffer() {
if(len < getCapacity()) {
if(fUnion.fFields.fLengthAndFlags & kBufferIsReadonly) {
// If len<capacity on a read-only alias, then array[len] is
- // either the original NUL (if constructed with (TRUE, s, length))
+ // either the original NUL (if constructed with (true, s, length))
// or one of the original string contents characters (if later truncated),
// therefore we can assume that array[len] is initialized memory.
if(array[len] == 0) {
@@ -1375,7 +1375,7 @@ UnicodeString::replace(int32_t start,
UChar32 srcChar) {
UChar buffer[U16_MAX_LENGTH];
int32_t count = 0;
- UBool isError = FALSE;
+ UBool isError = false;
U16_APPEND(buffer, count, U16_MAX_LENGTH, srcChar, isError);
// We test isError so that the compiler does not complain that we don't.
// If isError (srcChar is not a valid code point) then count==0 which means
@@ -1387,7 +1387,7 @@ UnicodeString&
UnicodeString::append(UChar32 srcChar) {
UChar buffer[U16_MAX_LENGTH];
int32_t _length = 0;
- UBool isError = FALSE;
+ UBool isError = false;
U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError);
// We test isError so that the compiler does not complain that we don't.
// If isError then _length==0 which turns the doAppend() into a no-op anyway.
@@ -1484,7 +1484,7 @@ UnicodeString::doReplace(int32_t start,
return doReplace(start, length, copy.getArrayStart(), 0, srcLength);
}
- // cloneArrayIfNeeded(doCopyArray=FALSE) may change fArray but will not copy the current contents;
+ // cloneArrayIfNeeded(doCopyArray=false) may change fArray but will not copy the current contents;
// therefore we need to keep the current fArray
UChar oldStackBuffer[US_STACKBUF_SIZE];
if((fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) {
@@ -1497,7 +1497,7 @@ UnicodeString::doReplace(int32_t start,
// clone our array and allocate a bigger array if needed
int32_t *bufferToDelete = 0;
if(!cloneArrayIfNeeded(newLength, getGrowCapacity(newLength),
- FALSE, &bufferToDelete)
+ false, &bufferToDelete)
) {
return *this;
}
@@ -1637,14 +1637,14 @@ UnicodeString::copy(int32_t start, int32_t limit, int32_t dest) {
* so we implement this function here.
*/
UBool Replaceable::hasMetaData() const {
- return TRUE;
+ return true;
}
/**
* Replaceable API
*/
UBool UnicodeString::hasMetaData() const {
- return FALSE;
+ return false;
}
UnicodeString&
@@ -1662,7 +1662,7 @@ UnicodeString::doReverse(int32_t start, int32_t length) {
UChar *left = getArrayStart() + start;
UChar *right = left + length - 1; // -1 for inclusive boundary (length>=2)
UChar swap;
- UBool hasSupplementary = FALSE;
+ UBool hasSupplementary = false;
// Before the loop we know left<right because length>=2.
do {
@@ -1699,7 +1699,7 @@ UnicodeString::padLeading(int32_t targetLength,
{
int32_t oldLength = length();
if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
- return FALSE;
+ return false;
} else {
// move contents up by padding width
UChar *array = getArrayStart();
@@ -1711,7 +1711,7 @@ UnicodeString::padLeading(int32_t targetLength,
array[start] = padChar;
}
setLength(targetLength);
- return TRUE;
+ return true;
}
}
@@ -1721,7 +1721,7 @@ UnicodeString::padTrailing(int32_t targetLength,
{
int32_t oldLength = length();
if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
- return FALSE;
+ return false;
} else {
// fill in padding character
UChar *array = getArrayStart();
@@ -1730,7 +1730,7 @@ UnicodeString::padTrailing(int32_t targetLength,
array[length] = padChar;
}
setLength(targetLength);
- return TRUE;
+ return true;
}
}
@@ -1800,10 +1800,10 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
}
// while a getBuffer(minCapacity) is "open",
- // prevent any modifications of the string by returning FALSE here
+ // prevent any modifications of the string by returning false here
// if the string is bogus, then only an assignment or similar can revive it
if(!isWritable()) {
- return FALSE;
+ return false;
}
/*
@@ -1811,7 +1811,7 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
* the buffer is read-only, or
* the buffer is refCounted (shared), and refCount>1, or
* the buffer is too small.
- * Return FALSE if memory could not be allocated.
+ * Return false if memory could not be allocated.
*/
if(forceClone ||
fUnion.fFields.fLengthAndFlags & kBufferIsReadonly ||
@@ -1890,10 +1890,10 @@ UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
}
fUnion.fFields.fLengthAndFlags = flags;
setToBogus();
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
// UnicodeStringAppendable ------------------------------------------------- ***
@@ -1909,7 +1909,7 @@ UBool
UnicodeStringAppendable::appendCodePoint(UChar32 c) {
UChar buffer[U16_MAX_LENGTH];
int32_t cLength = 0;
- UBool isError = FALSE;
+ UBool isError = false;
U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError);
return !isError && str.doAppend(buffer, 0, cLength).isWritable();
}
@@ -1961,10 +1961,10 @@ uhash_compareUnicodeString(const UElement key1, const UElement key2) {
const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
if (str1 == str2) {
- return TRUE;
+ return true;
}
if (str1 == NULL || str2 == NULL) {
- return FALSE;
+ return false;
}
return *str1 == *str2;
}
diff --git a/thirdparty/icu4c/common/unistr_case.cpp b/thirdparty/icu4c/common/unistr_case.cpp
index 2138d60c01..f4c43b4889 100644
--- a/thirdparty/icu4c/common/unistr_case.cpp
+++ b/thirdparty/icu4c/common/unistr_case.cpp
@@ -123,7 +123,7 @@ UnicodeString::caseMap(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITER
capacity = getCapacity();
} else {
// Switch from the read-only alias or shared heap buffer to the stack buffer.
- if (!cloneArrayIfNeeded(US_STACKBUF_SIZE, US_STACKBUF_SIZE, /* doCopyArray= */ FALSE)) {
+ if (!cloneArrayIfNeeded(US_STACKBUF_SIZE, US_STACKBUF_SIZE, /* doCopyArray= */ false)) {
return *this;
}
U_ASSERT(fUnion.fFields.fLengthAndFlags & kUsingStackBuffer);
@@ -132,7 +132,7 @@ UnicodeString::caseMap(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITER
}
#if !UCONFIG_NO_BREAK_ITERATION
if (iter != nullptr) {
- oldString.setTo(FALSE, oldArray, oldLength);
+ oldString.setTo(false, oldArray, oldLength);
iter->setText(oldString);
}
#endif
@@ -158,7 +158,7 @@ UnicodeString::caseMap(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITER
UChar replacementChars[200];
#if !UCONFIG_NO_BREAK_ITERATION
if (iter != nullptr) {
- oldString.setTo(FALSE, oldArray, oldLength);
+ oldString.setTo(false, oldArray, oldLength);
iter->setText(oldString);
}
#endif
@@ -194,7 +194,7 @@ UnicodeString::caseMap(int32_t caseLocale, uint32_t options, UCASEMAP_BREAK_ITER
// and deletes the old array itself after it is done.
// In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
int32_t *bufferToDelete = 0;
- if (!cloneArrayIfNeeded(newLength, newLength, FALSE, &bufferToDelete, TRUE)) {
+ if (!cloneArrayIfNeeded(newLength, newLength, false, &bufferToDelete, true)) {
return *this;
}
errorCode = U_ZERO_ERROR;
@@ -241,10 +241,10 @@ uhash_compareCaselessUnicodeString(const UElement key1, const UElement key2) {
const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
if (str1 == str2) {
- return TRUE;
+ return true;
}
if (str1 == NULL || str2 == NULL) {
- return FALSE;
+ return false;
}
return str1->caseCompare(*str2, U_FOLD_CASE_DEFAULT) == 0;
}
diff --git a/thirdparty/icu4c/common/unistr_cnv.cpp b/thirdparty/icu4c/common/unistr_cnv.cpp
index 64d3c16801..e1f60d4487 100644
--- a/thirdparty/icu4c/common/unistr_cnv.cpp
+++ b/thirdparty/icu4c/common/unistr_cnv.cpp
@@ -225,13 +225,13 @@ UnicodeString::extract(char *dest, int32_t destCapacity,
// get the converter
UBool isDefaultConverter;
if(cnv==0) {
- isDefaultConverter=TRUE;
+ isDefaultConverter=true;
cnv=u_getDefaultConverter(&errorCode);
if(U_FAILURE(errorCode)) {
return 0;
}
} else {
- isDefaultConverter=FALSE;
+ isDefaultConverter=false;
ucnv_resetFromUnicode(cnv);
}
@@ -275,7 +275,7 @@ UnicodeString::doExtract(int32_t start, int32_t length,
}
// perform the conversion
- ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, &errorCode);
+ ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, &errorCode);
length=(int32_t)(dest-originalDest);
// if an overflow occurs, then get the preflighting length
@@ -286,7 +286,7 @@ UnicodeString::doExtract(int32_t start, int32_t length,
do {
dest=buffer;
errorCode=U_ZERO_ERROR;
- ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, TRUE, &errorCode);
+ ucnv_fromUnicode(cnv, &dest, destLimit, &src, srcLimit, 0, true, &errorCode);
length+=(int32_t)(dest-buffer);
} while(errorCode==U_BUFFER_OVERFLOW_ERROR);
}
@@ -322,7 +322,7 @@ UnicodeString::doCodepageCreate(const char *codepageData,
converter = u_getDefaultConverter(&status);
} else if(*codepage == 0) {
// use the "invariant characters" conversion
- if(cloneArrayIfNeeded(dataLength, dataLength, FALSE)) {
+ if(cloneArrayIfNeeded(dataLength, dataLength, false)) {
u_charsToUChars(codepageData, getArrayStart(), dataLength);
setLength(dataLength);
} else {
@@ -379,7 +379,7 @@ UnicodeString::doCodepageCreate(const char *codepageData,
}
// we do not care about the current contents
- UBool doCopyArray = FALSE;
+ UBool doCopyArray = false;
for(;;) {
if(!cloneArrayIfNeeded(arraySize, arraySize, doCopyArray)) {
setToBogus();
@@ -390,7 +390,7 @@ UnicodeString::doCodepageCreate(const char *codepageData,
array = getArrayStart();
myTarget = array + length();
ucnv_toUnicode(converter, &myTarget, array + getCapacity(),
- &mySource, mySourceEnd, 0, TRUE, &status);
+ &mySource, mySourceEnd, 0, true, &status);
// update the conversion parameters
setLength((int32_t)(myTarget - array));
@@ -401,7 +401,7 @@ UnicodeString::doCodepageCreate(const char *codepageData,
status = U_ZERO_ERROR;
// keep the previous conversion results
- doCopyArray = TRUE;
+ doCopyArray = true;
// estimate the new size needed, larger than before
// try 2 UChar's per remaining source byte
diff --git a/thirdparty/icu4c/common/unorm.cpp b/thirdparty/icu4c/common/unorm.cpp
index 2d9f46052f..cf3915c27f 100644
--- a/thirdparty/icu4c/common/unorm.cpp
+++ b/thirdparty/icu4c/common/unorm.cpp
@@ -128,7 +128,7 @@ _iterate(UCharIterator *src, UBool forward,
}
if(pNeededToNormalize!=NULL) {
- *pNeededToNormalize=FALSE;
+ *pNeededToNormalize=false;
}
if(!(forward ? src->hasNext(src) : src->hasPrevious(src))) {
return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
@@ -199,7 +199,7 @@ unorm_previous(UCharIterator *src,
UNormalizationMode mode, int32_t options,
UBool doNormalize, UBool *pNeededToNormalize,
UErrorCode *pErrorCode) {
- return unorm_iterate(src, FALSE,
+ return unorm_iterate(src, false,
dest, destCapacity,
mode, options,
doNormalize, pNeededToNormalize,
@@ -212,7 +212,7 @@ unorm_next(UCharIterator *src,
UNormalizationMode mode, int32_t options,
UBool doNormalize, UBool *pNeededToNormalize,
UErrorCode *pErrorCode) {
- return unorm_iterate(src, TRUE,
+ return unorm_iterate(src, true,
dest, destCapacity,
mode, options,
doNormalize, pNeededToNormalize,
diff --git a/thirdparty/icu4c/common/unormcmp.cpp b/thirdparty/icu4c/common/unormcmp.cpp
index 689b0b53b2..e224190972 100644
--- a/thirdparty/icu4c/common/unormcmp.cpp
+++ b/thirdparty/icu4c/common/unormcmp.cpp
@@ -536,7 +536,7 @@ UBool _normalize(const Normalizer2 *n2, const UChar *s, int32_t length,
// check if s fulfill the conditions
int32_t spanQCYes=n2->spanQuickCheckYes(str, *pErrorCode);
if (U_FAILURE(*pErrorCode)) {
- return FALSE;
+ return false;
}
/*
* ICU 2.4 had a further optimization:
@@ -548,13 +548,13 @@ UBool _normalize(const Normalizer2 *n2, const UChar *s, int32_t length,
*/
if(spanQCYes<str.length()) {
UnicodeString unnormalized=str.tempSubString(spanQCYes);
- normalized.setTo(FALSE, str.getBuffer(), spanQCYes);
+ normalized.setTo(false, str.getBuffer(), spanQCYes);
n2->normalizeSecondAndAppend(normalized, unnormalized, *pErrorCode);
if (U_SUCCESS(*pErrorCode)) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
U_CAPI int32_t U_EXPORT2
diff --git a/thirdparty/icu4c/common/uprops.cpp b/thirdparty/icu4c/common/uprops.cpp
index 5186a0c75c..26e950b876 100644
--- a/thirdparty/icu4c/common/uprops.cpp
+++ b/thirdparty/icu4c/common/uprops.cpp
@@ -49,7 +49,7 @@ U_NAMESPACE_USE
namespace {
-icu::UInitOnce gLayoutInitOnce = U_INITONCE_INITIALIZER;
+icu::UInitOnce gLayoutInitOnce {};
UDataMemory *gLayoutMemory = nullptr;
UCPTrie *gInpcTrie = nullptr; // Indic_Positional_Category
@@ -76,7 +76,7 @@ UBool U_CALLCONV uprops_cleanup() {
gMaxVoValue = 0;
gLayoutInitOnce.reset();
- return TRUE;
+ return true;
}
UBool U_CALLCONV
@@ -141,7 +141,7 @@ void U_CALLCONV ulayout_load(UErrorCode &errorCode) {
}
UBool ulayout_ensureData(UErrorCode &errorCode) {
- if (U_FAILURE(errorCode)) { return FALSE; }
+ if (U_FAILURE(errorCode)) { return false; }
umtx_initOnce(gLayoutInitOnce, &ulayout_load, errorCode);
return U_SUCCESS(errorCode);
}
@@ -188,7 +188,7 @@ static UBool isJoinControl(const BinaryProperty &/*prop*/, UChar32 c, UProperty
#if UCONFIG_NO_NORMALIZATION
static UBool hasFullCompositionExclusion(const BinaryProperty &, UChar32, UProperty) {
- return FALSE;
+ return false;
}
#else
static UBool hasFullCompositionExclusion(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
@@ -202,7 +202,7 @@ static UBool hasFullCompositionExclusion(const BinaryProperty &/*prop*/, UChar32
// UCHAR_NF*_INERT properties
#if UCONFIG_NO_NORMALIZATION
static UBool isNormInert(const BinaryProperty &, UChar32, UProperty) {
- return FALSE;
+ return false;
}
#else
static UBool isNormInert(const BinaryProperty &/*prop*/, UChar32 c, UProperty which) {
@@ -215,7 +215,7 @@ static UBool isNormInert(const BinaryProperty &/*prop*/, UChar32 c, UProperty wh
#if UCONFIG_NO_NORMALIZATION
static UBool changesWhenCasefolded(const BinaryProperty &, UChar32, UProperty) {
- return FALSE;
+ return false;
}
#else
static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
@@ -223,7 +223,7 @@ static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UP
UErrorCode errorCode=U_ZERO_ERROR;
const Normalizer2 *nfcNorm2=Normalizer2::getNFCInstance(errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
if(nfcNorm2->getDecomposition(c, nfd)) {
/* c has a decomposition */
@@ -237,7 +237,7 @@ static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UP
c=U_SENTINEL;
}
} else if(c<0) {
- return FALSE; /* protect against bad input */
+ return false; /* protect against bad input */
}
if(c>=0) {
/* single code point */
@@ -252,21 +252,21 @@ static UBool changesWhenCasefolded(const BinaryProperty &/*prop*/, UChar32 c, UP
U_FOLD_CASE_DEFAULT, &errorCode);
return (UBool)(U_SUCCESS(errorCode) &&
0!=u_strCompare(nfd.getBuffer(), nfd.length(),
- dest, destLength, FALSE));
+ dest, destLength, false));
}
}
#endif
#if UCONFIG_NO_NORMALIZATION
static UBool changesWhenNFKC_Casefolded(const BinaryProperty &, UChar32, UProperty) {
- return FALSE;
+ return false;
}
#else
static UBool changesWhenNFKC_Casefolded(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
UErrorCode errorCode=U_ZERO_ERROR;
const Normalizer2Impl *kcf=Normalizer2Factory::getNFKC_CFImpl(errorCode);
if(U_FAILURE(errorCode)) {
- return FALSE;
+ return false;
}
UnicodeString src(c);
UnicodeString dest;
@@ -277,8 +277,8 @@ static UBool changesWhenNFKC_Casefolded(const BinaryProperty &/*prop*/, UChar32
// Small destCapacity for NFKC_CF(c).
if(buffer.init(5, errorCode)) {
const UChar *srcArray=src.getBuffer();
- kcf->compose(srcArray, srcArray+src.length(), FALSE,
- TRUE, buffer, errorCode);
+ kcf->compose(srcArray, srcArray+src.length(), false,
+ true, buffer, errorCode);
}
}
return U_SUCCESS(errorCode) && dest!=src;
@@ -287,7 +287,7 @@ static UBool changesWhenNFKC_Casefolded(const BinaryProperty &/*prop*/, UChar32
#if UCONFIG_NO_NORMALIZATION
static UBool isCanonSegmentStarter(const BinaryProperty &, UChar32, UProperty) {
- return FALSE;
+ return false;
}
#else
static UBool isCanonSegmentStarter(const BinaryProperty &/*prop*/, UChar32 c, UProperty /*which*/) {
@@ -416,7 +416,7 @@ u_hasBinaryProperty(UChar32 c, UProperty which) {
/* c is range-checked in the functions that are called from here */
if(which<UCHAR_BINARY_START || UCHAR_BINARY_LIMIT<=which) {
/* not a known binary property */
- return FALSE;
+ return false;
} else {
const BinaryProperty &prop=binProps[which];
return prop.contains(prop, c, which);
@@ -670,7 +670,7 @@ U_CAPI int32_t U_EXPORT2
u_getIntPropertyMaxValue(UProperty which) {
if(which<UCHAR_INT_START) {
if(UCHAR_BINARY_START<=which && which<UCHAR_BINARY_LIMIT) {
- return 1; // maximum TRUE for all binary properties
+ return 1; // maximum true for all binary properties
}
} else if(which<UCHAR_INT_LIMIT) {
const IntProperty &prop=intProps[which-UCHAR_INT_START];
@@ -812,7 +812,7 @@ u_getFC_NFKC_Closure(UChar32 c, UChar *dest, int32_t destCapacity, UErrorCode *p
if(folded1Length>UCASE_MAX_STRING_LENGTH) {
folded1String.setTo(folded1Length);
} else {
- folded1String.setTo(FALSE, folded1, folded1Length);
+ folded1String.setTo(false, folded1, folded1Length);
}
}
UnicodeString kc1=nfkc->normalize(folded1String, *pErrorCode);
diff --git a/thirdparty/icu4c/common/uresbund.cpp b/thirdparty/icu4c/common/uresbund.cpp
index a9c6459418..17c0177a05 100644
--- a/thirdparty/icu4c/common/uresbund.cpp
+++ b/thirdparty/icu4c/common/uresbund.cpp
@@ -49,7 +49,7 @@ TODO: This cache should probably be removed when the deprecated code is
completely removed.
*/
static UHashtable *cache = NULL;
-static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gCacheInitOnce {};
static UMutex resbMutex;
@@ -85,10 +85,206 @@ static UBool chopLocale(char *name) {
if(i != NULL) {
*i = '\0';
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
+}
+
+static UBool hasVariant(const char* localeID) {
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t variantLength = uloc_getVariant(localeID, NULL, 0, &err);
+ return variantLength != 0;
+}
+
+// This file contains the tables for doing locale fallback, which are generated
+// by the CLDR-to-ICU process directly from the CLDR data. This file should only
+// ever be included from here.
+#define INCLUDED_FROM_URESBUND_CPP
+#include "localefallback_data.h"
+
+static const char* performFallbackLookup(const char* key,
+ const char* keyStrs,
+ const char* valueStrs,
+ const int32_t* lookupTable,
+ int32_t lookupTableLength) {
+ const int32_t* bottom = lookupTable;
+ const int32_t* top = lookupTable + lookupTableLength;
+
+ while (bottom < top) {
+ // Effectively, divide by 2 and round down to an even index
+ const int32_t* middle = bottom + (((top - bottom) / 4) * 2);
+ const char* entryKey = &(keyStrs[*middle]);
+ int32_t strcmpResult = uprv_strcmp(key, entryKey);
+ if (strcmpResult == 0) {
+ return &(valueStrs[middle[1]]);
+ } else if (strcmpResult < 0) {
+ top = middle;
+ } else {
+ bottom = middle + 2;
+ }
+ }
+ return nullptr;
+}
+
+static CharString getDefaultScript(const CharString& language, const CharString& region) {
+ const char* defaultScript = nullptr;
+ UErrorCode err = U_ZERO_ERROR;
+
+ // the default script will be "Latn" if we don't find the locale ID in the tables
+ CharString result("Latn", err);
+
+ // if we were passed both language and region, make them into a locale ID and look that up in the default
+ // script table
+ if (!region.isEmpty()) {
+ CharString localeID;
+ localeID.append(language, err).append("_", err).append(region, err);
+ if (U_FAILURE(err)) {
+ return result;
+ }
+ defaultScript = performFallbackLookup(localeID.data(), dsLocaleIDChars, scriptCodeChars, defaultScriptTable, UPRV_LENGTHOF(defaultScriptTable));
+ }
+
+ // if we didn't find anything, look up just the language in the default script table
+ if (defaultScript == nullptr) {
+ defaultScript = performFallbackLookup(language.data(), dsLocaleIDChars, scriptCodeChars, defaultScriptTable, UPRV_LENGTHOF(defaultScriptTable));
+ }
+
+ // if either lookup above succeeded, copy the result from "defaultScript" into "result"; otherwise, return "Latn"
+ if (defaultScript != nullptr) {
+ result.clear();
+ result.append(defaultScript, err);
+ }
+ return result;
+}
+
+enum UResOpenType {
+ /**
+ * Open a resource bundle for the locale;
+ * if there is not even a base language bundle, then fall back to the default locale;
+ * if there is no bundle for that either, then load the root bundle.
+ *
+ * This is the default bundle loading behavior.
+ */
+ URES_OPEN_LOCALE_DEFAULT_ROOT,
+ // TODO: ICU ticket #11271 "consistent default locale across locale trees"
+ // Add an option to look at the main locale tree for whether to
+ // fall back to root directly (if the locale has main data) or
+ // fall back to the default locale first (if the locale does not even have main data).
+ /**
+ * Open a resource bundle for the locale;
+ * if there is not even a base language bundle, then load the root bundle;
+ * never fall back to the default locale.
+ *
+ * This is used for algorithms that have good pan-Unicode default behavior,
+ * such as case mappings, collation, and segmentation (BreakIterator).
+ */
+ URES_OPEN_LOCALE_ROOT,
+ /**
+ * Open a resource bundle for the exact bundle name as requested;
+ * no fallbacks, do not load parent bundles.
+ *
+ * This is used for supplemental (non-locale) data.
+ */
+ URES_OPEN_DIRECT
+};
+typedef enum UResOpenType UResOpenType;
+
+/**
+ * Internal function, determines the search path for resource bundle files.
+ * Currently, this function is used only by findFirstExisting() to help search for resource bundle files when a bundle for the specified
+ * locale doesn't exist. The code that supports inheritance of resources between existing resource bundle files continues to
+ * use chopLocale() below.
+ * @param name In-out parameter: On input, the locale ID to get a parent locale ID for (this is a locale's base name, without keywords); on output, the
+ * requested parent locale ID.
+ * @param origName The original locale ID the caller of findFirstExisting() requested. This is the same as `name` on the first call to this function,
+ * but as findFirstExisting() ascends the resource bundle's parent tree, this parameter will continue to be the original locale ID requested.
+ */
+static bool getParentLocaleID(char *name, const char *origName, UResOpenType openType) {
+ // early out if the locale ID has a variant code or ends with _
+ if (name[uprv_strlen(name) - 1] == '_' || hasVariant(name)) {
+ return chopLocale(name);
+ }
+
+ UErrorCode err = U_ZERO_ERROR;
+ const char* tempNamePtr = name;
+ CharString language = ulocimp_getLanguage(tempNamePtr, &tempNamePtr, err);
+ if (*tempNamePtr == '_') {
+ ++tempNamePtr;
+ }
+ CharString script = ulocimp_getScript(tempNamePtr, &tempNamePtr, err);
+ if (*tempNamePtr == '_') {
+ ++tempNamePtr;
+ }
+ CharString region = ulocimp_getCountry(tempNamePtr, &tempNamePtr, err);
+ CharString workingLocale;
+ if (U_FAILURE(err)) {
+ // hopefully this never happens...
+ return chopLocale(name);
+ }
+
+ // if the open type is URES_OPEN_LOCALE_DEFAULT_ROOT, first look the locale ID up in the parent locale table;
+ // if that table specifies a parent for it, return that (we don't do this for the other open types-- if we're not
+ // falling back through the system default locale, we also want to do straight truncation fallback instead
+ // of looking things up in the parent locale table-- see https://www.unicode.org/reports/tr35/tr35.html#Parent_Locales:
+ // "Collation data, however, is an exception...")
+ if (openType == URES_OPEN_LOCALE_DEFAULT_ROOT) {
+ const char* parentID = performFallbackLookup(name, parentLocaleChars, parentLocaleChars, parentLocaleTable, UPRV_LENGTHOF(parentLocaleTable));
+ if (parentID != NULL) {
+ uprv_strcpy(name, parentID);
+ return true;
+ }
+ }
+
+ // if it's not in the parent locale table, figure out the fallback script algorithmically
+ // (see CLDR-15265 for an explanation of the algorithm)
+ if (!script.isEmpty() && !region.isEmpty()) {
+ // if "name" has both script and region, is the script the default script?
+ // - if so, remove it and keep the region
+ // - if not, remove the region and keep the script
+ if (getDefaultScript(language, region) == script.toStringPiece()) {
+ workingLocale.append(language, err).append("_", err).append(region, err);
+ } else {
+ workingLocale.append(language, err).append("_", err).append(script, err);
+ }
+ } else if (!region.isEmpty()) {
+ // if "name" has region but not script, did the original locale ID specify a script?
+ // - if yes, replace the region with the script from the original locale ID
+ // - if no, replace the region with the default script for that language and region
+ UErrorCode err = U_ZERO_ERROR;
+ tempNamePtr = origName;
+ CharString origNameLanguage = ulocimp_getLanguage(tempNamePtr, &tempNamePtr, err);
+ if (*tempNamePtr == '_') {
+ ++tempNamePtr;
+ }
+ CharString origNameScript = ulocimp_getScript(origName, nullptr, err);
+ if (!origNameScript.isEmpty()) {
+ workingLocale.append(language, err).append("_", err).append(origNameScript, err);
+ } else {
+ workingLocale.append(language, err).append("_", err).append(getDefaultScript(language, region), err);
+ }
+ } else if (!script.isEmpty()) {
+ // if "name" has script but not region (and our open type if URES_OPEN_LOCALE_DEFAULT_ROOT), is the script
+ // the default script for the language?
+ // - if so, remove it from the locale ID
+ // - if not, return false to continue up the chain
+ // (we don't do this for other open types for the same reason we don't look things up in the parent
+ // locale table for other open types-- see the reference to UTS #35 above)
+ if (openType != URES_OPEN_LOCALE_DEFAULT_ROOT || getDefaultScript(language, CharString()) == script.toStringPiece()) {
+ workingLocale.append(language, err);
+ } else {
+ return false;
+ }
+ } else {
+ // if "name" just contains a language code, return false so the calling code falls back to "root"
+ return false;
+ }
+ if (U_SUCCESS(err) && !workingLocale.isEmpty()) {
+ uprv_strcpy(name, workingLocale.data());
+ return true;
+ } else {
+ return false;
+ }
}
/**
@@ -199,7 +395,7 @@ static int32_t ures_flushCache()
}
do {
- deletedMore = FALSE;
+ deletedMore = false;
/*creates an enumeration to iterate through every element in the table */
pos = UHASH_FIRST;
while ((e = uhash_nextElement(cache, &pos)) != NULL)
@@ -216,7 +412,7 @@ static int32_t ures_flushCache()
if (resB->fCountExisting == 0) {
rbDeletedNum++;
- deletedMore = TRUE;
+ deletedMore = true;
uhash_removeElement(cache, e);
free_entry(resB);
}
@@ -234,7 +430,7 @@ static int32_t ures_flushCache()
#include <stdio.h>
U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) {
- UBool cacheNotEmpty = FALSE;
+ UBool cacheNotEmpty = false;
int32_t pos = UHASH_FIRST;
const UHashElement *e;
UResourceDataEntry *resB;
@@ -242,11 +438,11 @@ U_CAPI UBool U_EXPORT2 ures_dumpCacheContents(void) {
Mutex lock(&resbMutex);
if (cache == NULL) {
fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
- return FALSE;
+ return false;
}
while ((e = uhash_nextElement(cache, &pos)) != NULL) {
- cacheNotEmpty=TRUE;
+ cacheNotEmpty=true;
resB = (UResourceDataEntry *) e->value.pointer;
fprintf(stderr,"%s:%d: RB Cache: Entry @0x%p, refcount %d, name %s:%s. Pool 0x%p, alias 0x%p, parent 0x%p\n",
__FILE__, __LINE__,
@@ -272,7 +468,7 @@ static UBool U_CALLCONV ures_cleanup(void)
cache = NULL;
}
gCacheInitOnce.reset();
- return TRUE;
+ return true;
}
/** INTERNAL: Initializes the cache for resources */
@@ -320,7 +516,7 @@ static UResourceDataEntry *init_entry(const char *localeID, const char *path, UE
const char *name;
char aliasName[100] = { 0 };
int32_t aliasLen = 0;
- /*UBool isAlias = FALSE;*/
+ /*UBool isAlias = false;*/
/*UHashTok hashkey; */
if(U_FAILURE(*status)) {
@@ -463,13 +659,15 @@ getPoolEntry(const char *path, UErrorCode *status) {
/* INTERNAL: */
/* CAUTION: resbMutex must be locked when calling this function! */
static UResourceDataEntry *
-findFirstExisting(const char* path, char* name, const char* defaultLocale,
- UBool *isRoot, UBool *hasChopped, UBool *isDefault, UErrorCode* status) {
+findFirstExisting(const char* path, char* name, const char* defaultLocale, UResOpenType openType,
+ UBool *isRoot, UBool *foundParent, UBool *isDefault, UErrorCode* status) {
UResourceDataEntry *r = NULL;
- UBool hasRealData = FALSE;
- *hasChopped = TRUE; /* we're starting with a fresh name */
+ UBool hasRealData = false;
+ *foundParent = true; /* we're starting with a fresh name */
+ char origName[ULOC_FULLNAME_CAPACITY];
- while(*hasChopped && !hasRealData) {
+ uprv_strcpy(origName, name);
+ while(*foundParent && !hasRealData) {
r = init_entry(name, path, status);
/* Null pointer test */
if (U_FAILURE(*status)) {
@@ -494,8 +692,14 @@ findFirstExisting(const char* path, char* name, const char* defaultLocale,
*isRoot = (UBool)(uprv_strcmp(name, kRootLocaleName) == 0);
/*Fallback data stuff*/
- *hasChopped = chopLocale(name);
- if (*hasChopped && *name == '\0') {
+ if (!hasRealData) {
+ *foundParent = getParentLocaleID(name, origName, openType);
+ } else {
+ // we've already found a real resource file; what we return to the caller is the parent
+ // locale ID for inheritance, which should come from chopLocale(), not getParentLocaleID()
+ *foundParent = chopLocale(name);
+ }
+ if (*foundParent && *name == '\0') {
uprv_strcpy(name, "und");
}
}
@@ -513,13 +717,13 @@ static void ures_setIsStackObject( UResourceBundle* resB, UBool state) {
}
static UBool ures_isStackObject(const UResourceBundle* resB) {
- return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?FALSE:TRUE);
+ return((resB->fMagic1 == MAGIC1 && resB->fMagic2 == MAGIC2)?false:true);
}
U_CFUNC void ures_initStackObject(UResourceBundle* resB) {
uprv_memset(resB, 0, sizeof(UResourceBundle));
- ures_setIsStackObject(resB, TRUE);
+ ures_setIsStackObject(resB, true);
}
U_NAMESPACE_BEGIN
@@ -538,8 +742,8 @@ static UBool // returns U_SUCCESS(*status)
loadParentsExceptRoot(UResourceDataEntry *&t1,
char name[], int32_t nameCapacity,
UBool usingUSRData, char usrDataPath[], UErrorCode *status) {
- if (U_FAILURE(*status)) { return FALSE; }
- UBool checkParent = TRUE;
+ if (U_FAILURE(*status)) { return false; }
+ UBool checkParent = true;
while (checkParent && t1->fParent == NULL && !t1->fData.noFallback &&
res_getResource(&t1->fData,"%%ParentIsRoot") == RES_BOGUS) {
Resource parentRes = res_getResource(&t1->fData, "%%Parent");
@@ -550,7 +754,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
if(parentLocaleName != NULL && 0 < parentLocaleLen && parentLocaleLen < nameCapacity) {
u_UCharsToChars(parentLocaleName, name, parentLocaleLen + 1);
if (uprv_strcmp(name, kRootLocaleName) == 0) {
- return TRUE;
+ return true;
}
}
}
@@ -559,7 +763,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
UResourceDataEntry *t2 = init_entry(name, t1->fPath, &parentStatus);
if (U_FAILURE(parentStatus)) {
*status = parentStatus;
- return FALSE;
+ return false;
}
UResourceDataEntry *u2 = NULL;
UErrorCode usrStatus = U_ZERO_ERROR;
@@ -568,7 +772,7 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
// If we failed due to out-of-memory, report that to the caller and exit early.
if (usrStatus == U_MEMORY_ALLOCATION_ERROR) {
*status = usrStatus;
- return FALSE;
+ return false;
}
}
@@ -585,65 +789,33 @@ loadParentsExceptRoot(UResourceDataEntry *&t1,
t1 = t2;
checkParent = chopLocale(name) || mayHaveParent(name);
}
- return TRUE;
+ return true;
}
static UBool // returns U_SUCCESS(*status)
insertRootBundle(UResourceDataEntry *&t1, UErrorCode *status) {
- if (U_FAILURE(*status)) { return FALSE; }
+ if (U_FAILURE(*status)) { return false; }
UErrorCode parentStatus = U_ZERO_ERROR;
UResourceDataEntry *t2 = init_entry(kRootLocaleName, t1->fPath, &parentStatus);
if (U_FAILURE(parentStatus)) {
*status = parentStatus;
- return FALSE;
+ return false;
}
t1->fParent = t2;
t1 = t2;
- return TRUE;
+ return true;
}
-enum UResOpenType {
- /**
- * Open a resource bundle for the locale;
- * if there is not even a base language bundle, then fall back to the default locale;
- * if there is no bundle for that either, then load the root bundle.
- *
- * This is the default bundle loading behavior.
- */
- URES_OPEN_LOCALE_DEFAULT_ROOT,
- // TODO: ICU ticket #11271 "consistent default locale across locale trees"
- // Add an option to look at the main locale tree for whether to
- // fall back to root directly (if the locale has main data) or
- // fall back to the default locale first (if the locale does not even have main data).
- /**
- * Open a resource bundle for the locale;
- * if there is not even a base language bundle, then load the root bundle;
- * never fall back to the default locale.
- *
- * This is used for algorithms that have good pan-Unicode default behavior,
- * such as case mappings, collation, and segmentation (BreakIterator).
- */
- URES_OPEN_LOCALE_ROOT,
- /**
- * Open a resource bundle for the exact bundle name as requested;
- * no fallbacks, do not load parent bundles.
- *
- * This is used for supplemental (non-locale) data.
- */
- URES_OPEN_DIRECT
-};
-typedef enum UResOpenType UResOpenType;
-
static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
UResOpenType openType, UErrorCode* status) {
U_ASSERT(openType != URES_OPEN_DIRECT);
UErrorCode intStatus = U_ZERO_ERROR;
UResourceDataEntry *r = NULL;
UResourceDataEntry *t1 = NULL;
- UBool isDefault = FALSE;
- UBool isRoot = FALSE;
- UBool hasRealData = FALSE;
- UBool hasChopped = TRUE;
+ UBool isDefault = false;
+ UBool isRoot = false;
+ UBool hasRealData = false;
+ UBool hasChopped = true;
UBool usingUSRData = U_USE_USRDATA && ( path == NULL || uprv_strncmp(path,U_ICUDATA_NAME,8) == 0);
char name[ULOC_FULLNAME_CAPACITY];
@@ -676,7 +848,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
Mutex lock(&resbMutex); // Lock resbMutex until the end of this function.
/* We're going to skip all the locales that do not have any data */
- r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
+ r = findFirstExisting(path, name, defaultLocale, openType, &isRoot, &hasChopped, &isDefault, &intStatus);
// If we failed due to out-of-memory, report the failure and exit early.
if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
@@ -686,7 +858,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
if(r != NULL) { /* if there is one real locale, we can look for parents. */
t1 = r;
- hasRealData = TRUE;
+ hasRealData = true;
if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
UErrorCode usrStatus = U_ZERO_ERROR;
UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
@@ -717,7 +889,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
/* insert default locale */
uprv_strcpy(name, defaultLocale);
- r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
+ r = findFirstExisting(path, name, defaultLocale, openType, &isRoot, &hasChopped, &isDefault, &intStatus);
// If we failed due to out-of-memory, report the failure and exit early.
if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
*status = intStatus;
@@ -726,8 +898,8 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
intStatus = U_USING_DEFAULT_WARNING;
if(r != NULL) { /* the default locale exists */
t1 = r;
- hasRealData = TRUE;
- isDefault = TRUE;
+ hasRealData = true;
+ isDefault = true;
// TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
if ((hasChopped || mayHaveParent(name)) && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
@@ -741,7 +913,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
/* present */
if(r == NULL) {
uprv_strcpy(name, kRootLocaleName);
- r = findFirstExisting(path, name, defaultLocale, &isRoot, &hasChopped, &isDefault, &intStatus);
+ r = findFirstExisting(path, name, defaultLocale, openType, &isRoot, &hasChopped, &isDefault, &intStatus);
// If we failed due to out-of-memory, report the failure and exit early.
if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
*status = intStatus;
@@ -750,7 +922,7 @@ static UResourceDataEntry *entryOpen(const char* path, const char* localeID,
if(r != NULL) {
t1 = r;
intStatus = U_USING_DEFAULT_WARNING;
- hasRealData = TRUE;
+ hasRealData = true;
} else { /* we don't even have the root locale */
*status = U_MISSING_RESOURCE_ERROR;
goto finish;
@@ -826,7 +998,7 @@ entryOpenDirect(const char* path, const char* localeID, UErrorCode* status) {
char name[ULOC_FULLNAME_CAPACITY];
uprv_strcpy(name, localeID);
if(!chopLocale(name) || uprv_strcmp(name, kRootLocaleName) == 0 ||
- loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), FALSE, NULL, status)) {
+ loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), false, NULL, status)) {
if(uprv_strcmp(t1->fName, kRootLocaleName) != 0 && t1->fParent == NULL) {
insertRootBundle(t1, status);
}
@@ -956,7 +1128,7 @@ ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
}
ures_freeResPath(resB);
- if(ures_isStackObject(resB) == FALSE && freeBundleObj) {
+ if(ures_isStackObject(resB) == false && freeBundleObj) {
uprv_free(resB);
}
#if 0 /*U_DEBUG*/
@@ -971,7 +1143,7 @@ ures_closeBundle(UResourceBundle* resB, UBool freeBundleObj)
U_CAPI void U_EXPORT2
ures_close(UResourceBundle* resB)
{
- ures_closeBundle(resB, TRUE);
+ ures_closeBundle(resB, true);
}
namespace {
@@ -1237,7 +1409,7 @@ UResourceBundle *init_resb_result(
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- ures_setIsStackObject(resB, FALSE);
+ ures_setIsStackObject(resB, false);
resB->fResPath = NULL;
resB->fResPathLen = 0;
} else {
@@ -1254,7 +1426,7 @@ UResourceBundle *init_resb_result(
treated the same
*/
/*
- if(ures_isStackObject(resB) != FALSE) {
+ if(ures_isStackObject(resB) != false) {
ures_initStackObject(resB);
}
*/
@@ -1264,8 +1436,8 @@ UResourceBundle *init_resb_result(
}
resB->fData = dataEntry;
entryIncrease(resB->fData);
- resB->fHasFallback = FALSE;
- resB->fIsTopLevel = FALSE;
+ resB->fHasFallback = false;
+ resB->fIsTopLevel = false;
resB->fIndex = -1;
resB->fKey = key;
resB->fValidLocaleDataEntry = validLocaleDataEntry;
@@ -1318,7 +1490,7 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin
}
if(original != NULL) {
if(r == NULL) {
- isStackObject = FALSE;
+ isStackObject = false;
r = (UResourceBundle *)uprv_malloc(sizeof(UResourceBundle));
/* test for NULL */
if (r == NULL) {
@@ -1327,7 +1499,7 @@ UResourceBundle *ures_copyResb(UResourceBundle *r, const UResourceBundle *origin
}
} else {
isStackObject = ures_isStackObject(r);
- ures_closeBundle(r, FALSE);
+ ures_closeBundle(r, false);
}
uprv_memcpy(r, original, sizeof(UResourceBundle));
r->fResPath = NULL;
@@ -1409,7 +1581,7 @@ ures_toUTF8String(const UChar *s16, int32_t length16,
* may store UTF-8 natively.
* (In which case dest would not be used at all.)
*
- * We do not do this if forceCopy=TRUE because then the caller
+ * We do not do this if forceCopy=true because then the caller
* expects the string to start exactly at dest.
*
* The test above for <= 0x2aaaaaaa prevents overflows.
@@ -1553,7 +1725,7 @@ U_CAPI void U_EXPORT2 ures_resetIterator(UResourceBundle *resB){
U_CAPI UBool U_EXPORT2 ures_hasNext(const UResourceBundle *resB) {
if(resB == NULL) {
- return FALSE;
+ return false;
}
return (UBool)(resB->fIndex < resB->fSize-1);
}
@@ -2133,7 +2305,7 @@ void getAllItemsWithFallback(
parentRef.fData = parentEntry;
parentRef.fValidLocaleDataEntry = bundle->fValidLocaleDataEntry;
parentRef.fHasFallback = !parentRef.getResData().noFallback;
- parentRef.fIsTopLevel = TRUE;
+ parentRef.fIsTopLevel = true;
parentRef.fRes = parentRef.getResData().rootRes;
parentRef.fSize = res_countArrayItems(&parentRef.getResData(), parentRef.fRes);
parentRef.fIndex = -1;
@@ -2276,7 +2448,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con
res = res_getTableItemByKey(&resB->getResData(), resB->fRes, &t, &key);
if(res == RES_BOGUS) {
key = inKey;
- if(resB->fHasFallback == TRUE) {
+ if(resB->fHasFallback == true) {
dataEntry = getFallbackData(resB, &key, &res, status);
if(U_SUCCESS(*status)) {
/* check if resB->fResPath gives the right name here */
@@ -2294,7 +2466,7 @@ U_CAPI UResourceBundle* U_EXPORT2 ures_getByKey(const UResourceBundle *resB, con
#if 0
/* this is a kind of TODO item. If we have an array with an index table, we could do this. */
/* not currently */
- else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) {
+ else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == true) {
/* here should go a first attempt to locate the key using index table */
dataEntry = getFallbackData(resB, &key, &res, status);
if(U_SUCCESS(*status)) {
@@ -2331,7 +2503,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
if(res == RES_BOGUS) {
key = inKey;
- if(resB->fHasFallback == TRUE) {
+ if(resB->fHasFallback == true) {
dataEntry = getFallbackData(resB, &key, &res, status);
if(U_SUCCESS(*status)) {
switch (RES_GET_TYPE(res)) {
@@ -2376,7 +2548,7 @@ U_CAPI const UChar* U_EXPORT2 ures_getStringByKey(const UResourceBundle *resB, c
#if 0
/* this is a kind of TODO item. If we have an array with an index table, we could do this. */
/* not currently */
- else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == TRUE) {
+ else if(RES_GET_TYPE(resB->fRes) == URES_ARRAY && resB->fHasFallback == true) {
/* here should go a first attempt to locate the key using index table */
dataEntry = getFallbackData(resB, &key, &res, status);
if(U_SUCCESS(*status)) {
@@ -2510,17 +2682,17 @@ ures_openWithType(UResourceBundle *r, const char* path, const char* localeID,
*status = U_MEMORY_ALLOCATION_ERROR;
return NULL;
}
- isStackObject = FALSE;
+ isStackObject = false;
} else { // fill-in
isStackObject = ures_isStackObject(r);
- ures_closeBundle(r, FALSE);
+ ures_closeBundle(r, false);
}
uprv_memset(r, 0, sizeof(UResourceBundle));
ures_setIsStackObject(r, isStackObject);
r->fValidLocaleDataEntry = r->fData = entry;
r->fHasFallback = openType != URES_OPEN_DIRECT && !r->getResData().noFallback;
- r->fIsTopLevel = TRUE;
+ r->fIsTopLevel = true;
r->fRes = r->getResData().rootRes;
r->fSize = res_countArrayItems(&r->getResData(), r->fRes);
r->fIndex = -1;
@@ -2795,10 +2967,10 @@ static UBool isLocaleInList(UEnumeration *locEnum, const char *locToSearch, UErr
const char *loc;
while ((loc = uenum_next(locEnum, NULL, status)) != NULL) {
if (uprv_strcmp(loc, locToSearch) == 0) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
U_CAPI int32_t U_EXPORT2
@@ -2836,7 +3008,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
if(isAvailable) {
UEnumeration *locEnum = ures_openAvailableLocales(path, &subStatus);
- *isAvailable = TRUE;
+ *isAvailable = true;
if (U_SUCCESS(subStatus)) {
*isAvailable = isLocaleInList(locEnum, parent, &subStatus);
}
@@ -2854,7 +3026,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
if(((subStatus == U_USING_FALLBACK_WARNING) ||
(subStatus == U_USING_DEFAULT_WARNING)) && isAvailable)
{
- *isAvailable = FALSE;
+ *isAvailable = false;
}
isAvailable = NULL; /* only want to set this the first time around */
@@ -2910,7 +3082,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
subStatus = U_ZERO_ERROR;
res = ures_open(path, parent, &subStatus);
if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
- *isAvailable = FALSE;
+ *isAvailable = false;
}
isAvailable = NULL; /* only want to set this the first time around */
@@ -2991,7 +3163,7 @@ ures_getFunctionalEquivalent(char *result, int32_t resultCapacity,
subStatus = U_ZERO_ERROR;
res = ures_open(path, parent, &subStatus);
if((subStatus == U_USING_FALLBACK_WARNING) && isAvailable) {
- *isAvailable = FALSE;
+ *isAvailable = false;
}
isAvailable = NULL; /* only want to set this the first time around */
@@ -3224,32 +3396,32 @@ ures_equal(const UResourceBundle* res1, const UResourceBundle* res2){
return (res1->fKey==res2->fKey);
}else{
if(uprv_strcmp(res1->fKey, res2->fKey)!=0){
- return FALSE;
+ return false;
}
}
if(uprv_strcmp(res1->fData->fName, res2->fData->fName)!=0){
- return FALSE;
+ return false;
}
if(res1->fData->fPath == NULL|| res2->fData->fPath==NULL){
return (res1->fData->fPath == res2->fData->fPath);
}else{
if(uprv_strcmp(res1->fData->fPath, res2->fData->fPath)!=0){
- return FALSE;
+ return false;
}
}
if(uprv_strcmp(res1->fData->fParent->fName, res2->fData->fParent->fName)!=0){
- return FALSE;
+ return false;
}
if(uprv_strcmp(res1->fData->fParent->fPath, res2->fData->fParent->fPath)!=0){
- return FALSE;
+ return false;
}
if(uprv_strncmp(res1->fResPath, res2->fResPath, res1->fResPathLen)!=0){
- return FALSE;
+ return false;
}
if(res1->fRes != res2->fRes){
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
U_CAPI UResourceBundle* U_EXPORT2
ures_clone(const UResourceBundle* res, UErrorCode* status){
diff --git a/thirdparty/icu4c/common/uresdata.cpp b/thirdparty/icu4c/common/uresdata.cpp
index 9af081be40..a1222d415c 100644
--- a/thirdparty/icu4c/common/uresdata.cpp
+++ b/thirdparty/icu4c/common/uresdata.cpp
@@ -234,7 +234,7 @@ res_init(ResourceData *pResData,
* formatVersion 1: compare key strings in native-charset order
* formatVersion 2 and up: compare key strings in ASCII order
*/
- pResData->useNativeStrcmp=TRUE;
+ pResData->useNativeStrcmp=true;
}
}
@@ -377,10 +377,10 @@ UBool isNoInheritanceMarker(const ResourceData *pResData, Resource res) {
return p[1] == 0x2205 && p[2] == 0x2205 && p[3] == 0x2205;
} else {
// Assume that the string has not been stored with more length units than necessary.
- return FALSE;
+ return false;
}
}
- return FALSE;
+ return false;
}
int32_t getStringArray(const ResourceData *pResData, const icu::ResourceArray &array,
@@ -409,7 +409,7 @@ int32_t getStringArray(const ResourceData *pResData, const icu::ResourceArray &a
errorCode = U_RESOURCE_TYPE_MISMATCH;
return 0;
}
- dest[i].setTo(TRUE, s, sLength);
+ dest[i].setTo(true, s, sLength);
}
return length;
}
@@ -660,7 +660,7 @@ int32_t ResourceDataValue::getStringArrayOrStringAsArray(UnicodeString *dest, in
int32_t sLength;
const UChar *s = res_getString(fTraceInfo, &getData(), res, &sLength);
if(s != NULL) {
- dest[0].setTo(TRUE, s, sLength);
+ dest[0].setTo(true, s, sLength);
return 1;
}
errorCode = U_RESOURCE_TYPE_MISMATCH;
@@ -675,7 +675,7 @@ UnicodeString ResourceDataValue::getStringOrFirstOfArray(UErrorCode &errorCode)
int32_t sLength;
const UChar *s = res_getString(fTraceInfo, &getData(), res, &sLength);
if(s != NULL) {
- us.setTo(TRUE, s, sLength);
+ us.setTo(true, s, sLength);
return us;
}
ResourceArray array = getArray(errorCode);
@@ -686,7 +686,7 @@ UnicodeString ResourceDataValue::getStringOrFirstOfArray(UErrorCode &errorCode)
// Tracing is already performed above (unimportant for trace that this is an array)
s = res_getStringNoTrace(&getData(), array.internalGetResource(&getData(), 0), &sLength);
if(s != NULL) {
- us.setTo(TRUE, s, sLength);
+ us.setTo(true, s, sLength);
return us;
}
}
@@ -837,9 +837,9 @@ UBool icu::ResourceTable::getKeyAndValue(int32_t i,
// alive for the duration that fields are being read from it
// (including nested fields).
rdValue.setResource(res, ResourceTracer(fTraceInfo, key));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
UBool icu::ResourceTable::findValue(const char *key, ResourceValue &value) const {
@@ -860,9 +860,9 @@ UBool icu::ResourceTable::findValue(const char *key, ResourceValue &value) const
}
// Same note about lifetime as in getKeyAndValue().
rdValue.setResource(res, ResourceTracer(fTraceInfo, key));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CAPI Resource U_EXPORT2
@@ -912,9 +912,9 @@ UBool icu::ResourceArray::getValue(int32_t i, icu::ResourceValue &value) const {
rdValue.setResource(
internalGetResource(&rdValue.getData(), i),
ResourceTracer(fTraceInfo, i));
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
U_CFUNC Resource
@@ -1222,7 +1222,7 @@ ures_swapResource(const UDataSwapper *ds,
}
uprv_sortArray(pTempTable->rows, count, sizeof(Row),
ures_compareRows, pTempTable->keyChars,
- FALSE, pErrorCode);
+ false, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
udata_printError(ds, "ures_swapResource(table res=%08x).uprv_sortArray(%d items) failed\n",
res, count);
diff --git a/thirdparty/icu4c/common/usc_impl.cpp b/thirdparty/icu4c/common/usc_impl.cpp
index 111029b974..a4e2fc6069 100644
--- a/thirdparty/icu4c/common/usc_impl.cpp
+++ b/thirdparty/icu4c/common/usc_impl.cpp
@@ -261,7 +261,7 @@ uscript_nextRun(UScriptRun *scriptRun, int32_t *pRunStart, int32_t *pRunLimit, U
/* if we've fallen off the end of the text, we're done */
if (scriptRun == NULL || scriptRun->scriptLimit >= scriptRun->textLength) {
- return FALSE;
+ return false;
}
SYNC_FIXUP(scriptRun);
@@ -357,5 +357,5 @@ uscript_nextRun(UScriptRun *scriptRun, int32_t *pRunStart, int32_t *pRunLimit, U
*pRunScript = scriptRun->scriptCode;
}
- return TRUE;
+ return true;
}
diff --git a/thirdparty/icu4c/common/uscript.cpp b/thirdparty/icu4c/common/uscript.cpp
index f8bd7e7fdd..1ededbb268 100644
--- a/thirdparty/icu4c/common/uscript.cpp
+++ b/thirdparty/icu4c/common/uscript.cpp
@@ -113,14 +113,14 @@ uscript_getCode(const char* nameOrAbbrOrLocale,
return 0;
}
- triedCode = FALSE;
+ triedCode = false;
if(uprv_strchr(nameOrAbbrOrLocale, '-')==NULL && uprv_strchr(nameOrAbbrOrLocale, '_')==NULL ){
/* try long and abbreviated script names first */
UScriptCode code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, nameOrAbbrOrLocale);
if(code!=USCRIPT_INVALID_CODE) {
return setOneCode(code, fillIn, capacity, err);
}
- triedCode = TRUE;
+ triedCode = true;
}
internalErrorCode = U_ZERO_ERROR;
length = getCodesFromLocale(nameOrAbbrOrLocale, fillIn, capacity, err);
diff --git a/thirdparty/icu4c/common/uscript_props.cpp b/thirdparty/icu4c/common/uscript_props.cpp
index 07bae251ea..886acfafa8 100644
--- a/thirdparty/icu4c/common/uscript_props.cpp
+++ b/thirdparty/icu4c/common/uscript_props.cpp
@@ -242,6 +242,8 @@ const int32_t SCRIPT_PROPS[] = {
0x16ABC | EXCLUSION, // Tnsa
0x1E290 | EXCLUSION, // Toto
0x10582 | EXCLUSION | CASED, // Vith
+ 0x11F1B | EXCLUSION | LB_LETTERS, // Kawi
+ 0x1E4E6 | EXCLUSION, // Nagm
// End copy-paste from parsescriptmetadata.py
};
diff --git a/thirdparty/icu4c/common/uset.cpp b/thirdparty/icu4c/common/uset.cpp
index 871a5d8986..2152693560 100644
--- a/thirdparty/icu4c/common/uset.cpp
+++ b/thirdparty/icu4c/common/uset.cpp
@@ -344,12 +344,12 @@ uset_getItem(const USet* uset, int32_t itemIndex,
//uset_getRange(const USet* set, int32_t rangeIndex,
// UChar32* pStart, UChar32* pEnd) {
// if ((uint32_t) rangeIndex >= (uint32_t) uset_getRangeCount(set)) {
-// return FALSE;
+// return false;
// }
// const UnicodeSet* us = (const UnicodeSet*) set;
// *pStart = us->getRangeStart(rangeIndex);
// *pEnd = us->getRangeEnd(rangeIndex);
-// return TRUE;
+// return true;
//}
/*
@@ -384,11 +384,11 @@ uset_getSerializedSet(USerializedSet* fillSet, const uint16_t* src, int32_t srcL
int32_t length;
if(fillSet==NULL) {
- return FALSE;
+ return false;
}
if(src==NULL || srcLength<=0) {
fillSet->length=fillSet->bmpLength=0;
- return FALSE;
+ return false;
}
length=*src++;
@@ -397,20 +397,20 @@ uset_getSerializedSet(USerializedSet* fillSet, const uint16_t* src, int32_t srcL
length&=0x7fff;
if(srcLength<(2+length)) {
fillSet->length=fillSet->bmpLength=0;
- return FALSE;
+ return false;
}
fillSet->bmpLength=*src++;
} else {
/* only BMP values */
if(srcLength<(1+length)) {
fillSet->length=fillSet->bmpLength=0;
- return FALSE;
+ return false;
}
fillSet->bmpLength=length;
}
fillSet->array=src;
fillSet->length=length;
- return TRUE;
+ return true;
}
U_CAPI void U_EXPORT2
@@ -451,7 +451,7 @@ uset_serializedContains(const USerializedSet* set, UChar32 c) {
const uint16_t* array;
if(set==NULL || (uint32_t)c>0x10ffff) {
- return FALSE;
+ return false;
}
array=set->array;
@@ -520,7 +520,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
int32_t bmpLength, length;
if(set==NULL || rangeIndex<0 || pStart==NULL || pEnd==NULL) {
- return FALSE;
+ return false;
}
array=set->array;
@@ -537,7 +537,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
} else {
*pEnd=0x10ffff;
}
- return TRUE;
+ return true;
} else {
rangeIndex-=bmpLength;
rangeIndex*=2; /* address pairs of pairs of units */
@@ -551,9 +551,9 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
} else {
*pEnd=0x10ffff;
}
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
}
@@ -591,14 +591,14 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
// int32_t i, length, more;
//
// if(set==NULL || (uint32_t)c>0x10ffff) {
-// return FALSE;
+// return false;
// }
//
// length=set->length;
// i=findChar(set->array, length, c);
// if((i&1)^doRemove) {
// /* c is already in the set */
-// return TRUE;
+// return true;
// }
//
// /* how many more array items do we need? */
@@ -615,7 +615,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
// }
// }
// }
-// return TRUE;
+// return true;
// } else if(i>0 && c==set->array[i-1]) {
// /* c is just after the previous range, extend that in-place by one */
// if(++c<=0x10ffff) {
@@ -632,7 +632,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
// /* extend the previous range (had limit 0x10ffff) to the end of Unicode */
// set->length=i-1;
// }
-// return TRUE;
+// return true;
// } else if(i==length && c==0x10ffff) {
// /* insert one range limit c */
// more=1;
@@ -647,7 +647,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
// int32_t newCapacity=set->capacity+set->capacity/2+USET_GROW_DELTA;
// UChar32* newArray=(UChar32* )uprv_malloc(newCapacity*4);
// if(newArray==NULL) {
-// return FALSE;
+// return false;
// }
// set->capacity=newCapacity;
// uprv_memcpy(newArray, set->array, length*4);
@@ -667,7 +667,7 @@ uset_getSerializedRange(const USerializedSet* set, int32_t rangeIndex,
// }
// set->length+=more;
//
-// return TRUE;
+// return true;
// }
//
// U_CAPI UBool U_EXPORT2
diff --git a/thirdparty/icu4c/common/usetiter.cpp b/thirdparty/icu4c/common/usetiter.cpp
index 7915169049..3cdece5500 100644
--- a/thirdparty/icu4c/common/usetiter.cpp
+++ b/thirdparty/icu4c/common/usetiter.cpp
@@ -50,19 +50,19 @@ UBool UnicodeSetIterator::next() {
if (nextElement <= endElement) {
codepoint = codepointEnd = nextElement++;
string = NULL;
- return TRUE;
+ return true;
}
if (range < endRange) {
loadRange(++range);
codepoint = codepointEnd = nextElement++;
string = NULL;
- return TRUE;
+ return true;
}
- if (nextString >= stringCount) return FALSE;
+ if (nextString >= stringCount) return false;
codepoint = (UChar32)IS_STRING; // signal that value is actually a string
string = (const UnicodeString*) set->strings->elementAt(nextString++);
- return TRUE;
+ return true;
}
/**
@@ -82,20 +82,20 @@ UBool UnicodeSetIterator::nextRange() {
codepointEnd = endElement;
codepoint = nextElement;
nextElement = endElement+1;
- return TRUE;
+ return true;
}
if (range < endRange) {
loadRange(++range);
codepointEnd = endElement;
codepoint = nextElement;
nextElement = endElement+1;
- return TRUE;
+ return true;
}
- if (nextString >= stringCount) return FALSE;
+ if (nextString >= stringCount) return false;
codepoint = (UChar32)IS_STRING; // signal that value is actually a string
string = (const UnicodeString*) set->strings->elementAt(nextString++);
- return TRUE;
+ return true;
}
/**
diff --git a/thirdparty/icu4c/common/ushape.cpp b/thirdparty/icu4c/common/ushape.cpp
index ae13b5c118..babbbe52a8 100644
--- a/thirdparty/icu4c/common/ushape.cpp
+++ b/thirdparty/icu4c/common/ushape.cpp
@@ -354,10 +354,10 @@ _shapeToArabicDigitsWithContext(UChar *s, int32_t length,
switch(ubidi_getClass(c)) {
case U_LEFT_TO_RIGHT: /* L */
case U_RIGHT_TO_LEFT: /* R */
- lastStrongWasAL=FALSE;
+ lastStrongWasAL=false;
break;
case U_RIGHT_TO_LEFT_ARABIC: /* AL */
- lastStrongWasAL=TRUE;
+ lastStrongWasAL=true;
break;
case U_EUROPEAN_NUMBER: /* EN */
if(lastStrongWasAL && (uint32_t)(c-0x30)<10) {
@@ -374,10 +374,10 @@ _shapeToArabicDigitsWithContext(UChar *s, int32_t length,
switch(ubidi_getClass(c)) {
case U_LEFT_TO_RIGHT: /* L */
case U_RIGHT_TO_LEFT: /* R */
- lastStrongWasAL=FALSE;
+ lastStrongWasAL=false;
break;
case U_RIGHT_TO_LEFT_ARABIC: /* AL */
- lastStrongWasAL=TRUE;
+ lastStrongWasAL=true;
break;
case U_EUROPEAN_NUMBER: /* EN */
if(lastStrongWasAL && (uint32_t)(c-0x30)<10) {
@@ -1710,13 +1710,13 @@ u_shapeArabic(const UChar *source, int32_t sourceLength,
_shapeToArabicDigitsWithContext(dest, destLength,
digitBase,
(UBool)((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_LOGICAL),
- FALSE);
+ false);
break;
case U_SHAPE_DIGITS_ALEN2AN_INIT_AL:
_shapeToArabicDigitsWithContext(dest, destLength,
digitBase,
(UBool)((options&U_SHAPE_TEXT_DIRECTION_MASK)==U_SHAPE_TEXT_DIRECTION_LOGICAL),
- TRUE);
+ true);
break;
default:
/* will never occur because of validity checks above */
diff --git a/thirdparty/icu4c/common/usprep.cpp b/thirdparty/icu4c/common/usprep.cpp
index 41a1f56c77..50d16081d1 100644
--- a/thirdparty/icu4c/common/usprep.cpp
+++ b/thirdparty/icu4c/common/usprep.cpp
@@ -45,7 +45,7 @@ U_CDECL_BEGIN
Static cache for already opened StringPrep profiles
*/
static UHashtable *SHARED_DATA_HASHTABLE = NULL;
-static icu::UInitOnce gSharedDataInitOnce = U_INITONCE_INITIALIZER;
+static icu::UInitOnce gSharedDataInitOnce {};
static UMutex usprepMutex;
/* format version of spp file */
@@ -91,9 +91,9 @@ isSPrepAcceptable(void * /* context */,
) {
//uprv_memcpy(formatVersion, pInfo->formatVersion, 4);
uprv_memcpy(dataVersion, pInfo->dataVersion, 4);
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
@@ -159,8 +159,8 @@ usprep_internal_flushCache(UBool noRefCount){
profile = (UStringPrepProfile *) e->value.pointer;
key = (UStringPrepKey *) e->key.pointer;
- if ((noRefCount== FALSE && profile->refCount == 0) ||
- noRefCount== TRUE) {
+ if ((noRefCount== false && profile->refCount == 0) ||
+ noRefCount== true) {
deletedNum++;
uhash_removeElement(SHARED_DATA_HASHTABLE, e);
@@ -188,13 +188,13 @@ usprep_internal_flushCache(UBool noRefCount){
/* Works just like ucnv_flushCache()
static int32_t
usprep_flushCache(){
- return usprep_internal_flushCache(FALSE);
+ return usprep_internal_flushCache(false);
}
*/
static UBool U_CALLCONV usprep_cleanup(void){
if (SHARED_DATA_HASHTABLE != NULL) {
- usprep_internal_flushCache(TRUE);
+ usprep_internal_flushCache(true);
if (SHARED_DATA_HASHTABLE != NULL && uhash_count(SHARED_DATA_HASHTABLE) == 0) {
uhash_close(SHARED_DATA_HASHTABLE);
SHARED_DATA_HASHTABLE = NULL;
@@ -243,7 +243,7 @@ loadData(UStringPrepProfile* profile,
//TODO: change the path
dataMemory=udata_openChoice(path, type, name, isSPrepAcceptable, NULL, errorCode);
if(U_FAILURE(*errorCode)) {
- return FALSE;
+ return false;
}
p=(const int32_t *)udata_getMemory(dataMemory);
@@ -254,7 +254,7 @@ loadData(UStringPrepProfile* profile,
if(U_FAILURE(*errorCode)) {
udata_close(dataMemory);
- return FALSE;
+ return false;
}
/* in the mutex block, set the data for this process */
@@ -280,7 +280,7 @@ loadData(UStringPrepProfile* profile,
if(U_FAILURE(*errorCode)){
udata_close(dataMemory);
- return FALSE;
+ return false;
}
if( normUniVer < sprepUniVer && /* the Unicode version of SPREP file must be less than the Unicode Version of the normalization data */
normUniVer < normCorrVer && /* the Unicode version of the NormalizationCorrections.txt file should be less than the Unicode Version of the normalization data */
@@ -288,9 +288,9 @@ loadData(UStringPrepProfile* profile,
){
*errorCode = U_INVALID_FORMAT_ERROR;
udata_close(dataMemory);
- return FALSE;
+ return false;
}
- profile->isDataLoaded = TRUE;
+ profile->isDataLoaded = true;
/* if a different thread set it first, then close the extra data */
if(dataMemory!=NULL) {
@@ -474,28 +474,28 @@ getValues(uint16_t trieWord, int16_t& value, UBool& isIndex){
* the source codepoint is copied to the destination
*/
type = USPREP_TYPE_LIMIT;
- isIndex =FALSE;
+ isIndex =false;
value = 0;
}else if(trieWord >= _SPREP_TYPE_THRESHOLD){
type = (UStringPrepType) (trieWord - _SPREP_TYPE_THRESHOLD);
- isIndex =FALSE;
+ isIndex =false;
value = 0;
}else{
/* get the type */
type = USPREP_MAP;
/* ascertain if the value is index or delta */
if(trieWord & 0x02){
- isIndex = TRUE;
+ isIndex = true;
value = trieWord >> 2; //mask off the lower 2 bits and shift
}else{
- isIndex = FALSE;
+ isIndex = false;
value = (int16_t)trieWord;
value = (value >> 2);
}
if((trieWord>>2) == _SPREP_MAX_INDEX_VALUE){
type = USPREP_DELETE;
- isIndex =FALSE;
+ isIndex =false;
value = 0;
}
}
@@ -535,7 +535,7 @@ usprep_map( const UStringPrepProfile* profile,
type = getValues(result, value, isIndex);
// check if the source codepoint is unassigned
- if(type == USPREP_UNASSIGNED && allowUnassigned == FALSE){
+ if(type == USPREP_UNASSIGNED && allowUnassigned == false){
uprv_syntaxError(src,srcIndex-U16_LENGTH(ch), srcLength,parseError);
*status = U_STRINGPREP_UNASSIGNED_ERROR;
@@ -709,7 +709,7 @@ usprep_prepare( const UStringPrepProfile* profile,
const UChar *b2 = s2.getBuffer();
int32_t b2Len = s2.length();
UCharDirection direction=U_CHAR_DIRECTION_COUNT, firstCharDir=U_CHAR_DIRECTION_COUNT;
- UBool leftToRight=FALSE, rightToLeft=FALSE;
+ UBool leftToRight=false, rightToLeft=false;
int32_t rtlPos =-1, ltrPos =-1;
for(int32_t b2Index=0; b2Index<b2Len;){
@@ -737,31 +737,31 @@ usprep_prepare( const UStringPrepProfile* profile,
firstCharDir = direction;
}
if(direction == U_LEFT_TO_RIGHT){
- leftToRight = TRUE;
+ leftToRight = true;
ltrPos = b2Index-1;
}
if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
- rightToLeft = TRUE;
+ rightToLeft = true;
rtlPos = b2Index-1;
}
}
}
- if(profile->checkBiDi == TRUE){
+ if(profile->checkBiDi == true){
// satisfy 2
- if( leftToRight == TRUE && rightToLeft == TRUE){
+ if( leftToRight == true && rightToLeft == true){
*status = U_STRINGPREP_CHECK_BIDI_ERROR;
uprv_syntaxError(b2,(rtlPos>ltrPos) ? rtlPos : ltrPos, b2Len, parseError);
return 0;
}
//satisfy 3
- if( rightToLeft == TRUE &&
+ if( rightToLeft == true &&
!((firstCharDir == U_RIGHT_TO_LEFT || firstCharDir == U_RIGHT_TO_LEFT_ARABIC) &&
(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC))
){
*status = U_STRINGPREP_CHECK_BIDI_ERROR;
uprv_syntaxError(b2, rtlPos, b2Len, parseError);
- return FALSE;
+ return false;
}
}
return s2.extract(dest, destCapacity, *status);
diff --git a/thirdparty/icu4c/common/ustr_cnv.cpp b/thirdparty/icu4c/common/ustr_cnv.cpp
index 9a25a9905a..97fbc527a3 100644
--- a/thirdparty/icu4c/common/ustr_cnv.cpp
+++ b/thirdparty/icu4c/common/ustr_cnv.cpp
@@ -144,7 +144,7 @@ u_uastrncpy(UChar *ucs1,
&s2,
s2+u_astrnlen(s2, n),
NULL,
- TRUE,
+ true,
&err);
ucnv_reset(cnv); /* be good citizens */
u_releaseDefaultConverter(cnv);
@@ -216,7 +216,7 @@ u_austrncpy(char *s1,
&ucs2,
ucs2+u_ustrnlen(ucs2, n),
NULL,
- TRUE,
+ true,
&err);
ucnv_reset(cnv); /* be good citizens */
u_releaseDefaultConverter(cnv);
diff --git a/thirdparty/icu4c/common/ustr_titlecase_brkiter.cpp b/thirdparty/icu4c/common/ustr_titlecase_brkiter.cpp
index 3002d64e34..85dfa0decb 100644
--- a/thirdparty/icu4c/common/ustr_titlecase_brkiter.cpp
+++ b/thirdparty/icu4c/common/ustr_titlecase_brkiter.cpp
@@ -110,7 +110,7 @@ int32_t WholeStringBreakIterator::next() { return length; }
int32_t WholeStringBreakIterator::current() const { return 0; }
int32_t WholeStringBreakIterator::following(int32_t /*offset*/) { return length; }
int32_t WholeStringBreakIterator::preceding(int32_t /*offset*/) { return 0; }
-UBool WholeStringBreakIterator::isBoundary(int32_t /*offset*/) { return FALSE; }
+UBool WholeStringBreakIterator::isBoundary(int32_t /*offset*/) { return false; }
int32_t WholeStringBreakIterator::next(int32_t /*n*/) { return length; }
WholeStringBreakIterator *WholeStringBreakIterator::createBufferClone(
diff --git a/thirdparty/icu4c/common/ustrcase.cpp b/thirdparty/icu4c/common/ustrcase.cpp
index 43910ea520..8037c09b4f 100644
--- a/thirdparty/icu4c/common/ustrcase.cpp
+++ b/thirdparty/icu4c/common/ustrcase.cpp
@@ -107,7 +107,7 @@ appendResult(UChar *dest, int32_t destIndex, int32_t destCapacity,
/* append the result */
if(c>=0) {
/* code point */
- UBool isError=FALSE;
+ UBool isError=false;
U16_APPEND(dest, destIndex, destCapacity, c, isError);
if(isError) {
/* overflow, nothing written */
@@ -1087,12 +1087,12 @@ UBool isFollowedByCasedLetter(const UChar *s, int32_t i, int32_t length) {
if ((type & UCASE_IGNORABLE) != 0) {
// Case-ignorable, continue with the loop.
} else if (type != UCASE_NONE) {
- return TRUE; // Followed by cased letter.
+ return true; // Followed by cased letter.
} else {
- return FALSE; // Uncased and not case-ignorable.
+ return false; // Uncased and not case-ignorable.
}
}
- return FALSE; // Not followed by cased letter.
+ return false; // Not followed by cased letter.
}
/**
@@ -1155,7 +1155,7 @@ int32_t toUpper(uint32_t options,
nextState |= AFTER_VOWEL_WITH_ACCENT;
}
// Map according to Greek rules.
- UBool addTonos = FALSE;
+ UBool addTonos = false;
if (upper == 0x397 &&
(data & HAS_ACCENT) != 0 &&
numYpogegrammeni == 0 &&
@@ -1166,7 +1166,7 @@ int32_t toUpper(uint32_t options,
if (i == nextIndex) {
upper = 0x389; // Preserve the precomposed form.
} else {
- addTonos = TRUE;
+ addTonos = true;
}
} else if ((data & HAS_DIALYTIKA) != 0) {
// Preserve a vowel with dialytika in precomposed form if it exists.
@@ -1181,7 +1181,7 @@ int32_t toUpper(uint32_t options,
UBool change;
if (edits == nullptr && (options & U_OMIT_UNCHANGED_TEXT) == 0) {
- change = TRUE; // common, simple usage
+ change = true; // common, simple usage
} else {
// Find out first whether we are changing the text.
change = src[i] != upper || numYpogegrammeni > 0;
diff --git a/thirdparty/icu4c/common/ustring.cpp b/thirdparty/icu4c/common/ustring.cpp
index 8477256389..5804976ef9 100644
--- a/thirdparty/icu4c/common/ustring.cpp
+++ b/thirdparty/icu4c/common/ustring.cpp
@@ -43,13 +43,13 @@ static inline UBool
isMatchAtCPBoundary(const UChar *start, const UChar *match, const UChar *matchLimit, const UChar *limit) {
if(U16_IS_TRAIL(*match) && start!=match && U16_IS_LEAD(*(match-1))) {
/* the leading edge of the match is in the middle of a surrogate pair */
- return FALSE;
+ return false;
}
if(U16_IS_LEAD(*(matchLimit-1)) && matchLimit!=limit && U16_IS_TRAIL(*matchLimit)) {
/* the trailing edge of the match is in the middle of a surrogate pair */
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
U_CAPI UChar * U_EXPORT2
@@ -461,7 +461,7 @@ u_memrchr32(const UChar *s, UChar32 c, int32_t count) {
/*
* Match each code point in a string against each code point in the matchSet.
* Return the index of the first string code point that
- * is (polarity==TRUE) or is not (FALSE) contained in the matchSet.
+ * is (polarity==true) or is not (false) contained in the matchSet.
* Return -(string length)-1 if there is no such code point.
*/
static int32_t
@@ -540,7 +540,7 @@ endloop:
U_CAPI UChar * U_EXPORT2
u_strpbrk(const UChar *string, const UChar *matchSet)
{
- int32_t idx = _matchFromSet(string, matchSet, TRUE);
+ int32_t idx = _matchFromSet(string, matchSet, true);
if(idx >= 0) {
return (UChar *)string + idx;
} else {
@@ -552,7 +552,7 @@ u_strpbrk(const UChar *string, const UChar *matchSet)
U_CAPI int32_t U_EXPORT2
u_strcspn(const UChar *string, const UChar *matchSet)
{
- int32_t idx = _matchFromSet(string, matchSet, TRUE);
+ int32_t idx = _matchFromSet(string, matchSet, true);
if(idx >= 0) {
return idx;
} else {
@@ -564,7 +564,7 @@ u_strcspn(const UChar *string, const UChar *matchSet)
U_CAPI int32_t U_EXPORT2
u_strspn(const UChar *string, const UChar *matchSet)
{
- int32_t idx = _matchFromSet(string, matchSet, FALSE);
+ int32_t idx = _matchFromSet(string, matchSet, false);
if(idx >= 0) {
return idx;
} else {
@@ -929,13 +929,13 @@ u_strCompare(const UChar *s1, int32_t length1,
if(s1==NULL || length1<-1 || s2==NULL || length2<-1) {
return 0;
}
- return uprv_strCompare(s1, length1, s2, length2, FALSE, codePointOrder);
+ return uprv_strCompare(s1, length1, s2, length2, false, codePointOrder);
}
/* String compare in code point order - u_strcmp() compares in code unit order. */
U_CAPI int32_t U_EXPORT2
u_strcmpCodePointOrder(const UChar *s1, const UChar *s2) {
- return uprv_strCompare(s1, -1, s2, -1, FALSE, TRUE);
+ return uprv_strCompare(s1, -1, s2, -1, false, true);
}
U_CAPI int32_t U_EXPORT2
@@ -960,7 +960,7 @@ u_strncmp(const UChar *s1,
U_CAPI int32_t U_EXPORT2
u_strncmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t n) {
- return uprv_strCompare(s1, n, s2, n, TRUE, TRUE);
+ return uprv_strCompare(s1, n, s2, n, true, true);
}
U_CAPI UChar* U_EXPORT2
@@ -1049,10 +1049,10 @@ U_CAPI UBool U_EXPORT2
u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
if(number<0) {
- return TRUE;
+ return true;
}
if(s==NULL || length<-1) {
- return FALSE;
+ return false;
}
if(length==-1) {
@@ -1062,10 +1062,10 @@ u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
/* count code points until they exceed */
for(;;) {
if((c=*s++)==0) {
- return FALSE;
+ return false;
}
if(number==0) {
- return TRUE;
+ return true;
}
if(U16_IS_LEAD(c) && U16_IS_TRAIL(*s)) {
++s;
@@ -1079,13 +1079,13 @@ u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
/* s contains at least (length+1)/2 code points: <=2 UChars per cp */
if(((length+1)/2)>number) {
- return TRUE;
+ return true;
}
/* check if s does not even contain enough UChars */
maxSupplementary=length-number;
if(maxSupplementary<=0) {
- return FALSE;
+ return false;
}
/* there are maxSupplementary=length-number more UChars than asked-for code points */
@@ -1096,16 +1096,16 @@ u_strHasMoreChar32Than(const UChar *s, int32_t length, int32_t number) {
limit=s+length;
for(;;) {
if(s==limit) {
- return FALSE;
+ return false;
}
if(number==0) {
- return TRUE;
+ return true;
}
if(U16_IS_LEAD(*s++) && s!=limit && U16_IS_TRAIL(*s)) {
++s;
if(--maxSupplementary<=0) {
/* too many pairs - too few code points */
- return FALSE;
+ return false;
}
}
--number;
@@ -1162,7 +1162,7 @@ u_memcmp(const UChar *buf1, const UChar *buf2, int32_t count) {
U_CAPI int32_t U_EXPORT2
u_memcmpCodePointOrder(const UChar *s1, const UChar *s2, int32_t count) {
- return uprv_strCompare(s1, count, s2, count, FALSE, TRUE);
+ return uprv_strCompare(s1, count, s2, count, false, true);
}
/* u_unescape & support fns ------------------------------------------------- */
@@ -1223,7 +1223,7 @@ u_unescapeAt(UNESCAPE_CHAR_AT charAt,
int8_t maxDig = 0;
int8_t bitsPerDigit = 4;
int32_t dig;
- UBool braces = FALSE;
+ UBool braces = false;
/* Check that offset is in range */
if (*offset < 0 || *offset >= length) {
@@ -1245,7 +1245,7 @@ u_unescapeAt(UNESCAPE_CHAR_AT charAt,
minDig = 1;
if (*offset < length && charAt(*offset, context) == u'{') {
++(*offset);
- braces = TRUE;
+ braces = true;
maxDig = 8;
} else {
maxDig = 2;
diff --git a/thirdparty/icu4c/common/ustrtrns.cpp b/thirdparty/icu4c/common/ustrtrns.cpp
index 5dc032c02f..dcb9dc5878 100644
--- a/thirdparty/icu4c/common/ustrtrns.cpp
+++ b/thirdparty/icu4c/common/ustrtrns.cpp
@@ -119,7 +119,7 @@ u_strFromUTF32WithSub(UChar *dest,
} else {
++numSubstitutions;
}
- } while(TRUE);
+ } while(true);
}
reqLength += (int32_t)(pDest - dest);
diff --git a/thirdparty/icu4c/common/utext.cpp b/thirdparty/icu4c/common/utext.cpp
index ec79700ca8..548e6a60f3 100644
--- a/thirdparty/icu4c/common/utext.cpp
+++ b/thirdparty/icu4c/common/utext.cpp
@@ -49,14 +49,14 @@ utext_moveIndex32(UText *ut, int32_t delta) {
UChar32 c;
if (delta > 0) {
do {
- if(ut->chunkOffset>=ut->chunkLength && !utext_access(ut, ut->chunkNativeLimit, TRUE)) {
- return FALSE;
+ if(ut->chunkOffset>=ut->chunkLength && !utext_access(ut, ut->chunkNativeLimit, true)) {
+ return false;
}
c = ut->chunkContents[ut->chunkOffset];
if (U16_IS_SURROGATE(c)) {
c = utext_next32(ut);
if (c == U_SENTINEL) {
- return FALSE;
+ return false;
}
} else {
ut->chunkOffset++;
@@ -65,14 +65,14 @@ utext_moveIndex32(UText *ut, int32_t delta) {
} else if (delta<0) {
do {
- if(ut->chunkOffset<=0 && !utext_access(ut, ut->chunkNativeStart, FALSE)) {
- return FALSE;
+ if(ut->chunkOffset<=0 && !utext_access(ut, ut->chunkNativeStart, false)) {
+ return false;
}
c = ut->chunkContents[ut->chunkOffset-1];
if (U16_IS_SURROGATE(c)) {
c = utext_previous32(ut);
if (c == U_SENTINEL) {
- return FALSE;
+ return false;
}
} else {
ut->chunkOffset--;
@@ -80,7 +80,7 @@ utext_moveIndex32(UText *ut, int32_t delta) {
} while(++delta<0);
}
- return TRUE;
+ return true;
}
@@ -114,7 +114,7 @@ utext_setNativeIndex(UText *ut, int64_t index) {
// Access the new position. Assume a forward iteration from here,
// which will also be optimimum for a single random access.
// Reverse iterations may suffer slightly.
- ut->pFuncs->access(ut, index, TRUE);
+ ut->pFuncs->access(ut, index, true);
} else if((int32_t)(index - ut->chunkNativeStart) <= ut->nativeIndexingLimit) {
// utf-16 indexing.
ut->chunkOffset=(int32_t)(index-ut->chunkNativeStart);
@@ -127,7 +127,7 @@ utext_setNativeIndex(UText *ut, int64_t index) {
UChar c= ut->chunkContents[ut->chunkOffset];
if (U16_IS_TRAIL(c)) {
if (ut->chunkOffset==0) {
- ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE);
+ ut->pFuncs->access(ut, ut->chunkNativeStart, false);
}
if (ut->chunkOffset>0) {
UChar lead = ut->chunkContents[ut->chunkOffset-1];
@@ -152,7 +152,7 @@ utext_getPreviousNativeIndex(UText *ut) {
int64_t result;
if (i >= 0) {
UChar c = ut->chunkContents[i];
- if (U16_IS_TRAIL(c) == FALSE) {
+ if (U16_IS_TRAIL(c) == false) {
if (i <= ut->nativeIndexingLimit) {
result = ut->chunkNativeStart + i;
} else {
@@ -189,14 +189,14 @@ utext_current32(UText *ut) {
UChar32 c;
if (ut->chunkOffset==ut->chunkLength) {
// Current position is just off the end of the chunk.
- if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+ if (ut->pFuncs->access(ut, ut->chunkNativeLimit, true) == false) {
// Off the end of the text.
return U_SENTINEL;
}
}
c = ut->chunkContents[ut->chunkOffset];
- if (U16_IS_LEAD(c) == FALSE) {
+ if (U16_IS_LEAD(c) == false) {
// Normal, non-supplementary case.
return c;
}
@@ -219,11 +219,11 @@ utext_current32(UText *ut) {
// the original position before the unpaired lead still needs to be restored.
int64_t nativePosition = ut->chunkNativeLimit;
int32_t originalOffset = ut->chunkOffset;
- if (ut->pFuncs->access(ut, nativePosition, TRUE)) {
+ if (ut->pFuncs->access(ut, nativePosition, true)) {
trail = ut->chunkContents[ut->chunkOffset];
}
- UBool r = ut->pFuncs->access(ut, nativePosition, FALSE); // reverse iteration flag loads preceding chunk
- U_ASSERT(r==TRUE);
+ UBool r = ut->pFuncs->access(ut, nativePosition, false); // reverse iteration flag loads preceding chunk
+ U_ASSERT(r==true);
ut->chunkOffset = originalOffset;
if(!r) {
return U_SENTINEL;
@@ -246,7 +246,7 @@ utext_char32At(UText *ut, int64_t nativeIndex) {
if (nativeIndex>=ut->chunkNativeStart && nativeIndex < ut->chunkNativeStart + ut->nativeIndexingLimit) {
ut->chunkOffset = (int32_t)(nativeIndex - ut->chunkNativeStart);
c = ut->chunkContents[ut->chunkOffset];
- if (U16_IS_SURROGATE(c) == FALSE) {
+ if (U16_IS_SURROGATE(c) == false) {
return c;
}
}
@@ -270,13 +270,13 @@ utext_next32(UText *ut) {
UChar32 c;
if (ut->chunkOffset >= ut->chunkLength) {
- if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+ if (ut->pFuncs->access(ut, ut->chunkNativeLimit, true) == false) {
return U_SENTINEL;
}
}
c = ut->chunkContents[ut->chunkOffset++];
- if (U16_IS_LEAD(c) == FALSE) {
+ if (U16_IS_LEAD(c) == false) {
// Normal case, not supplementary.
// (A trail surrogate seen here is just returned as is, as a surrogate value.
// It cannot be part of a pair.)
@@ -284,14 +284,14 @@ utext_next32(UText *ut) {
}
if (ut->chunkOffset >= ut->chunkLength) {
- if (ut->pFuncs->access(ut, ut->chunkNativeLimit, TRUE) == FALSE) {
+ if (ut->pFuncs->access(ut, ut->chunkNativeLimit, true) == false) {
// c is an unpaired lead surrogate at the end of the text.
// return it as it is.
return c;
}
}
UChar32 trail = ut->chunkContents[ut->chunkOffset];
- if (U16_IS_TRAIL(trail) == FALSE) {
+ if (U16_IS_TRAIL(trail) == false) {
// c was an unpaired lead surrogate, not at the end of the text.
// return it as it is (unpaired). Iteration position is on the
// following character, possibly in the next chunk, where the
@@ -310,13 +310,13 @@ utext_previous32(UText *ut) {
UChar32 c;
if (ut->chunkOffset <= 0) {
- if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) {
+ if (ut->pFuncs->access(ut, ut->chunkNativeStart, false) == false) {
return U_SENTINEL;
}
}
ut->chunkOffset--;
c = ut->chunkContents[ut->chunkOffset];
- if (U16_IS_TRAIL(c) == FALSE) {
+ if (U16_IS_TRAIL(c) == false) {
// Normal case, not supplementary.
// (A lead surrogate seen here is just returned as is, as a surrogate value.
// It cannot be part of a pair.)
@@ -324,7 +324,7 @@ utext_previous32(UText *ut) {
}
if (ut->chunkOffset <= 0) {
- if (ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE) == FALSE) {
+ if (ut->pFuncs->access(ut, ut->chunkNativeStart, false) == false) {
// c is an unpaired trail surrogate at the start of the text.
// return it as it is.
return c;
@@ -332,7 +332,7 @@ utext_previous32(UText *ut) {
}
UChar32 lead = ut->chunkContents[ut->chunkOffset-1];
- if (U16_IS_LEAD(lead) == FALSE) {
+ if (U16_IS_LEAD(lead) == false) {
// c was an unpaired trail surrogate, not at the end of the text.
// return it as it is (unpaired). Iteration position is at c
return c;
@@ -351,7 +351,7 @@ utext_next32From(UText *ut, int64_t index) {
if(index<ut->chunkNativeStart || index>=ut->chunkNativeLimit) {
// Desired position is outside of the current chunk.
- if(!ut->pFuncs->access(ut, index, TRUE)) {
+ if(!ut->pFuncs->access(ut, index, true)) {
// no chunk available here
return U_SENTINEL;
}
@@ -391,7 +391,7 @@ utext_previous32From(UText *ut, int64_t index) {
//
if(index<=ut->chunkNativeStart || index>ut->chunkNativeLimit) {
// Requested native index is outside of the current chunk.
- if(!ut->pFuncs->access(ut, index, FALSE)) {
+ if(!ut->pFuncs->access(ut, index, false)) {
// no chunk available here
return U_SENTINEL;
}
@@ -400,7 +400,7 @@ utext_previous32From(UText *ut, int64_t index) {
ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart);
} else {
ut->chunkOffset=ut->pFuncs->mapNativeIndexToUTF16(ut, index);
- if (ut->chunkOffset==0 && !ut->pFuncs->access(ut, index, FALSE)) {
+ if (ut->chunkOffset==0 && !ut->pFuncs->access(ut, index, false)) {
// no chunk available here
return U_SENTINEL;
}
@@ -438,24 +438,24 @@ utext_equals(const UText *a, const UText *b) {
a->magic != UTEXT_MAGIC ||
b->magic != UTEXT_MAGIC) {
// Null or invalid arguments don't compare equal to anything.
- return FALSE;
+ return false;
}
if (a->pFuncs != b->pFuncs) {
// Different types of text providers.
- return FALSE;
+ return false;
}
if (a->context != b->context) {
// Different sources (different strings)
- return FALSE;
+ return false;
}
if (utext_getNativeIndex(a) != utext_getNativeIndex(b)) {
// Different current position in the string.
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
U_CAPI UBool U_EXPORT2
@@ -987,7 +987,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
// Don't swap buffers, but do set the
// current buffer position.
ut->chunkOffset = ut->chunkLength;
- return FALSE;
+ return false;
} else {
// End of current buffer.
// check whether other buffer already has what we need.
@@ -1016,7 +1016,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
// Current buffer extends up to the end of the string.
// Leave it as the current buffer.
ut->chunkOffset = ut->chunkLength;
- return FALSE;
+ return false;
}
if (ix == u8b->bufNativeLimit) {
// Alternate buffer extends to the end of string.
@@ -1038,7 +1038,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
mapIndex = ix - u8b->toUCharsMapStart;
U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));
ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
- return TRUE;
+ return true;
}
}
@@ -1055,7 +1055,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
// Don't swap buffers, but do set the
// current buffer position.
ut->chunkOffset = 0;
- return FALSE;
+ return false;
} else {
// Start of current buffer.
// check whether other buffer already has what we need.
@@ -1108,9 +1108,9 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
// one of the trailing bytes. Because there is no preceding ,
// character, this access fails. We can't pick up on the
// situation sooner because the requested index is not zero.
- return FALSE;
+ return false;
} else {
- return TRUE;
+ return true;
}
@@ -1139,7 +1139,7 @@ swapBuffers:
U_ASSERT(mapIndex<(int32_t)sizeof(u8b->mapToUChars));
ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
- return TRUE;
+ return true;
}
@@ -1170,7 +1170,7 @@ swapBuffers:
ut->chunkOffset = 0;
U_ASSERT(ix == u8b->bufNativeStart);
}
- return FALSE;
+ return false;
makeStubBuffer:
// The user has done a seek/access past the start or end
@@ -1203,10 +1203,10 @@ fillForward:
ut->p = u8b_swap;
int32_t strLen = ut->b;
- UBool nulTerminated = FALSE;
+ UBool nulTerminated = false;
if (strLen < 0) {
strLen = 0x7fffffff;
- nulTerminated = TRUE;
+ nulTerminated = true;
}
UChar *buf = u8b_swap->buf;
@@ -1214,7 +1214,7 @@ fillForward:
uint8_t *mapToUChars = u8b_swap->mapToUChars;
int32_t destIx = 0;
int32_t srcIx = ix;
- UBool seenNonAscii = FALSE;
+ UBool seenNonAscii = false;
UChar32 c = 0;
// Fill the chunk buffer and mapping arrays.
@@ -1230,8 +1230,8 @@ fillForward:
destIx++;
} else {
// General case, handle everything.
- if (seenNonAscii == FALSE) {
- seenNonAscii = TRUE;
+ if (seenNonAscii == false) {
+ seenNonAscii = true;
u8b_swap->bufNILimit = destIx;
}
@@ -1269,7 +1269,7 @@ fillForward:
u8b_swap->bufNativeLimit = srcIx;
u8b_swap->bufStartIdx = 0;
u8b_swap->bufLimitIdx = destIx;
- if (seenNonAscii == FALSE) {
+ if (seenNonAscii == false) {
u8b_swap->bufNILimit = destIx;
}
u8b_swap->toUCharsMapStart = u8b_swap->bufNativeStart;
@@ -1293,7 +1293,7 @@ fillForward:
ut->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_LENGTH_IS_EXPENSIVE);
}
}
- return TRUE;
+ return true;
}
@@ -1402,7 +1402,7 @@ fillReverse:
ut->chunkNativeStart = u8b_swap->bufNativeStart;
ut->chunkNativeLimit = u8b_swap->bufNativeLimit;
ut->nativeIndexingLimit = u8b_swap->bufNILimit;
- return TRUE;
+ return true;
}
}
@@ -1526,7 +1526,7 @@ utf8TextExtract(UText *ut,
utext_strFromUTF8(dest, destCapacity, &destLength,
(const char *)ut->context+start32, limit32-start32,
pErrorCode);
- utf8TextAccess(ut, limit32, TRUE);
+ utf8TextAccess(ut, limit32, true);
return destLength;
}
@@ -1760,13 +1760,13 @@ repTextAccess(UText *ut, int64_t index, UBool forward) {
if (index32>=ut->chunkNativeStart && index32<ut->chunkNativeLimit) {
// Buffer already contains the requested position.
ut->chunkOffset = (int32_t)(index - ut->chunkNativeStart);
- return TRUE;
+ return true;
}
if (index32>=length && ut->chunkNativeLimit==length) {
// Request for end of string, and buffer already extends up to it.
// Can't get the data, but don't change the buffer.
ut->chunkOffset = length - (int32_t)ut->chunkNativeStart;
- return FALSE;
+ return false;
}
ut->chunkNativeLimit = index + REP_TEXT_CHUNK_SIZE - 1;
@@ -1787,13 +1787,13 @@ repTextAccess(UText *ut, int64_t index, UBool forward) {
if (index32>ut->chunkNativeStart && index32<=ut->chunkNativeLimit) {
// Requested position already in buffer.
ut->chunkOffset = index32 - (int32_t)ut->chunkNativeStart;
- return TRUE;
+ return true;
}
if (index32==0 && ut->chunkNativeStart==0) {
// Request for start, buffer already begins at start.
// No data, but keep the buffer as is.
ut->chunkOffset = 0;
- return FALSE;
+ return false;
}
// Figure out the bounds of the chunk to extract for reverse iteration.
@@ -1849,7 +1849,7 @@ repTextAccess(UText *ut, int64_t index, UBool forward) {
// Use fast indexing for get/setNativeIndex()
ut->nativeIndexingLimit = ut->chunkLength;
- return TRUE;
+ return true;
}
@@ -1892,7 +1892,7 @@ repTextExtract(UText *ut,
}
UnicodeString buffer(dest, 0, destCapacity); // writable alias
rep->extractBetween(start32, limit32, buffer);
- repTextAccess(ut, limit32, TRUE);
+ repTextAccess(ut, limit32, true);
return u_terminateUChars(dest, destCapacity, length, status);
}
@@ -1948,7 +1948,7 @@ repTextReplace(UText *ut,
// set the iteration position to the end of the newly inserted replacement text.
int32_t newIndexPos = limit32 + lengthDelta;
- repTextAccess(ut, newIndexPos, TRUE);
+ repTextAccess(ut, newIndexPos, true);
return lengthDelta;
}
@@ -2012,7 +2012,7 @@ repTextCopy(UText *ut,
}
// Set position, reload chunk if needed.
- repTextAccess(ut, nativeIterIndex, TRUE);
+ repTextAccess(ut, nativeIterIndex, true);
}
static const struct UTextFuncs repFuncs =
@@ -2254,7 +2254,7 @@ unistrTextCopy(UText *ut,
// update chunk description, set iteration position.
ut->chunkContents = us->getBuffer();
- if (move==FALSE) {
+ if (move==false) {
// copy operation, string length grows
ut->chunkLength += limit32-start32;
ut->chunkNativeLimit = ut->chunkLength;
@@ -2525,7 +2525,7 @@ ucstrTextExtract(UText *ut,
// Access the start. Does two things we need:
// Pins 'start' to the length of the string, if it came in out-of-bounds.
// Snaps 'start' to the beginning of a code point.
- ucstrTextAccess(ut, start, TRUE);
+ ucstrTextAccess(ut, start, true);
const UChar *s=ut->chunkContents;
start32 = ut->chunkOffset;
@@ -2579,7 +2579,7 @@ ucstrTextExtract(UText *ut,
if (si <= ut->chunkNativeLimit) {
ut->chunkOffset = si;
} else {
- ucstrTextAccess(ut, si, TRUE);
+ ucstrTextAccess(ut, si, true);
}
// Add a terminating NUL if space in the buffer permits,
@@ -2698,11 +2698,11 @@ charIterTextAccess(UText *ut, int64_t index, UBool forward) {
neededIndex -= neededIndex % CIBufSize;
UChar *buf = NULL;
- UBool needChunkSetup = TRUE;
+ UBool needChunkSetup = true;
int i;
if (ut->chunkNativeStart == neededIndex) {
// The buffer we want is already the current chunk.
- needChunkSetup = FALSE;
+ needChunkSetup = false;
} else if (ut->b == neededIndex) {
// The first buffer (buffer p) has what we need.
buf = (UChar *)ut->p;
@@ -2809,7 +2809,7 @@ charIterTextExtract(UText *ut,
srci += len;
}
- charIterTextAccess(ut, copyLimit, TRUE);
+ charIterTextAccess(ut, copyLimit, true);
u_terminateUChars(dest, destCapacity, desti, status);
return desti;
diff --git a/thirdparty/icu4c/common/utf_impl.cpp b/thirdparty/icu4c/common/utf_impl.cpp
index 9dd241a12b..a1f9c6529a 100644
--- a/thirdparty/icu4c/common/utf_impl.cpp
+++ b/thirdparty/icu4c/common/utf_impl.cpp
@@ -55,7 +55,7 @@
* -finish:
* (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB)
*/
-extern "C" U_EXPORT const uint8_t
+U_CAPI const uint8_t
utf8_countTrailBytes[256]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -117,11 +117,11 @@ errorValue(int32_t count, int8_t strict) {
* Unicode 16-bit strings that are not well-formed UTF-16, that is, they
* contain unpaired surrogates.
* -3: All illegal byte sequences yield U+FFFD.
- * 0 Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ * 0 Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., false):
* All illegal byte sequences yield a positive code point such that this
* result code point would be encoded with the same number of bytes as
* the illegal sequence.
- * >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ * >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., true):
* Same as the obsolete "safe" behavior, but non-characters are also treated
* like illegal sequences.
*
@@ -214,7 +214,7 @@ utf8_appendCharSafeBody(uint8_t *s, int32_t i, int32_t length, UChar32 c, UBool
}
/* c>0x10ffff or not enough space, write an error value */
if(pIsError!=NULL) {
- *pIsError=TRUE;
+ *pIsError=true;
} else {
length-=i;
if(length>0) {
diff --git a/thirdparty/icu4c/common/util.cpp b/thirdparty/icu4c/common/util.cpp
index f342172259..3dcc05578b 100644
--- a/thirdparty/icu4c/common/util.cpp
+++ b/thirdparty/icu4c/common/util.cpp
@@ -214,14 +214,14 @@ int32_t ICU_Utility::skipWhitespace(const UnicodeString& str, int32_t& pos,
*/
UBool ICU_Utility::parseChar(const UnicodeString& id, int32_t& pos, UChar ch) {
int32_t start = pos;
- skipWhitespace(id, pos, TRUE);
+ skipWhitespace(id, pos, true);
if (pos == id.length() ||
id.charAt(pos) != ch) {
pos = start;
- return FALSE;
+ return false;
}
++pos;
- return TRUE;
+ return true;
}
/**
@@ -302,7 +302,7 @@ int32_t ICU_Utility::parseAsciiInteger(const UnicodeString& str, int32_t& pos) {
/**
* Append a character to a rule that is being built up. To flush
- * the quoteBuf to rule, make one final call with isLiteral == TRUE.
+ * the quoteBuf to rule, make one final call with isLiteral == true.
* If there is no final character, pass in (UChar32)-1 as c.
* @param rule the string to append the character to
* @param c the character to append, or (UChar32)-1 if none.
@@ -428,7 +428,7 @@ void ICU_Utility::appendToRule(UnicodeString& rule,
if (matcher != NULL) {
UnicodeString pat;
appendToRule(rule, matcher->toPattern(pat, escapeUnprintable),
- TRUE, escapeUnprintable, quoteBuf);
+ true, escapeUnprintable, quoteBuf);
}
}
diff --git a/thirdparty/icu4c/common/util.h b/thirdparty/icu4c/common/util.h
index 7e6d356899..4a9ae831de 100644
--- a/thirdparty/icu4c/common/util.h
+++ b/thirdparty/icu4c/common/util.h
@@ -258,7 +258,7 @@ class U_COMMON_API ICU_Utility /* not : public UObject because all methods are s
private:
// do not instantiate
- ICU_Utility();
+ ICU_Utility() = delete;
};
U_NAMESPACE_END
diff --git a/thirdparty/icu4c/common/utrace.cpp b/thirdparty/icu4c/common/utrace.cpp
index dfd2062f31..f7b8ade674 100644
--- a/thirdparty/icu4c/common/utrace.cpp
+++ b/thirdparty/icu4c/common/utrace.cpp
@@ -436,7 +436,7 @@ utrace_cleanup() {
pTraceDataFunc = NULL;
utrace_level = UTRACE_OFF;
gTraceContext = NULL;
- return TRUE;
+ return true;
}
diff --git a/thirdparty/icu4c/common/utrie.cpp b/thirdparty/icu4c/common/utrie.cpp
index ecf9b1cba7..96f2397ca1 100644
--- a/thirdparty/icu4c/common/utrie.cpp
+++ b/thirdparty/icu4c/common/utrie.cpp
@@ -72,14 +72,14 @@ utrie_open(UNewTrie *fillIn,
if(aliasData!=NULL) {
trie->data=aliasData;
- trie->isDataAllocated=FALSE;
+ trie->isDataAllocated=false;
} else {
trie->data=(uint32_t *)uprv_malloc(maxDataLength*4);
if(trie->data==NULL) {
uprv_free(trie);
return NULL;
}
- trie->isDataAllocated=TRUE;
+ trie->isDataAllocated=true;
}
/* preallocate and reset the first data block (block index 0) */
@@ -108,7 +108,7 @@ utrie_open(UNewTrie *fillIn,
trie->indexLength=UTRIE_MAX_INDEX_LENGTH;
trie->dataCapacity=maxDataLength;
trie->isLatin1Linear=latin1Linear;
- trie->isCompacted=FALSE;
+ trie->isCompacted=false;
return trie;
}
@@ -124,14 +124,14 @@ utrie_clone(UNewTrie *fillIn, const UNewTrie *other, uint32_t *aliasData, int32_
/* clone data */
if(aliasData!=NULL && aliasDataCapacity>=other->dataCapacity) {
- isDataAllocated=FALSE;
+ isDataAllocated=false;
} else {
aliasDataCapacity=other->dataCapacity;
aliasData=(uint32_t *)uprv_malloc(other->dataCapacity*4);
if(aliasData==NULL) {
return NULL;
}
- isDataAllocated=TRUE;
+ isDataAllocated=true;
}
trie=utrie_open(fillIn, aliasData, aliasDataCapacity,
@@ -216,7 +216,7 @@ utrie_getDataBlock(UNewTrie *trie, UChar32 c) {
}
/**
- * @return TRUE if the value was successfully set
+ * @return true if the value was successfully set
*/
U_CAPI UBool U_EXPORT2
utrie_set32(UNewTrie *trie, UChar32 c, uint32_t value) {
@@ -224,16 +224,16 @@ utrie_set32(UNewTrie *trie, UChar32 c, uint32_t value) {
/* valid, uncompacted trie and valid c? */
if(trie==NULL || trie->isCompacted || (uint32_t)c>0x10ffff) {
- return FALSE;
+ return false;
}
block=utrie_getDataBlock(trie, c);
if(block<0) {
- return FALSE;
+ return false;
}
trie->data[block+(c&UTRIE_MASK)]=value;
- return TRUE;
+ return true;
}
U_CAPI uint32_t U_EXPORT2
@@ -243,7 +243,7 @@ utrie_get32(UNewTrie *trie, UChar32 c, UBool *pInBlockZero) {
/* valid, uncompacted trie and valid c? */
if(trie==NULL || trie->isCompacted || (uint32_t)c>0x10ffff) {
if(pInBlockZero!=NULL) {
- *pInBlockZero=TRUE;
+ *pInBlockZero=true;
}
return 0;
}
@@ -294,10 +294,10 @@ utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, U
if( trie==NULL || trie->isCompacted ||
(uint32_t)start>0x10ffff || (uint32_t)limit>0x110000 || start>limit
) {
- return FALSE;
+ return false;
}
if(start==limit) {
- return TRUE; /* nothing to do */
+ return true; /* nothing to do */
}
initialValue=trie->data[0];
@@ -307,7 +307,7 @@ utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, U
/* set partial block at [start..following block boundary[ */
block=utrie_getDataBlock(trie, start);
if(block<0) {
- return FALSE;
+ return false;
}
nextStart=(start+UTRIE_DATA_BLOCK_LENGTH)&~UTRIE_MASK;
@@ -318,7 +318,7 @@ utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, U
} else {
utrie_fillBlock(trie->data+block, start&UTRIE_MASK, limit&UTRIE_MASK,
value, initialValue, overwrite);
- return TRUE;
+ return true;
}
}
@@ -348,12 +348,12 @@ utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, U
/* create and set and fill the repeatBlock */
repeatBlock=utrie_getDataBlock(trie, start);
if(repeatBlock<0) {
- return FALSE;
+ return false;
}
/* set the negative block number to indicate that it is a repeat block */
trie->index[start>>UTRIE_SHIFT]=-repeatBlock;
- utrie_fillBlock(trie->data+repeatBlock, 0, UTRIE_DATA_BLOCK_LENGTH, value, initialValue, TRUE);
+ utrie_fillBlock(trie->data+repeatBlock, 0, UTRIE_DATA_BLOCK_LENGTH, value, initialValue, true);
}
}
@@ -364,13 +364,13 @@ utrie_setRange32(UNewTrie *trie, UChar32 start, UChar32 limit, uint32_t value, U
/* set partial block at [last block boundary..limit[ */
block=utrie_getDataBlock(trie, start);
if(block<0) {
- return FALSE;
+ return false;
}
utrie_fillBlock(trie->data+block, 0, rest, value, initialValue, overwrite);
}
- return TRUE;
+ return true;
}
static int32_t
@@ -437,7 +437,7 @@ utrie_fold(UNewTrie *trie, UNewTrieGetFoldedValue *getFoldedValue, UErrorCode *p
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return;
}
- utrie_fillBlock(trie->data+block, 0, UTRIE_DATA_BLOCK_LENGTH, trie->leadUnitValue, trie->data[0], TRUE);
+ utrie_fillBlock(trie->data+block, 0, UTRIE_DATA_BLOCK_LENGTH, trie->leadUnitValue, trie->data[0], true);
block=-block; /* negative block number to indicate that it is a repeat block */
}
for(c=(0xd800>>UTRIE_SHIFT); c<(0xdc00>>UTRIE_SHIFT); ++c) {
@@ -579,7 +579,7 @@ _findSameDataBlock(const uint32_t *data, int32_t dataLength,
*
* The compaction
* - removes blocks that are identical with earlier ones
- * - overlaps adjacent blocks as much as possible (if overlap==TRUE)
+ * - overlaps adjacent blocks as much as possible (if overlap==true)
* - moves blocks in steps of the data granularity
* - moves and overlaps blocks that overlap with multiple values in the overlap region
*
@@ -766,15 +766,15 @@ utrie_serialize(UNewTrie *trie, void *dt, int32_t capacity,
/* fold and compact if necessary, also checks that indexLength is within limits */
if(!trie->isCompacted) {
/* compact once without overlap to improve folding */
- utrie_compact(trie, FALSE, pErrorCode);
+ utrie_compact(trie, false, pErrorCode);
/* fold the supplementary part of the index array */
utrie_fold(trie, getFoldedValue, pErrorCode);
/* compact again with overlap for minimum data array length */
- utrie_compact(trie, TRUE, pErrorCode);
+ utrie_compact(trie, true, pErrorCode);
- trie->isCompacted=TRUE;
+ trie->isCompacted=true;
if(U_FAILURE(*pErrorCode)) {
return 0;
}
@@ -966,7 +966,7 @@ utrie_unserializeDummy(UTrie *trie,
return actualLength;
}
- trie->isLatin1Linear=TRUE;
+ trie->isLatin1Linear=true;
trie->initialValue=initialValue;
/* fill the index and data arrays */
diff --git a/thirdparty/icu4c/common/utrie2.cpp b/thirdparty/icu4c/common/utrie2.cpp
index 24ef5782c9..0fb74ba1c3 100644
--- a/thirdparty/icu4c/common/utrie2.cpp
+++ b/thirdparty/icu4c/common/utrie2.cpp
@@ -66,7 +66,7 @@ utrie2_get32(const UTrie2 *trie, UChar32 c) {
} else if((uint32_t)c>0x10ffff) {
return trie->errorValue;
} else {
- return get32(trie->newTrie, c, TRUE);
+ return get32(trie->newTrie, c, true);
}
}
@@ -80,7 +80,7 @@ utrie2_get32FromLeadSurrogateCodeUnit(const UTrie2 *trie, UChar32 c) {
} else if(trie->data32!=NULL) {
return UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, c);
} else {
- return get32(trie->newTrie, c, FALSE);
+ return get32(trie->newTrie, c, false);
}
}
@@ -200,7 +200,7 @@ utrie2_openFromSerialized(UTrie2ValueBits valueBits,
uprv_memcpy(trie, &tempTrie, sizeof(tempTrie));
trie->memory=(uint32_t *)data;
trie->length=actualLength;
- trie->isMemoryOwned=FALSE;
+ trie->isMemoryOwned=false;
#ifdef UTRIE2_DEBUG
trie->name="fromSerialized";
#endif
@@ -279,7 +279,7 @@ utrie2_openDummy(UTrie2ValueBits valueBits,
return 0;
}
trie->length=length;
- trie->isMemoryOwned=TRUE;
+ trie->isMemoryOwned=true;
/* set the UTrie2 fields */
if(valueBits==UTRIE2_16_VALUE_BITS) {
diff --git a/thirdparty/icu4c/common/utrie2.h b/thirdparty/icu4c/common/utrie2.h
index d1e1e15a6e..ace52cce37 100644
--- a/thirdparty/icu4c/common/utrie2.h
+++ b/thirdparty/icu4c/common/utrie2.h
@@ -591,8 +591,8 @@ U_CDECL_END
#ifdef __cplusplus
+#include "unicode/uobject.h"
#include "unicode/utf.h"
-#include "mutex.h"
U_NAMESPACE_BEGIN
diff --git a/thirdparty/icu4c/common/utrie2_builder.cpp b/thirdparty/icu4c/common/utrie2_builder.cpp
index 8de824cc3d..2513332b80 100644
--- a/thirdparty/icu4c/common/utrie2_builder.cpp
+++ b/thirdparty/icu4c/common/utrie2_builder.cpp
@@ -152,7 +152,7 @@ utrie2_open(uint32_t initialValue, uint32_t errorValue, UErrorCode *pErrorCode)
newTrie->errorValue=errorValue;
newTrie->highStart=0x110000;
newTrie->firstFreeBlock=0; /* no free block in the list */
- newTrie->isCompacted=FALSE;
+ newTrie->isCompacted=false;
/*
* preallocate and reset
@@ -317,7 +317,7 @@ utrie2_clone(const UTrie2 *other, UErrorCode *pErrorCode) {
if(other->memory!=NULL) {
trie->memory=uprv_malloc(other->length);
if(trie->memory!=NULL) {
- trie->isMemoryOwned=TRUE;
+ trie->isMemoryOwned=true;
uprv_memcpy(trie->memory, other->memory, other->length);
/* make the clone's pointers point to its own memory */
@@ -357,11 +357,11 @@ copyEnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
if(start==end) {
utrie2_set32(nt->trie, start, value, &nt->errorCode);
} else {
- utrie2_setRange32(nt->trie, start, end, value, TRUE, &nt->errorCode);
+ utrie2_setRange32(nt->trie, start, end, value, true, &nt->errorCode);
}
return U_SUCCESS(nt->errorCode);
} else {
- return TRUE;
+ return true;
}
}
@@ -422,7 +422,7 @@ utrie2_cloneAsThawed(const UTrie2 *other, UErrorCode *pErrorCode) {
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
- context.exclusiveLimit=FALSE;
+ context.exclusiveLimit=false;
context.errorCode=*pErrorCode;
utrie2_enum(other, NULL, copyEnumRange, &context);
*pErrorCode=context.errorCode;
@@ -461,7 +461,7 @@ utrie2_fromUTrie(const UTrie *trie1, uint32_t errorValue, UErrorCode *pErrorCode
if(U_FAILURE(*pErrorCode)) {
return NULL;
}
- context.exclusiveLimit=TRUE;
+ context.exclusiveLimit=true;
context.errorCode=*pErrorCode;
utrie_enum(trie1, NULL, copyEnumRange, &context);
*pErrorCode=context.errorCode;
@@ -649,7 +649,7 @@ getDataBlock(UNewTrie2 *trie, UChar32 c, UBool forLSCP) {
}
/**
- * @return TRUE if the value was successfully set
+ * @return true if the value was successfully set
*/
static void
set32(UNewTrie2 *trie,
@@ -683,7 +683,7 @@ utrie2_set32(UTrie2 *trie, UChar32 c, uint32_t value, UErrorCode *pErrorCode) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- set32(trie->newTrie, c, TRUE, value, pErrorCode);
+ set32(trie->newTrie, c, true, value, pErrorCode);
}
U_CAPI void U_EXPORT2
@@ -697,7 +697,7 @@ utrie2_set32ForLeadSurrogateCodeUnit(UTrie2 *trie,
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- set32(trie->newTrie, c, FALSE, value, pErrorCode);
+ set32(trie->newTrie, c, false, value, pErrorCode);
}
static void
@@ -709,7 +709,7 @@ writeBlock(uint32_t *block, uint32_t value) {
}
/**
- * initialValue is ignored if overwrite=TRUE
+ * initialValue is ignored if overwrite=true
* @internal
*/
static void
@@ -771,7 +771,7 @@ utrie2_setRange32(UTrie2 *trie,
UChar32 nextStart;
/* set partial block at [start..following block boundary[ */
- block=getDataBlock(newTrie, start, TRUE);
+ block=getDataBlock(newTrie, start, true);
if(block<0) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return;
@@ -804,15 +804,15 @@ utrie2_setRange32(UTrie2 *trie,
while(start<limit) {
int32_t i2;
- UBool setRepeatBlock=FALSE;
+ UBool setRepeatBlock=false;
- if(value==newTrie->initialValue && isInNullBlock(newTrie, start, TRUE)) {
+ if(value==newTrie->initialValue && isInNullBlock(newTrie, start, true)) {
start+=UTRIE2_DATA_BLOCK_LENGTH; /* nothing to do */
continue;
}
/* get index value */
- i2=getIndex2Block(newTrie, start, TRUE);
+ i2=getIndex2Block(newTrie, start, true);
if(i2<0) {
*pErrorCode=U_INTERNAL_PROGRAM_ERROR;
return;
@@ -827,7 +827,7 @@ utrie2_setRange32(UTrie2 *trie,
* protected (ASCII-linear or 2-byte UTF-8) block:
* replace with the repeatBlock.
*/
- setRepeatBlock=TRUE;
+ setRepeatBlock=true;
} else {
/* !overwrite, or protected block: just write the values into this block */
fillBlock(newTrie->data+block,
@@ -851,14 +851,14 @@ utrie2_setRange32(UTrie2 *trie,
* and if we overwrite any data or if the data is all initial values
* (which is the same as the block being the null block, see above).
*/
- setRepeatBlock=TRUE;
+ setRepeatBlock=true;
}
if(setRepeatBlock) {
if(repeatBlock>=0) {
setIndex2Entry(newTrie, i2, repeatBlock);
} else {
/* create and set and fill the repeatBlock */
- repeatBlock=getDataBlock(newTrie, start, TRUE);
+ repeatBlock=getDataBlock(newTrie, start, true);
if(repeatBlock<0) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return;
@@ -872,7 +872,7 @@ utrie2_setRange32(UTrie2 *trie,
if(rest>0) {
/* set partial block at [last block boundary..limit[ */
- block=getDataBlock(newTrie, start, TRUE);
+ block=getDataBlock(newTrie, start, true);
if(block<0) {
*pErrorCode=U_MEMORY_ALLOCATION_ERROR;
return;
@@ -1019,7 +1019,7 @@ findHighStart(UNewTrie2 *trie, uint32_t highValue) {
*
* The compaction
* - removes blocks that are identical with earlier ones
- * - overlaps adjacent blocks as much as possible (if overlap==TRUE)
+ * - overlaps adjacent blocks as much as possible (if overlap==true)
* - moves blocks in steps of the data granularity
* - moves and overlaps blocks that overlap with multiple values in the overlap region
*
@@ -1255,7 +1255,7 @@ compactTrie(UTrie2 *trie, UErrorCode *pErrorCode) {
if(highStart<0x110000) {
/* Blank out [highStart..10ffff] to release associated data blocks. */
suppHighStart= highStart<=0x10000 ? 0x10000 : highStart;
- utrie2_setRange32(trie, suppHighStart, 0x10ffff, trie->initialValue, TRUE, pErrorCode);
+ utrie2_setRange32(trie, suppHighStart, 0x10ffff, trie->initialValue, true, pErrorCode);
if(U_FAILURE(*pErrorCode)) {
return;
}
@@ -1281,7 +1281,7 @@ compactTrie(UTrie2 *trie, UErrorCode *pErrorCode) {
newTrie->data[newTrie->dataLength++]=trie->initialValue;
}
- newTrie->isCompacted=TRUE;
+ newTrie->isCompacted=true;
}
/* serialization ------------------------------------------------------------ */
@@ -1382,7 +1382,7 @@ utrie2_freeze(UTrie2 *trie, UTrie2ValueBits valueBits, UErrorCode *pErrorCode) {
return;
}
trie->length=length;
- trie->isMemoryOwned=TRUE;
+ trie->isMemoryOwned=true;
trie->indexLength=allIndexesLength;
trie->dataLength=newTrie->dataLength;
diff --git a/thirdparty/icu4c/common/utrie_swap.cpp b/thirdparty/icu4c/common/utrie_swap.cpp
index 6e8b138394..b01b94601e 100644
--- a/thirdparty/icu4c/common/utrie_swap.cpp
+++ b/thirdparty/icu4c/common/utrie_swap.cpp
@@ -294,8 +294,8 @@ namespace {
* @param data a pointer to 32-bit-aligned memory containing the serialized form of a trie
* @param length the number of bytes available at data;
* can be more than necessary (see return value)
- * @param anyEndianOk If FALSE, only platform-endian serialized forms are recognized.
- * If TRUE, opposite-endian serialized forms are recognized as well.
+ * @param anyEndianOk If false, only platform-endian serialized forms are recognized.
+ * If true, opposite-endian serialized forms are recognized as well.
* @return the trie version of the serialized form, or 0 if it is not
* recognized as a serialized trie
*/
@@ -334,7 +334,7 @@ utrie_swapAnyVersion(const UDataSwapper *ds,
const void *inData, int32_t length, void *outData,
UErrorCode *pErrorCode) {
if(U_FAILURE(*pErrorCode)) { return 0; }
- switch(getVersion(inData, length, TRUE)) {
+ switch(getVersion(inData, length, true)) {
case 1:
return utrie_swap(ds, inData, length, outData, pErrorCode);
case 2:
diff --git a/thirdparty/icu4c/common/uts46.cpp b/thirdparty/icu4c/common/uts46.cpp
index 6f93070339..10a4f56597 100644
--- a/thirdparty/icu4c/common/uts46.cpp
+++ b/thirdparty/icu4c/common/uts46.cpp
@@ -53,10 +53,10 @@ isASCIIString(const UnicodeString &dest) {
const UChar *limit=s+dest.length();
while(s<limit) {
if(*s++>0x7f) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
static UBool
@@ -224,19 +224,19 @@ UTS46::~UTS46() {}
UnicodeString &
UTS46::labelToASCII(const UnicodeString &label, UnicodeString &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- return process(label, TRUE, TRUE, dest, info, errorCode);
+ return process(label, true, true, dest, info, errorCode);
}
UnicodeString &
UTS46::labelToUnicode(const UnicodeString &label, UnicodeString &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- return process(label, TRUE, FALSE, dest, info, errorCode);
+ return process(label, true, false, dest, info, errorCode);
}
UnicodeString &
UTS46::nameToASCII(const UnicodeString &name, UnicodeString &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- process(name, FALSE, TRUE, dest, info, errorCode);
+ process(name, false, true, dest, info, errorCode);
if( dest.length()>=254 && (info.errors&UIDNA_ERROR_DOMAIN_NAME_TOO_LONG)==0 &&
isASCIIString(dest) &&
(dest.length()>254 || dest[253]!=0x2e)
@@ -249,31 +249,31 @@ UTS46::nameToASCII(const UnicodeString &name, UnicodeString &dest,
UnicodeString &
UTS46::nameToUnicode(const UnicodeString &name, UnicodeString &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- return process(name, FALSE, FALSE, dest, info, errorCode);
+ return process(name, false, false, dest, info, errorCode);
}
void
UTS46::labelToASCII_UTF8(StringPiece label, ByteSink &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- processUTF8(label, TRUE, TRUE, dest, info, errorCode);
+ processUTF8(label, true, true, dest, info, errorCode);
}
void
UTS46::labelToUnicodeUTF8(StringPiece label, ByteSink &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- processUTF8(label, TRUE, FALSE, dest, info, errorCode);
+ processUTF8(label, true, false, dest, info, errorCode);
}
void
UTS46::nameToASCII_UTF8(StringPiece name, ByteSink &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- processUTF8(name, FALSE, TRUE, dest, info, errorCode);
+ processUTF8(name, false, true, dest, info, errorCode);
}
void
UTS46::nameToUnicodeUTF8(StringPiece name, ByteSink &dest,
IDNAInfo &info, UErrorCode &errorCode) const {
- processUTF8(name, FALSE, FALSE, dest, info, errorCode);
+ processUTF8(name, false, false, dest, info, errorCode);
}
// UTS #46 data for ASCII characters.
@@ -561,7 +561,7 @@ UTS46::processUnicode(const UnicodeString &src,
} else if(c<0xdf) {
// pass
} else if(c<=0x200d && (c==0xdf || c==0x3c2 || c>=0x200c)) {
- info.isTransDiff=TRUE;
+ info.isTransDiff=true;
if(doMapDevChars) {
destLength=mapDevChars(dest, labelStart, labelLimit, errorCode);
if(U_FAILURE(errorCode)) {
@@ -569,7 +569,7 @@ UTS46::processUnicode(const UnicodeString &src,
}
destArray=dest.getBuffer();
// All deviation characters have been mapped, no need to check for them again.
- doMapDevChars=FALSE;
+ doMapDevChars=false;
// Do not increment labelLimit in case c was removed.
continue;
}
@@ -610,14 +610,14 @@ UTS46::mapDevChars(UnicodeString &dest, int32_t labelStart, int32_t mappingStart
return length;
}
int32_t capacity=dest.getCapacity();
- UBool didMapDevChars=FALSE;
+ UBool didMapDevChars=false;
int32_t readIndex=mappingStart, writeIndex=mappingStart;
do {
UChar c=s[readIndex++];
switch(c) {
case 0xdf:
// Map sharp s to ss.
- didMapDevChars=TRUE;
+ didMapDevChars=true;
s[writeIndex++]=0x73; // Replace sharp s with first s.
// Insert second s and account for possible buffer reallocation.
if(writeIndex==readIndex) {
@@ -637,12 +637,12 @@ UTS46::mapDevChars(UnicodeString &dest, int32_t labelStart, int32_t mappingStart
++length;
break;
case 0x3c2: // Map final sigma to nonfinal sigma.
- didMapDevChars=TRUE;
+ didMapDevChars=true;
s[writeIndex++]=0x3c3;
break;
case 0x200c: // Ignore/remove ZWNJ.
case 0x200d: // Ignore/remove ZWJ.
- didMapDevChars=TRUE;
+ didMapDevChars=true;
--length;
break;
default:
@@ -724,7 +724,7 @@ UTS46::processLabel(UnicodeString &dest,
info.labelErrors|=UIDNA_ERROR_INVALID_ACE_LABEL;
return markBadACELabel(dest, labelStart, labelLength, toASCII, info, errorCode);
}
- wasPunycode=TRUE;
+ wasPunycode=true;
UChar *unicodeBuffer=fromPunycode.getBuffer(-1); // capacity==-1: most labels should fit
if(unicodeBuffer==NULL) {
// Should never occur if we used capacity==-1 which uses the internal buffer.
@@ -772,7 +772,7 @@ UTS46::processLabel(UnicodeString &dest,
labelStart=0;
labelLength=fromPunycode.length();
} else {
- wasPunycode=FALSE;
+ wasPunycode=false;
labelString=&dest;
}
// Validity check
@@ -932,8 +932,8 @@ UTS46::markBadACELabel(UnicodeString &dest,
return 0;
}
UBool disallowNonLDHDot=(options&UIDNA_USE_STD3_RULES)!=0;
- UBool isASCII=TRUE;
- UBool onlyLDH=TRUE;
+ UBool isASCII=true;
+ UBool onlyLDH=true;
const UChar *label=dest.getBuffer()+labelStart;
const UChar *limit=label+labelLength;
// Start after the initial "xn--".
@@ -944,16 +944,16 @@ UTS46::markBadACELabel(UnicodeString &dest,
if(c==0x2e) {
info.labelErrors|=UIDNA_ERROR_LABEL_HAS_DOT;
*s=0xfffd;
- isASCII=onlyLDH=FALSE;
+ isASCII=onlyLDH=false;
} else if(asciiData[c]<0) {
- onlyLDH=FALSE;
+ onlyLDH=false;
if(disallowNonLDHDot) {
*s=0xfffd;
- isASCII=FALSE;
+ isASCII=false;
}
}
} else {
- isASCII=onlyLDH=FALSE;
+ isASCII=onlyLDH=false;
}
}
if(onlyLDH) {
@@ -1008,7 +1008,7 @@ UTS46::checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) c
// or AL. If it has the R or AL property, it is an RTL label; if it
// has the L property, it is an LTR label.
if((firstMask&~L_R_AL_MASK)!=0) {
- info.isOkBiDi=FALSE;
+ info.isOkBiDi=false;
}
// Get the directionality of the last non-NSM character.
uint32_t lastMask;
@@ -1034,7 +1034,7 @@ UTS46::checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) c
(lastMask&~L_EN_MASK)!=0 :
(lastMask&~R_AL_EN_AN_MASK)!=0
) {
- info.isOkBiDi=FALSE;
+ info.isOkBiDi=false;
}
// Add the directionalities of the intervening characters.
uint32_t mask=firstMask|lastMask;
@@ -1046,18 +1046,18 @@ UTS46::checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) c
// 5. In an LTR label, only characters with the BIDI properties L, EN,
// ES, CS, ET, ON, BN and NSM are allowed.
if((mask&~L_EN_ES_CS_ET_ON_BN_NSM_MASK)!=0) {
- info.isOkBiDi=FALSE;
+ info.isOkBiDi=false;
}
} else {
// 2. In an RTL label, only characters with the BIDI properties R, AL,
// AN, EN, ES, CS, ET, ON, BN and NSM are allowed.
if((mask&~R_AL_AN_EN_ES_CS_ET_ON_BN_NSM_MASK)!=0) {
- info.isOkBiDi=FALSE;
+ info.isOkBiDi=false;
}
// 4. In an RTL label, if an EN is present, no AN may be present, and
// vice versa.
if((mask&EN_AN_MASK)==EN_AN_MASK) {
- info.isOkBiDi=FALSE;
+ info.isOkBiDi=false;
}
}
// An RTL label is a label that contains at least one character of type
@@ -1067,7 +1067,7 @@ UTS46::checkLabelBiDi(const UChar *label, int32_t labelLength, IDNAInfo &info) c
// The following rule, consisting of six conditions, applies to labels
// in BIDI domain names.
if((mask&R_AL_AN_MASK)!=0) {
- info.isBiDi=TRUE;
+ info.isBiDi=true;
}
}
@@ -1094,23 +1094,23 @@ isASCIIOkBiDi(const UChar *s, int32_t length) {
c=s[i-1];
if(!(0x61<=c && c<=0x7a) && !(0x30<=c && c<=0x39)) {
// Last character in the label is not an L or EN.
- return FALSE;
+ return false;
}
}
labelStart=i+1;
} else if(i==labelStart) {
if(!(0x61<=c && c<=0x7a)) {
// First character in the label is not an L.
- return FALSE;
+ return false;
}
} else {
if(c<=0x20 && (c>=0x1c || (9<=c && c<=0xd))) {
// Intermediate character in the label is a B, S or WS.
- return FALSE;
+ return false;
}
}
}
- return TRUE;
+ return true;
}
// UTF-8 version, called for source ASCII prefix.
@@ -1126,23 +1126,23 @@ isASCIIOkBiDi(const char *s, int32_t length) {
c=s[i-1];
if(!(0x61<=c && c<=0x7a) && !(0x41<=c && c<=0x5a) && !(0x30<=c && c<=0x39)) {
// Last character in the label is not an L or EN.
- return FALSE;
+ return false;
}
}
labelStart=i+1;
} else if(i==labelStart) {
if(!(0x61<=c && c<=0x7a) && !(0x41<=c && c<=0x5a)) {
// First character in the label is not an L.
- return FALSE;
+ return false;
}
} else {
if(c<=0x20 && (c>=0x1c || (9<=c && c<=0xd))) {
// Intermediate character in the label is a B, S or WS.
- return FALSE;
+ return false;
}
}
}
- return TRUE;
+ return true;
}
UBool
@@ -1158,7 +1158,7 @@ UTS46::isLabelOkContextJ(const UChar *label, int32_t labelLength) const {
// If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C
// (Joining_Type:T)*(Joining_Type:{R,D})) Then True;
if(i==0) {
- return FALSE;
+ return false;
}
UChar32 c;
int32_t j=i;
@@ -1171,19 +1171,19 @@ UTS46::isLabelOkContextJ(const UChar *label, int32_t labelLength) const {
UJoiningType type=ubidi_getJoiningType(c);
if(type==U_JT_TRANSPARENT) {
if(j==0) {
- return FALSE;
+ return false;
}
U16_PREV_UNSAFE(label, j, c);
} else if(type==U_JT_LEFT_JOINING || type==U_JT_DUAL_JOINING) {
break; // precontext fulfilled
} else {
- return FALSE;
+ return false;
}
}
// check postcontext (Joining_Type:T)*(Joining_Type:{R,D})
for(j=i+1;;) {
if(j==labelLength) {
- return FALSE;
+ return false;
}
U16_NEXT_UNSAFE(label, j, c);
UJoiningType type=ubidi_getJoiningType(c);
@@ -1192,7 +1192,7 @@ UTS46::isLabelOkContextJ(const UChar *label, int32_t labelLength) const {
} else if(type==U_JT_RIGHT_JOINING || type==U_JT_DUAL_JOINING) {
break; // postcontext fulfilled
} else {
- return FALSE;
+ return false;
}
}
} else if(label[i]==0x200d) {
@@ -1201,17 +1201,17 @@ UTS46::isLabelOkContextJ(const UChar *label, int32_t labelLength) const {
// False;
// If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True;
if(i==0) {
- return FALSE;
+ return false;
}
UChar32 c;
int32_t j=i;
U16_PREV_UNSAFE(label, j, c);
if(uts46Norm2.getCombiningClass(c)!=9) {
- return FALSE;
+ return false;
}
}
}
- return TRUE;
+ return true;
}
void
@@ -1338,23 +1338,23 @@ checkArgs(const void *label, int32_t length,
void *dest, int32_t capacity,
UIDNAInfo *pInfo, UErrorCode *pErrorCode) {
if(U_FAILURE(*pErrorCode)) {
- return FALSE;
+ return false;
}
// sizeof(UIDNAInfo)=16 in the first API version.
if(pInfo==NULL || pInfo->size<16) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
if( (label==NULL ? length!=0 : length<-1) ||
(dest==NULL ? capacity!=0 : capacity<0) ||
(dest==label && label!=NULL)
) {
*pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
// Set all *pInfo bytes to 0 except for the size field itself.
uprv_memset(&pInfo->size+1, 0, pInfo->size-sizeof(pInfo->size));
- return TRUE;
+ return true;
}
static void
diff --git a/thirdparty/icu4c/common/uvector.cpp b/thirdparty/icu4c/common/uvector.cpp
index 844463921e..729314ae95 100644
--- a/thirdparty/icu4c/common/uvector.cpp
+++ b/thirdparty/icu4c/common/uvector.cpp
@@ -193,40 +193,40 @@ int32_t UVector::elementAti(int32_t index) const {
UBool UVector::containsAll(const UVector& other) const {
for (int32_t i=0; i<other.size(); ++i) {
if (indexOf(other.elements[i]) < 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
UBool UVector::containsNone(const UVector& other) const {
for (int32_t i=0; i<other.size(); ++i) {
if (indexOf(other.elements[i]) >= 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
UBool UVector::removeAll(const UVector& other) {
- UBool changed = FALSE;
+ UBool changed = false;
for (int32_t i=0; i<other.size(); ++i) {
int32_t j = indexOf(other.elements[i]);
if (j >= 0) {
removeElementAt(j);
- changed = TRUE;
+ changed = true;
}
}
return changed;
}
UBool UVector::retainAll(const UVector& other) {
- UBool changed = FALSE;
+ UBool changed = false;
for (int32_t j=size()-1; j>=0; --j) {
int32_t i = other.indexOf(elements[j]);
if (i < 0) {
removeElementAt(j);
- changed = TRUE;
+ changed = true;
}
}
return changed;
@@ -243,9 +243,9 @@ UBool UVector::removeElement(void* obj) {
int32_t i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
void UVector::removeAllElements(void) {
@@ -263,12 +263,12 @@ UBool UVector::equals(const UVector &other) const {
int i;
if (this->count != other.count) {
- return FALSE;
+ return false;
}
if (comparer == nullptr) {
for (i=0; i<count; i++) {
if (elements[i].pointer != other.elements[i].pointer) {
- return FALSE;
+ return false;
}
}
} else {
@@ -276,11 +276,11 @@ UBool UVector::equals(const UVector &other) const {
for (i=0; i<count; i++) {
key.pointer = &other.elements[i];
if (!(*comparer)(key, elements[i])) {
- return FALSE;
+ return false;
}
}
}
- return TRUE;
+ return true;
}
@@ -525,7 +525,7 @@ sortiComparator(const void * /*context */, const void *left, const void *right)
void UVector::sorti(UErrorCode &ec) {
if (U_SUCCESS(ec)) {
uprv_sortArray(elements, count, sizeof(UElement),
- sortiComparator, nullptr, FALSE, &ec);
+ sortiComparator, nullptr, false, &ec);
}
}
@@ -547,7 +547,7 @@ void UVector::sorti(UErrorCode &ec) {
void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
if (U_SUCCESS(ec)) {
uprv_sortArray(elements, count, sizeof(UElement),
- sortComparator, &compare, FALSE, &ec);
+ sortComparator, &compare, false, &ec);
}
}
@@ -558,7 +558,7 @@ void UVector::sort(UElementComparator *compare, UErrorCode &ec) {
void UVector::sortWithUComparator(UComparator *compare, const void *context, UErrorCode &ec) {
if (U_SUCCESS(ec)) {
uprv_sortArray(elements, count, sizeof(UElement),
- compare, context, TRUE, &ec);
+ compare, context, true, &ec);
}
}
diff --git a/thirdparty/icu4c/common/uvectr32.cpp b/thirdparty/icu4c/common/uvectr32.cpp
index 2b4d0b8a75..952f51792b 100644
--- a/thirdparty/icu4c/common/uvectr32.cpp
+++ b/thirdparty/icu4c/common/uvectr32.cpp
@@ -117,40 +117,40 @@ void UVector32::insertElementAt(int32_t elem, int32_t index, UErrorCode &status)
UBool UVector32::containsAll(const UVector32& other) const {
for (int32_t i=0; i<other.size(); ++i) {
if (indexOf(other.elements[i]) < 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
UBool UVector32::containsNone(const UVector32& other) const {
for (int32_t i=0; i<other.size(); ++i) {
if (indexOf(other.elements[i]) >= 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
UBool UVector32::removeAll(const UVector32& other) {
- UBool changed = FALSE;
+ UBool changed = false;
for (int32_t i=0; i<other.size(); ++i) {
int32_t j = indexOf(other.elements[i]);
if (j >= 0) {
removeElementAt(j);
- changed = TRUE;
+ changed = true;
}
}
return changed;
}
UBool UVector32::retainAll(const UVector32& other) {
- UBool changed = FALSE;
+ UBool changed = false;
for (int32_t j=size()-1; j>=0; --j) {
int32_t i = other.indexOf(elements[j]);
if (i < 0) {
removeElementAt(j);
- changed = TRUE;
+ changed = true;
}
}
return changed;
@@ -173,14 +173,14 @@ UBool UVector32::equals(const UVector32 &other) const {
int i;
if (this->count != other.count) {
- return FALSE;
+ return false;
}
for (i=0; i<count; i++) {
if (elements[i] != other.elements[i]) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
@@ -199,22 +199,22 @@ int32_t UVector32::indexOf(int32_t key, int32_t startIndex) const {
UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
if (minimumCapacity < 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
if (capacity >= minimumCapacity) {
- return TRUE;
+ return true;
}
if (maxCapacity>0 && minimumCapacity>maxCapacity) {
status = U_BUFFER_OVERFLOW_ERROR;
- return FALSE;
+ return false;
}
if (capacity > (INT32_MAX - 1) / 2) { // integer overflow check
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
int32_t newCap = capacity * 2;
if (newCap < minimumCapacity) {
@@ -226,17 +226,17 @@ UBool UVector32::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
if (newCap > (int32_t)(INT32_MAX / sizeof(int32_t))) { // integer overflow check
// We keep the original memory contents on bad minimumCapacity/maxCapacity.
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
int32_t* newElems = (int32_t *)uprv_realloc(elements, sizeof(int32_t)*newCap);
if (newElems == NULL) {
// We keep the original contents on the memory failure on realloc.
status = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
elements = newElems;
capacity = newCap;
- return TRUE;
+ return true;
}
void UVector32::setMaxCapacity(int32_t limit) {
diff --git a/thirdparty/icu4c/common/uvectr32.h b/thirdparty/icu4c/common/uvectr32.h
index ecefb7af3e..a7fada3833 100644
--- a/thirdparty/icu4c/common/uvectr32.h
+++ b/thirdparty/icu4c/common/uvectr32.h
@@ -187,10 +187,10 @@ private:
void _init(int32_t initialCapacity, UErrorCode &status);
// Disallow
- UVector32(const UVector32&);
+ UVector32(const UVector32&) = delete;
// Disallow
- UVector32& operator=(const UVector32&);
+ UVector32& operator=(const UVector32&) = delete;
// API Functions for Stack operations.
diff --git a/thirdparty/icu4c/common/uvectr64.cpp b/thirdparty/icu4c/common/uvectr64.cpp
index 57315c00ff..8bd5cd7839 100644
--- a/thirdparty/icu4c/common/uvectr64.cpp
+++ b/thirdparty/icu4c/common/uvectr64.cpp
@@ -117,22 +117,22 @@ void UVector64::removeAllElements(void) {
UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
if (minimumCapacity < 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
if (capacity >= minimumCapacity) {
- return TRUE;
+ return true;
}
if (maxCapacity>0 && minimumCapacity>maxCapacity) {
status = U_BUFFER_OVERFLOW_ERROR;
- return FALSE;
+ return false;
}
if (capacity > (INT32_MAX - 1) / 2) { // integer overflow check
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
int32_t newCap = capacity * 2;
if (newCap < minimumCapacity) {
@@ -144,17 +144,17 @@ UBool UVector64::expandCapacity(int32_t minimumCapacity, UErrorCode &status) {
if (newCap > (int32_t)(INT32_MAX / sizeof(int64_t))) { // integer overflow check
// We keep the original memory contents on bad minimumCapacity/maxCapacity.
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
int64_t* newElems = (int64_t *)uprv_realloc(elements, sizeof(int64_t)*newCap);
if (newElems == NULL) {
// We keep the original contents on the memory failure on realloc.
status = U_MEMORY_ALLOCATION_ERROR;
- return FALSE;
+ return false;
}
elements = newElems;
capacity = newCap;
- return TRUE;
+ return true;
}
void UVector64::setMaxCapacity(int32_t limit) {
diff --git a/thirdparty/icu4c/common/uvectr64.h b/thirdparty/icu4c/common/uvectr64.h
index ba3eca268d..070e2dd67d 100644
--- a/thirdparty/icu4c/common/uvectr64.h
+++ b/thirdparty/icu4c/common/uvectr64.h
@@ -176,10 +176,10 @@ private:
void _init(int32_t initialCapacity, UErrorCode &status);
// Disallow
- UVector64(const UVector64&);
+ UVector64(const UVector64&) = delete;
// Disallow
- UVector64& operator=(const UVector64&);
+ UVector64& operator=(const UVector64&) = delete;
// API Functions for Stack operations.
diff --git a/thirdparty/icu4c/common/wintz.cpp b/thirdparty/icu4c/common/wintz.cpp
index 84a29b8d36..1bc08ae654 100644
--- a/thirdparty/icu4c/common/wintz.cpp
+++ b/thirdparty/icu4c/common/wintz.cpp
@@ -274,7 +274,7 @@ uprv_detectWindowsTimeZone()
CharString winTZ;
UErrorCode status = U_ZERO_ERROR;
- winTZ.appendInvariantChars(UnicodeString(TRUE, windowsTimeZoneName, -1), status);
+ winTZ.appendInvariantChars(UnicodeString(true, windowsTimeZoneName, -1), status);
// Map Windows Timezone name (non-localized) to ICU timezone ID (~ Olson timezone id).
StackUResourceBundle winTZBundle;
diff --git a/thirdparty/icu4c/i18n/scriptset.cpp b/thirdparty/icu4c/i18n/scriptset.cpp
index 6a1db8c01c..236bf9d37f 100644
--- a/thirdparty/icu4c/i18n/scriptset.cpp
+++ b/thirdparty/icu4c/i18n/scriptset.cpp
@@ -55,11 +55,11 @@ bool ScriptSet::operator == (const ScriptSet &other) const {
UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
if (U_FAILURE(status)) {
- return FALSE;
+ return false;
}
if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
status = U_ILLEGAL_ARGUMENT_ERROR;
- return FALSE;
+ return false;
}
uint32_t index = script / 32;
uint32_t bit = 1 << (script & 31);
@@ -188,19 +188,19 @@ int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
UBool ScriptSet::isEmpty() const {
for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
if (bits[i] != 0) {
- return FALSE;
+ return false;
}
}
- return TRUE;
+ return true;
}
UnicodeString &ScriptSet::displayScripts(UnicodeString &dest) const {
- UBool firstTime = TRUE;
+ UBool firstTime = true;
for (int32_t i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
if (!firstTime) {
dest.append((UChar)0x20);
}
- firstTime = FALSE;
+ firstTime = false;
const char *scriptName = uscript_getShortName((UScriptCode(i)));
dest.append(UnicodeString(scriptName, -1, US_INV));
}
@@ -248,7 +248,7 @@ void ScriptSet::setScriptExtensions(UChar32 codePoint, UErrorCode& status) {
UErrorCode internalStatus = U_ZERO_ERROR;
int32_t script_count = -1;
- while (TRUE) {
+ while (true) {
script_count = uscript_getScriptExtensions(
codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
if (internalStatus == U_BUFFER_OVERFLOW_ERROR) {
diff --git a/thirdparty/icu4c/i18n/scriptset.h b/thirdparty/icu4c/i18n/scriptset.h
index 51980ab7b3..df5cfdc748 100644
--- a/thirdparty/icu4c/i18n/scriptset.h
+++ b/thirdparty/icu4c/i18n/scriptset.h
@@ -83,4 +83,7 @@ uhash_hashScriptSet(const UElement key);
U_CAPI void U_EXPORT2
uhash_deleteScriptSet(void *obj);
-#endif // __SCRIPTSET_H__
+U_CAPI UBool U_EXPORT2
+uhash_equalsScriptSet(const UElement key1, const UElement key2);
+
+#endif // __SCRIPTSET_H_
diff --git a/thirdparty/icu4c/i18n/ucln_in.cpp b/thirdparty/icu4c/i18n/ucln_in.cpp
index f29cbe41dd..cdbd16a65e 100644
--- a/thirdparty/icu4c/i18n/ucln_in.cpp
+++ b/thirdparty/icu4c/i18n/ucln_in.cpp
@@ -45,7 +45,7 @@ static UBool U_CALLCONV i18n_cleanup(void)
#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
ucln_unRegisterAutomaticCleanup();
#endif
- return TRUE;
+ return true;
}
void ucln_i18n_registerCleanup(ECleanupI18NType type,
diff --git a/thirdparty/icu4c/i18n/unicode/uspoof.h b/thirdparty/icu4c/i18n/unicode/uspoof.h
index b674c91b2c..0aa887b706 100644
--- a/thirdparty/icu4c/i18n/unicode/uspoof.h
+++ b/thirdparty/icu4c/i18n/unicode/uspoof.h
@@ -35,7 +35,7 @@
/**
* \file
- * \brief Unicode Security and Spoofing Detection, C API.
+ * \brief C API: Unicode Security and Spoofing Detection
*
* <p>
* This class, based on <a href="http://unicode.org/reports/tr36">Unicode Technical Report #36</a> and
diff --git a/thirdparty/icu4c/i18n/uspoof.cpp b/thirdparty/icu4c/i18n/uspoof.cpp
index dd4618baa7..f894dc44ca 100644
--- a/thirdparty/icu4c/i18n/uspoof.cpp
+++ b/thirdparty/icu4c/i18n/uspoof.cpp
@@ -41,7 +41,7 @@ U_NAMESPACE_USE
static UnicodeSet *gInclusionSet = NULL;
static UnicodeSet *gRecommendedSet = NULL;
static const Normalizer2 *gNfdNormalizer = NULL;
-static UInitOnce gSpoofInitStaticsOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gSpoofInitStaticsOnce {};
namespace {
@@ -53,13 +53,13 @@ uspoof_cleanup(void) {
gRecommendedSet = NULL;
gNfdNormalizer = NULL;
gSpoofInitStaticsOnce.reset();
- return TRUE;
+ return true;
}
void U_CALLCONV initializeStatics(UErrorCode &status) {
static const char16_t *inclusionPat =
- u"['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u200C"
- u"\\u200D\\u2010\\u2019\\u2027\\u30A0\\u30FB]";
+ u"['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u2010"
+ u"\\u2019\\u2027\\u30A0\\u30FB]";
gInclusionSet = new UnicodeSet(UnicodeString(inclusionPat), status);
if (gInclusionSet == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -103,14 +103,14 @@ void U_CALLCONV initializeStatics(UErrorCode &status) {
u"\\u0C56\\u0C5D\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-"
u"\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-"
u"\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDD\\u0CE0-\\u0CE3"
- u"\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02\\u0D03\\u0D05-\\u0D0C\\u0D0E-"
+ u"\\u0CE6-\\u0CEF\\u0CF1-\\u0CF3\\u0D00\\u0D02\\u0D03\\u0D05-\\u0D0C\\u0D0E-"
u"\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-"
u"\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-"
u"\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD"
u"\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDE\\u0DF2\\u0E01-"
u"\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84"
u"\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB2\\u0EB4-\\u0EBD\\u0EC0-"
- u"\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00\\u0F20-"
+ u"\\u0EC4\\u0EC6\\u0EC8-\\u0ECE\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00\\u0F20-"
u"\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-\\u0F47\\u0F49-\\u0F4C\\u0F4E-"
u"\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-\\u0F68\\u0F6A-\\u0F6C\\u0F71"
u"\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84\\u0F86-\\u0F92\\u0F94-\\u0F97"
@@ -131,17 +131,18 @@ void U_CALLCONV initializeStatics(UErrorCode &status) {
u"\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3005-"
u"\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E\\u30A1-\\u30FA\\u30FC-"
u"\\u30FE\\u3105-\\u312D\\u312F\\u31A0-\\u31BF\\u3400-\\u4DBF\\u4E00-\\u9FFF"
- u"\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793\\uA7AA\\uA7AE\\uA7B8"
- u"\\uA7B9\\uA7C0-\\uA7CA\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA9E7-\\uA9FE"
- u"\\uAA60-\\uAA76\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16"
- u"\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F"
- u"\\uFA11\\uFA13\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301"
- u"\\U00011303\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B11F-"
- u"\\U0001B122\\U0001B150-\\U0001B152\\U0001B164-\\U0001B167\\U0001DF00-"
- u"\\U0001DF1E\\U0001E7E0-\\U0001E7E6\\U0001E7E8-\\U0001E7EB\\U0001E7ED"
- u"\\U0001E7EE\\U0001E7F0-\\U0001E7FE\\U00020000-\\U0002A6DF\\U0002A700-"
- u"\\U0002B738\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-"
- u"\\U0002EBE0\\U00030000-\\U0003134A]";
+ u"\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793\\uA7AA\\uA7C0-\\uA7CA"
+ u"\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA9E7-\\uA9FE\\uAA60-\\uAA76\\uAA7A-"
+ u"\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-"
+ u"\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F\\uFA11\\uFA13\\uFA14"
+ u"\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301\\U00011303"
+ u"\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B11F-\\U0001B122"
+ u"\\U0001B132\\U0001B150-\\U0001B152\\U0001B155\\U0001B164-\\U0001B167"
+ u"\\U0001DF00-\\U0001DF1E\\U0001DF25-\\U0001DF2A\\U0001E08F\\U0001E7E0-"
+ u"\\U0001E7E6\\U0001E7E8-\\U0001E7EB\\U0001E7ED\\U0001E7EE\\U0001E7F0-"
+ u"\\U0001E7FE\\U00020000-\\U0002A6DF\\U0002A700-\\U0002B739\\U0002B740-"
+ u"\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-\\U0002EBE0\\U00030000-"
+ u"\\U0003134A\\U00031350-\\U000323AF]";
gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status);
if (gRecommendedSet == NULL) {
@@ -611,7 +612,7 @@ int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* c
int32_t i;
UChar32 c;
UChar32 firstNonspacingMark = 0;
- UBool haveMultipleMarks = FALSE;
+ UBool haveMultipleMarks = false;
UnicodeSet marksSeenSoFar; // Set of combining marks in a single combining sequence.
for (i=0; i<nfdLength ;) {
@@ -621,7 +622,7 @@ int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* c
firstNonspacingMark = 0;
if (haveMultipleMarks) {
marksSeenSoFar.clear();
- haveMultipleMarks = FALSE;
+ haveMultipleMarks = false;
}
continue;
}
@@ -631,7 +632,7 @@ int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* c
}
if (!haveMultipleMarks) {
marksSeenSoFar.add(firstNonspacingMark);
- haveMultipleMarks = TRUE;
+ haveMultipleMarks = true;
}
if (marksSeenSoFar.contains(c)) {
// report the error, and stop scanning.
@@ -656,13 +657,13 @@ uspoof_check2UnicodeString(const USpoofChecker *sc,
UErrorCode *status) {
const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
if (This == NULL) {
- return FALSE;
+ return false;
}
if (checkResult != NULL) {
CheckResult* ThisCheckResult = CheckResult::validateThis(checkResult, *status);
if (ThisCheckResult == NULL) {
- return FALSE;
+ return false;
}
return checkImpl(This, id, ThisCheckResult, status);
} else {
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.cpp b/thirdparty/icu4c/i18n/uspoof_impl.cpp
index b283d81321..e50344c469 100644
--- a/thirdparty/icu4c/i18n/uspoof_impl.cpp
+++ b/thirdparty/icu4c/i18n/uspoof_impl.cpp
@@ -320,10 +320,10 @@ URestrictionLevel SpoofImpl::getRestrictionLevel(const UnicodeString& input, UEr
// Section 5.2 step 2
// Java use a static UnicodeSet for this test. In C++, avoid the static variable
// and just do a simple for loop.
- UBool allASCII = TRUE;
+ UBool allASCII = true;
for (int32_t i=0, length=input.length(); i<length; i++) {
if (input.charAt(i) > 0x7f) {
- allASCII = FALSE;
+ allASCII = false;
break;
}
}
@@ -495,9 +495,9 @@ UBool SpoofData::validateDataVersion(UErrorCode &status) const {
fRawData->fFormatVersion[2] != 0 ||
fRawData->fFormatVersion[3] != 0) {
status = U_INVALID_FORMAT_ERROR;
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
static UBool U_CALLCONV
@@ -518,9 +518,9 @@ spoofDataIsAcceptable(void *context,
if(version != NULL) {
uprv_memcpy(version, pInfo->dataVersion, 4);
}
- return TRUE;
+ return true;
} else {
- return FALSE;
+ return false;
}
}
@@ -538,7 +538,7 @@ spoofDataIsAcceptable(void *context,
// uspoof_cleanupDefaultData - Called during cleanup.
//
-static UInitOnce gSpoofInitDefaultOnce = U_INITONCE_INITIALIZER;
+static UInitOnce gSpoofInitDefaultOnce {};
static SpoofData* gDefaultSpoofData;
static UBool U_CALLCONV
@@ -549,7 +549,7 @@ uspoof_cleanupDefaultData(void) {
gDefaultSpoofData = nullptr;
gSpoofInitDefaultOnce.reset();
}
- return TRUE;
+ return true;
}
static void U_CALLCONV uspoof_loadDefaultData(UErrorCode& status) {
@@ -655,7 +655,7 @@ SpoofData::SpoofData(UErrorCode &status) {
// Called by constructors to put things in a known initial state.
void SpoofData::reset() {
fRawData = NULL;
- fDataOwned = FALSE;
+ fDataOwned = false;
fUDM = NULL;
fMemLimit = 0;
fRefCount = 1;
@@ -945,7 +945,7 @@ uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *ou
uint32_t magic = ds->readUInt32(spoofDH->fMagic);
ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
- if (outputDH->fFormatVersion != spoofDH->fFormatVersion) {
+ if (inBytes != outBytes) {
uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
}
// swap starting at fLength
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.h b/thirdparty/icu4c/i18n/uspoof_impl.h
index e75ae262bd..68d7bedae1 100644
--- a/thirdparty/icu4c/i18n/uspoof_impl.h
+++ b/thirdparty/icu4c/i18n/uspoof_impl.h
@@ -28,6 +28,7 @@
#ifdef __cplusplus
#include "capi_helper.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
diff --git a/thirdparty/icu4c/icudt71l.dat b/thirdparty/icu4c/icudt72l.dat
index 3fa3af9c23..69edf4293d 100644
--- a/thirdparty/icu4c/icudt71l.dat
+++ b/thirdparty/icu4c/icudt72l.dat
Binary files differ
diff --git a/thirdparty/misc/patches/polypartition-hole.patch b/thirdparty/misc/patches/polypartition-hole.patch
new file mode 100644
index 0000000000..2fcb5d1928
--- /dev/null
+++ b/thirdparty/misc/patches/polypartition-hole.patch
@@ -0,0 +1,15 @@
+diff --git a/thirdparty/misc/polypartition.h b/thirdparty/misc/polypartition.h
+index fae7909079..c084bdf74c 100644
+--- a/thirdparty/misc/polypartition.h
++++ b/thirdparty/misc/polypartition.h
+@@ -71,8 +71,8 @@ class TPPLPoly {
+ return hole;
+ }
+
+- void SetHole(bool hole) {
+- this->hole = hole;
++ void SetHole(bool p_hole) {
++ this->hole = p_hole;
+ }
+
+ TPPLPoint &GetPoint(long i) {
diff --git a/thirdparty/misc/polypartition.h b/thirdparty/misc/polypartition.h
index fae7909079..c084bdf74c 100644
--- a/thirdparty/misc/polypartition.h
+++ b/thirdparty/misc/polypartition.h
@@ -71,8 +71,8 @@ class TPPLPoly {
return hole;
}
- void SetHole(bool hole) {
- this->hole = hole;
+ void SetHole(bool p_hole) {
+ this->hole = p_hole;
}
TPPLPoint &GetPoint(long i) {
diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h
index 879b70442b..68935c583b 100644
--- a/thirdparty/thorvg/inc/config.h
+++ b/thirdparty/thorvg/inc/config.h
@@ -13,5 +13,5 @@
#define THORVG_JPG_LOADER_SUPPORT 1
-#define THORVG_VERSION_STRING "0.8.1"
+#define THORVG_VERSION_STRING "0.8.2"
#endif
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h b/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
index 47b0cb83f5..157fdb8f82 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwCommon.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
index bba6f26a0b..04014a9ec3 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwFill.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
index ced66ae35c..1027bb1f79 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwMath.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
index 810df8d435..bf1c10a0c3 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRaster.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,8 +22,8 @@
#ifdef _WIN32
#include <malloc.h>
-#elif defined(__FreeBSD__)
- #include <stdlib.h>
+#elif __FreeBSD__
+ #include<stdlib.h>
#else
#include <alloca.h>
#endif
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
index be4392740e..fa213cc5d3 100644
--- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
+++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwStroke.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp
deleted file mode 100644
index 522c3c71a6..0000000000
--- a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <memory.h>
-#include <turbojpeg.h>
-#include "tvgLoader.h"
-#include "tvgJpgLoader.h"
-
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
-
-void JpgLoader::clear()
-{
- if (freeData) free(data);
- data = nullptr;
- size = 0;
- freeData = false;
-}
-
-/************************************************************************/
-/* External Class Implementation */
-/************************************************************************/
-
-JpgLoader::JpgLoader()
-{
- jpegDecompressor = tjInitDecompress();
-}
-
-
-JpgLoader::~JpgLoader()
-{
- if (freeData) free(data);
- tjDestroy(jpegDecompressor);
-
- //This image is shared with raster engine.
- tjFree(image);
-}
-
-
-bool JpgLoader::open(const string& path)
-{
- clear();
-
- auto jpegFile = fopen(path.c_str(), "rb");
- if (!jpegFile) return false;
-
- auto ret = false;
-
- //determine size
- if (fseek(jpegFile, 0, SEEK_END) < 0) goto finalize;
- if (((size = ftell(jpegFile)) < 1)) goto finalize;
- if (fseek(jpegFile, 0, SEEK_SET)) goto finalize;
-
- data = (unsigned char *) malloc(size);
- if (!data) goto finalize;
-
- freeData = true;
-
- if (fread(data, size, 1, jpegFile) < 1) goto failure;
-
- int width, height, subSample, colorSpace;
- if (tjDecompressHeader3(jpegDecompressor, data, size, &width, &height, &subSample, &colorSpace) < 0) {
- TVGERR("JPG LOADER", "%s", tjGetErrorStr());
- goto failure;
- }
-
- w = static_cast<float>(width);
- h = static_cast<float>(height);
- ret = true;
-
- goto finalize;
-
-failure:
- clear();
-
-finalize:
- fclose(jpegFile);
- return ret;
-}
-
-
-bool JpgLoader::open(const char* data, uint32_t size, bool copy)
-{
- clear();
-
- int width, height, subSample, colorSpace;
- if (tjDecompressHeader3(jpegDecompressor, (unsigned char *) data, size, &width, &height, &subSample, &colorSpace) < 0) return false;
-
- if (copy) {
- this->data = (unsigned char *) malloc(size);
- if (!this->data) return false;
- memcpy((unsigned char *)this->data, data, size);
- freeData = true;
- } else {
- this->data = (unsigned char *) data;
- freeData = false;
- }
-
- w = static_cast<float>(width);
- h = static_cast<float>(height);
- this->size = size;
-
- return true;
-}
-
-
-bool JpgLoader::read()
-{
- if (image) tjFree(image);
- image = (unsigned char *)tjAlloc(static_cast<int>(w) * static_cast<int>(h) * tjPixelSize[TJPF_BGRX]);
- if (!image) return false;
-
- //decompress jpg image
- if (tjDecompress2(jpegDecompressor, data, size, image, static_cast<int>(w), 0, static_cast<int>(h), TJPF_BGRX, 0) < 0) {
- TVGERR("JPG LOADER", "%s", tjGetErrorStr());
- tjFree(image);
- image = nullptr;
- return false;
- }
-
- return true;
-}
-
-
-bool JpgLoader::close()
-{
- clear();
- return true;
-}
-
-
-unique_ptr<Surface> JpgLoader::bitmap()
-{
- if (!image) return nullptr;
-
- auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
- surface->buffer = (uint32_t*)(image);
- surface->stride = w;
- surface->w = w;
- surface->h = h;
- surface->cs = SwCanvas::ARGB8888;
-
- return unique_ptr<Surface>(surface);
-}
diff --git a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.h b/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.h
deleted file mode 100644
index 3f82af8003..0000000000
--- a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _TVG_JPG_LOADER_H_
-#define _TVG_JPG_LOADER_H_
-
-using tjhandle = void*;
-
-//TODO: Use Task?
-class JpgLoader : public LoadModule
-{
-public:
- JpgLoader();
- ~JpgLoader();
-
- using LoadModule::open;
- bool open(const string& path) override;
- bool open(const char* data, uint32_t size, bool copy) override;
- bool read() override;
- bool close() override;
-
- unique_ptr<Surface> bitmap() override;
-
-private:
- void clear();
-
- tjhandle jpegDecompressor;
- unsigned char* data = nullptr;
- unsigned char *image = nullptr;
- unsigned long size = 0;
- bool freeData = false;
-};
-
-#endif //_TVG_JPG_LOADER_H_
diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp b/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
deleted file mode 100644
index eaed025c54..0000000000
--- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.cpp
+++ /dev/null
@@ -1,2647 +0,0 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- LodePNG version 20200306
-
- Copyright (c) 2005-2020 Lode Vandevenne
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any sourcedistribution.
-*/
-
-#include <cstdlib>
-#include "tvgLodePng.h"
-
-
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/
- #pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/
- #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/
-#endif /*_MSC_VER */
-
-
-/* convince the compiler to inline a function, for use when this measurably improves performance */
-/* inline is not available in C90, but use it when supported by the compiler */
-#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || (defined(__cplusplus) && (__cplusplus >= 199711L))
- #define LODEPNG_INLINE inline
-#else
- #define LODEPNG_INLINE /* not available */
-#endif
-
-/* restrict is not available in C90, but use it when supported by the compiler */
-#if (defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) ||\
- (defined(_MSC_VER) && (_MSC_VER >= 1400)) || \
- (defined(__WATCOMC__) && (__WATCOMC__ >= 1250) && !defined(__cplusplus))
- #define LODEPNG_RESTRICT __restrict
-#else
- #define LODEPNG_RESTRICT /* not available */
-#endif
-
-#define LODEPNG_MAX(a, b) (((a) > (b)) ? (a) : (b))
-#define LODEPNG_MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define LODEPNG_ABS(x) ((x) < 0 ? -(x) : (x))
-
-
-/* Replacements for C library functions such as memcpy and strlen, to support platforms
-where a full C library is not available. The compiler can recognize them and compile
-to something as fast. */
-
-static void lodepng_memcpy(void* LODEPNG_RESTRICT dst, const void* LODEPNG_RESTRICT src, size_t size)
-{
- size_t i;
- for (i = 0; i < size; i++) ((char*)dst)[i] = ((const char*)src)[i];
-}
-
-
-static void lodepng_memset(void* LODEPNG_RESTRICT dst, int value, size_t num)
-{
- size_t i;
- for (i = 0; i < num; i++) ((char*)dst)[i] = (char)value;
-}
-
-
-/* does not check memory out of bounds, do not use on untrusted data */
-static size_t lodepng_strlen(const char* a)
-{
- const char* orig = a;
- /* avoid warning about unused function in case of disabled COMPILE... macros */
- (void)(&lodepng_strlen);
- while (*a) a++;
- return (size_t)(a - orig);
-}
-
-
-/* Safely check if adding two integers will overflow (no undefined
-behavior, compiler removing the code, etc...) and output result. */
-static int lodepng_addofl(size_t a, size_t b, size_t* result)
-{
- *result = a + b; /* Unsigned addition is well defined and safe in C90 */
- return *result < a;
-}
-
-
-/* Safely check if multiplying two integers will overflow (no undefined
-behavior, compiler removing the code, etc...) and output result. */
-static int lodepng_mulofl(size_t a, size_t b, size_t* result)
-{
- *result = a * b; /* Unsigned multiplication is well defined and safe in C90 */
- return (a != 0 && *result / a != b);
-}
-
-
-/* Safely check if a + b > c, even if overflow could happen. */
-static int lodepng_gtofl(size_t a, size_t b, size_t c)
-{
- size_t d;
- if (lodepng_addofl(a, b, &d)) return 1;
- return d > c;
-}
-
-
-/*
- Often in case of an error a value is assigned to a variable and then it breaks
- out of a loop (to go to the cleanup phase of a function). This macro does that.
- It makes the error handling code shorter and more readable.
-
- Example: if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83);
-*/
-#define CERROR_BREAK(errorvar, code){\
- errorvar = code;\
- break;\
-}
-
-/* version of CERROR_BREAK that assumes the common case where the error variable is named "error" */
-#define ERROR_BREAK(code) CERROR_BREAK(error, code)
-
-/* Set error var to the error code, and return it.*/
-#define CERROR_RETURN_ERROR(errorvar, code){\
- errorvar = code;\
- return code;\
-}
-
-/* Try the code, if it returns error, also return the error. */
-#define CERROR_TRY_RETURN(call){\
- unsigned error = call;\
- if(error) return error;\
-}
-
-/* Set error var to the error code, and return from the void function. */
-#define CERROR_RETURN(errorvar, code){\
- errorvar = code;\
- return;\
-}
-
-
-/* dynamic vector of unsigned chars */
-struct ucvector
-{
- unsigned char* data;
- size_t size; /*used size*/
- size_t allocsize; /*allocated size*/
-};
-
-
-/* returns 1 if success, 0 if failure ==> nothing done */
-static unsigned ucvector_resize(ucvector* p, size_t size)
-{
- if (size > p->allocsize) {
- size_t newsize = size + (p->allocsize >> 1u);
- void* data = realloc(p->data, newsize);
- if(data) {
- p->allocsize = newsize;
- p->data = (unsigned char*)data;
- }
- else return 0; /*error: not enough memory*/
- }
- p->size = size;
- return 1; /*success*/
-}
-
-
-static ucvector ucvector_init(unsigned char* buffer, size_t size)
-{
- ucvector v;
- v.data = buffer;
- v.allocsize = v.size = size;
- return v;
-}
-
-
-static unsigned lodepng_read32bitInt(const unsigned char* buffer)
-{
- return (((unsigned)buffer[0] << 24u) | ((unsigned)buffer[1] << 16u) | ((unsigned)buffer[2] << 8u) | (unsigned)buffer[3]);
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* ////////////////////////////////////////////////////////////////////////// */
-/* // End of common code and tools. Begin of Zlib related code. // */
-/* ////////////////////////////////////////////////////////////////////////// */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-struct LodePNGBitReader
-{
- const unsigned char* data;
- size_t size; /*size of data in bytes*/
- size_t bitsize; /*size of data in bits, end of valid bp values, should be 8*size*/
- size_t bp;
- unsigned buffer; /*buffer for reading bits. NOTE: 'unsigned' must support at least 32 bits*/
-};
-
-
-/* data size argument is in bytes. Returns error if size too large causing overflow */
-static unsigned LodePNGBitReader_init(LodePNGBitReader* reader, const unsigned char* data, size_t size)
-{
- size_t temp;
- reader->data = data;
- reader->size = size;
- /* size in bits, return error if overflow (if size_t is 32 bit this supports up to 500MB) */
- if (lodepng_mulofl(size, 8u, &reader->bitsize)) return 105;
- /*ensure incremented bp can be compared to bitsize without overflow even when it would be incremented 32 too much and
- trying to ensure 32 more bits*/
- if (lodepng_addofl(reader->bitsize, 64u, &temp)) return 105;
- reader->bp = 0;
- reader->buffer = 0;
- return 0; /*ok*/
- }
-
-/*
- ensureBits functions:
- Ensures the reader can at least read nbits bits in one or more readBits calls,
- safely even if not enough bits are available.
- Returns 1 if there are enough bits available, 0 if not.
-*/
-
-/*See ensureBits documentation above. This one ensures exactly 1 bit */
-/*static unsigned ensureBits1(LodePNGBitReader* reader) {
- if(reader->bp >= reader->bitsize) return 0;
- reader->buffer = (unsigned)reader->data[reader->bp >> 3u] >> (reader->bp & 7u);
- return 1;
-}*/
-
-/*See ensureBits documentation above. This one ensures up to 9 bits */
-static unsigned ensureBits9(LodePNGBitReader* reader, size_t nbits)
-{
- size_t start = reader->bp >> 3u;
- size_t size = reader->size;
- if (start + 1u < size) {
- reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u);
- reader->buffer >>= (reader->bp & 7u);
- return 1;
- } else {
- reader->buffer = 0;
- if (start + 0u < size) reader->buffer |= reader->data[start + 0];
- reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
- }
-}
-
-
-/*See ensureBits documentation above. This one ensures up to 17 bits */
-static unsigned ensureBits17(LodePNGBitReader* reader, size_t nbits)
-{
- size_t start = reader->bp >> 3u;
- size_t size = reader->size;
- if (start + 2u < size) {
- reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u);
- reader->buffer >>= (reader->bp & 7u);
- return 1;
- } else {
- reader->buffer = 0;
- if (start + 0u < size) reader->buffer |= reader->data[start + 0];
- if (start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
- reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
- }
-}
-
-
-/*See ensureBits documentation above. This one ensures up to 25 bits */
-static LODEPNG_INLINE unsigned ensureBits25(LodePNGBitReader* reader, size_t nbits)
-{
- size_t start = reader->bp >> 3u;
- size_t size = reader->size;
- if (start + 3u < size) {
- reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
- reader->buffer >>= (reader->bp & 7u);
- return 1;
- } else {
- reader->buffer = 0;
- if (start + 0u < size) reader->buffer |= reader->data[start + 0];
- if (start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
- if (start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
- reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
- }
-}
-
-
-/*See ensureBits documentation above. This one ensures up to 32 bits */
-static LODEPNG_INLINE unsigned ensureBits32(LodePNGBitReader* reader, size_t nbits)
-{
- size_t start = reader->bp >> 3u;
- size_t size = reader->size;
- if(start + 4u < size) {
- reader->buffer = (unsigned)reader->data[start + 0] | ((unsigned)reader->data[start + 1] << 8u) | ((unsigned)reader->data[start + 2] << 16u) | ((unsigned)reader->data[start + 3] << 24u);
- reader->buffer >>= (reader->bp & 7u);
- reader->buffer |= (((unsigned)reader->data[start + 4] << 24u) << (8u - (reader->bp & 7u)));
- return 1;
- } else {
- reader->buffer = 0;
- if (start + 0u < size) reader->buffer |= reader->data[start + 0];
- if (start + 1u < size) reader->buffer |= ((unsigned)reader->data[start + 1] << 8u);
- if (start + 2u < size) reader->buffer |= ((unsigned)reader->data[start + 2] << 16u);
- if (start + 3u < size) reader->buffer |= ((unsigned)reader->data[start + 3] << 24u);
- reader->buffer >>= (reader->bp & 7u);
- return reader->bp + nbits <= reader->bitsize;
- }
-}
-
-
-/* Get bits without advancing the bit pointer. Must have enough bits available with ensureBits. Max nbits is 31. */
-static unsigned peekBits(LodePNGBitReader* reader, size_t nbits)
-{
- /* The shift allows nbits to be only up to 31. */
- return reader->buffer & ((1u << nbits) - 1u);
-}
-
-
-/* Must have enough bits available with ensureBits */
-static void advanceBits(LodePNGBitReader* reader, size_t nbits)
-{
- reader->buffer >>= nbits;
- reader->bp += nbits;
-}
-
-
-/* Must have enough bits available with ensureBits */
-static unsigned readBits(LodePNGBitReader* reader, size_t nbits)
-{
- unsigned result = peekBits(reader, nbits);
- advanceBits(reader, nbits);
- return result;
-}
-
-
-/* Public for testing only. steps and result must have numsteps values. */
-unsigned lode_png_test_bitreader(const unsigned char* data, size_t size, size_t numsteps, const size_t* steps, unsigned* result)
-{
- size_t i;
- LodePNGBitReader reader;
- unsigned error = LodePNGBitReader_init(&reader, data, size);
- if (error) return 0;
- for (i = 0; i < numsteps; i++) {
- size_t step = steps[i];
- unsigned ok;
- if (step > 25) ok = ensureBits32(&reader, step);
- else if (step > 17) ok = ensureBits25(&reader, step);
- else if (step > 9) ok = ensureBits17(&reader, step);
- else ok = ensureBits9(&reader, step);
- if (!ok) return 0;
- result[i] = readBits(&reader, step);
- }
- return 1;
-}
-
-
-static unsigned reverseBits(unsigned bits, unsigned num)
-{
- /*TODO: implement faster lookup table based version when needed*/
- unsigned i, result = 0;
- for (i = 0; i < num; i++) result |= ((bits >> (num - i - 1u)) & 1u) << i;
- return result;
-}
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Deflate - Huffman / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-#define FIRST_LENGTH_CODE_INDEX 257
-#define LAST_LENGTH_CODE_INDEX 285
-/*256 literals, the end code, some length codes, and 2 unused codes*/
-#define NUM_DEFLATE_CODE_SYMBOLS 288
-/*the distance codes have their own symbols, 30 used, 2 unused*/
-#define NUM_DISTANCE_SYMBOLS 32
-/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/
-#define NUM_CODE_LENGTH_CODES 19
-
-/*the base lengths represented by codes 257-285*/
-static const unsigned LENGTHBASE[29]
- = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
- 67, 83, 99, 115, 131, 163, 195, 227, 258};
-
-/*the extra bits used by codes 257-285 (added to base length)*/
-static const unsigned LENGTHEXTRA[29]
- = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
- 4, 4, 4, 4, 5, 5, 5, 5, 0};
-
-/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/
-static const unsigned DISTANCEBASE[30]
- = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
- 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
-
-/*the extra bits of backwards distances (added to base)*/
-static const unsigned DISTANCEEXTRA[30]
- = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
- 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
-
-/*the order in which "code length alphabet code lengths" are stored as specified by deflate, out of this the huffman
-tree of the dynamic huffman tree lengths is generated*/
-static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]
- = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*
-Huffman tree struct, containing multiple representations of the tree
-*/
-struct HuffmanTree
-{
- unsigned* codes; /*the huffman codes (bit patterns representing the symbols)*/
- unsigned* lengths; /*the lengths of the huffman codes*/
- unsigned maxbitlen; /*maximum number of bits a single code can get*/
- unsigned numcodes; /*number of symbols in the alphabet = number of codes*/
- /* for reading only */
- unsigned char* table_len; /*length of symbol from lookup table, or max length if secondary lookup needed*/
- unsigned short* table_value; /*value of symbol from lookup table, or pointer to secondary table if needed*/
-};
-
-
-static void HuffmanTree_init(HuffmanTree* tree)
-{
- tree->codes = 0;
- tree->lengths = 0;
- tree->table_len = 0;
- tree->table_value = 0;
-}
-
-
-static void HuffmanTree_cleanup(HuffmanTree* tree)
-{
- free(tree->codes);
- free(tree->lengths);
- free(tree->table_len);
- free(tree->table_value);
-}
-
-
-/* amount of bits for first huffman table lookup (aka root bits), see HuffmanTree_makeTable and huffmanDecodeSymbol.*/
-/* values 8u and 9u work the fastest */
-#define FIRSTBITS 9u
-
-/* a symbol value too big to represent any valid symbol, to indicate reading disallowed huffman bits combination,
-which is possible in case of only 0 or 1 present symbols. */
-#define INVALIDSYMBOL 65535u
-
-/* make table for huffman decoding */
-static unsigned HuffmanTree_makeTable(HuffmanTree* tree)
-{
- static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/
- static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u;
- size_t i, numpresent, pointer, size; /*total table size*/
- unsigned* maxlens = (unsigned*)malloc(headsize * sizeof(unsigned));
- if (!maxlens) return 83; /*alloc fail*/
-
- /* compute maxlens: max total bit length of symbols sharing prefix in the first table*/
- lodepng_memset(maxlens, 0, headsize * sizeof(*maxlens));
- for (i = 0; i < tree->numcodes; i++) {
- unsigned symbol = tree->codes[i];
- unsigned l = tree->lengths[i];
- unsigned index;
- if(l <= FIRSTBITS) continue; /*symbols that fit in first table don't increase secondary table size*/
- /*get the FIRSTBITS MSBs, the MSBs of the symbol are encoded first. See later comment about the reversing*/
- index = reverseBits(symbol >> (l - FIRSTBITS), FIRSTBITS);
- maxlens[index] = LODEPNG_MAX(maxlens[index], l);
- }
- /* compute total table size: size of first table plus all secondary tables for symbols longer than FIRSTBITS */
- size = headsize;
- for (i = 0; i < headsize; ++i) {
- unsigned l = maxlens[i];
- if (l > FIRSTBITS) size += (1u << (l - FIRSTBITS));
- }
- tree->table_len = (unsigned char*)malloc(size * sizeof(*tree->table_len));
- tree->table_value = (unsigned short*)malloc(size * sizeof(*tree->table_value));
- if (!tree->table_len || !tree->table_value) {
- free(maxlens);
- /* freeing tree->table values is done at a higher scope */
- return 83; /*alloc fail*/
- }
- /*initialize with an invalid length to indicate unused entries*/
- for (i = 0; i < size; ++i) tree->table_len[i] = 16;
-
- /*fill in the first table for long symbols: max prefix size and pointer to secondary tables*/
- pointer = headsize;
- for (i = 0; i < headsize; ++i) {
- unsigned l = maxlens[i];
- if(l <= FIRSTBITS) continue;
- tree->table_len[i] = l;
- tree->table_value[i] = pointer;
- pointer += (1u << (l - FIRSTBITS));
- }
- free(maxlens);
-
- /*fill in the first table for short symbols, or secondary table for long symbols*/
- numpresent = 0;
- for (i = 0; i < tree->numcodes; ++i) {
- unsigned l = tree->lengths[i];
- unsigned symbol = tree->codes[i]; /*the huffman bit pattern. i itself is the value.*/
- /*reverse bits, because the huffman bits are given in MSB first order but the bit reader reads LSB first*/
- unsigned reverse = reverseBits(symbol, l);
- if (l == 0) continue;
- numpresent++;
-
- if (l <= FIRSTBITS) {
- /*short symbol, fully in first table, replicated num times if l < FIRSTBITS*/
- unsigned num = 1u << (FIRSTBITS - l);
- unsigned j;
- for (j = 0; j < num; ++j) {
- /*bit reader will read the l bits of symbol first, the remaining FIRSTBITS - l bits go to the MSB's*/
- unsigned index = reverse | (j << l);
- if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
- tree->table_len[index] = l;
- tree->table_value[index] = i;
- }
- } else {
- /*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/
- /*the FIRSTBITS MSBs of the symbol are the first table index*/
- unsigned index = reverse & mask;
- unsigned maxlen = tree->table_len[index];
- /*log2 of secondary table length, should be >= l - FIRSTBITS*/
- unsigned tablelen = maxlen - FIRSTBITS;
- unsigned start = tree->table_value[index]; /*starting index in secondary table*/
- unsigned num = 1u << (tablelen - (l - FIRSTBITS)); /*amount of entries of this symbol in secondary table*/
- unsigned j;
- if (maxlen < l) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
- for (j = 0; j < num; ++j) {
- unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */
- unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));
- tree->table_len[index2] = l;
- tree->table_value[index2] = i;
- }
- }
- }
-
- if (numpresent < 2) {
- /* In case of exactly 1 symbol, in theory the huffman symbol needs 0 bits,
- but deflate uses 1 bit instead. In case of 0 symbols, no symbols can
- appear at all, but such huffman tree could still exist (e.g. if distance
- codes are never used). In both cases, not all symbols of the table will be
- filled in. Fill them in with an invalid symbol value so returning them from
- huffmanDecodeSymbol will cause error. */
- for (i = 0; i < size; ++i) {
- if (tree->table_len[i] == 16) {
- /* As length, use a value smaller than FIRSTBITS for the head table,
- and a value larger than FIRSTBITS for the secondary table, to ensure
- valid behavior for advanceBits when reading this symbol. */
- tree->table_len[i] = (i < headsize) ? 1 : (FIRSTBITS + 1);
- tree->table_value[i] = INVALIDSYMBOL;
- }
- }
- } else {
- /* A good huffman tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
- If that is not the case (due to too long length codes), the table will not
- have been fully used, and this is an error (not all bit combinations can be
- decoded): an oversubscribed huffman tree, indicated by error 55. */
- for (i = 0; i < size; ++i) {
- if (tree->table_len[i] == 16) return 55;
- }
- }
- return 0;
-}
-
-
-/*
- Second step for the ...makeFromLengths and ...makeFromFrequencies functions.
- numcodes, lengths and maxbitlen must already be filled in correctly. return
- value is error.
-*/
-static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree)
-{
- unsigned* blcount;
- unsigned* nextcode;
- unsigned error = 0;
- unsigned bits, n;
-
- tree->codes = (unsigned*)malloc(tree->numcodes * sizeof(unsigned));
- blcount = (unsigned*)malloc((tree->maxbitlen + 1) * sizeof(unsigned));
- nextcode = (unsigned*)malloc((tree->maxbitlen + 1) * sizeof(unsigned));
- if (!tree->codes || !blcount || !nextcode) error = 83; /*alloc fail*/
-
- if (!error) {
- for (n = 0; n != tree->maxbitlen + 1; n++) blcount[n] = nextcode[n] = 0;
- /*step 1: count number of instances of each code length*/
- for (bits = 0; bits != tree->numcodes; ++bits) ++blcount[tree->lengths[bits]];
- /*step 2: generate the nextcode values*/
- for(bits = 1; bits <= tree->maxbitlen; ++bits) {
- nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1u;
- }
- /*step 3: generate all the codes*/
- for (n = 0; n != tree->numcodes; ++n) {
- if (tree->lengths[n] != 0) {
- tree->codes[n] = nextcode[tree->lengths[n]]++;
- /*remove superfluous bits from the code*/
- tree->codes[n] &= ((1u << tree->lengths[n]) - 1u);
- }
- }
- }
-
- free(blcount);
- free(nextcode);
-
- if (!error) error = HuffmanTree_makeTable(tree);
- return error;
-}
-
-
-/*
- given the code lengths (as stored in the PNG file), generate the tree as defined
- by Deflate. maxbitlen is the maximum bits that a code in the tree can have.
- return value is error.
-*/
-static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen, size_t numcodes, unsigned maxbitlen)
-{
- unsigned i;
- tree->lengths = (unsigned*)malloc(numcodes * sizeof(unsigned));
- if (!tree->lengths) return 83; /*alloc fail*/
- for (i = 0; i != numcodes; ++i) tree->lengths[i] = bitlen[i];
- tree->numcodes = (unsigned)numcodes; /*number of symbols*/
- tree->maxbitlen = maxbitlen;
- return HuffmanTree_makeFromLengths2(tree);
-}
-
-
-/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/
-static unsigned generateFixedLitLenTree(HuffmanTree* tree)
-{
- unsigned i, error = 0;
- unsigned* bitlen = (unsigned*)malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
- if (!bitlen) return 83; /*alloc fail*/
-
- /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
- for (i = 0; i <= 143; ++i) bitlen[i] = 8;
- for (i = 144; i <= 255; ++i) bitlen[i] = 9;
- for (i = 256; i <= 279; ++i) bitlen[i] = 7;
- for (i = 280; i <= 287; ++i) bitlen[i] = 8;
-
- error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);
-
- free(bitlen);
- return error;
-}
-
-
-/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/
-static unsigned generateFixedDistanceTree(HuffmanTree* tree)
-{
- unsigned i, error = 0;
- unsigned* bitlen = (unsigned*)malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
- if (!bitlen) return 83; /*alloc fail*/
-
- /*there are 32 distance codes, but 30-31 are unused*/
- for (i = 0; i != NUM_DISTANCE_SYMBOLS; ++i) bitlen[i] = 5;
- error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);
-
- free(bitlen);
- return error;
-}
-
-
-/*
- returns the code. The bit reader must already have been ensured at least 15 bits
-*/
-static unsigned huffmanDecodeSymbol(LodePNGBitReader* reader, const HuffmanTree* codetree)
-{
- unsigned short code = peekBits(reader, FIRSTBITS);
- unsigned short l = codetree->table_len[code];
- unsigned short value = codetree->table_value[code];
- if (l <= FIRSTBITS) {
- advanceBits(reader, l);
- return value;
- } else {
- unsigned index2;
- advanceBits(reader, FIRSTBITS);
- index2 = value + peekBits(reader, l - FIRSTBITS);
- advanceBits(reader, codetree->table_len[index2] - FIRSTBITS);
- return codetree->table_value[index2];
- }
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Inflator (Decompressor) / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*get the tree of a deflated block with fixed tree, as specified in the deflate specification
-Returns error code.*/
-static unsigned getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d)
-{
- unsigned error = generateFixedLitLenTree(tree_ll);
- if (error) return error;
- return generateFixedDistanceTree(tree_d);
-}
-
-
-/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
-static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d, LodePNGBitReader* reader)
-{
- /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
- unsigned error = 0;
- unsigned n, HLIT, HDIST, HCLEN, i;
-
- /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
- unsigned* bitlen_ll = 0; /*lit,len code lengths*/
- unsigned* bitlen_d = 0; /*dist code lengths*/
- /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
- unsigned* bitlen_cl = 0;
- HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
-
- if (!ensureBits17(reader, 14)) return 49; /*error: the bit pointer is or will go past the memory*/
-
- /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
- HLIT = readBits(reader, 5) + 257;
- /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
- HDIST = readBits(reader, 5) + 1;
- /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
- HCLEN = readBits(reader, 4) + 4;
-
- bitlen_cl = (unsigned*)malloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
- if(!bitlen_cl) return 83 /*alloc fail*/;
-
- HuffmanTree_init(&tree_cl);
-
- while (!error) {
- /*read the code length codes out of 3 * (amount of code length codes) bits*/
- if (lodepng_gtofl(reader->bp, HCLEN * 3, reader->bitsize)) {
- ERROR_BREAK(50); /*error: the bit pointer is or will go past the memory*/
- }
- for (i = 0; i != HCLEN; ++i) {
- ensureBits9(reader, 3); /*out of bounds already checked above */
- bitlen_cl[CLCL_ORDER[i]] = readBits(reader, 3);
- }
- for (i = HCLEN; i != NUM_CODE_LENGTH_CODES; ++i) {
- bitlen_cl[CLCL_ORDER[i]] = 0;
- }
-
- error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);
- if(error) break;
-
- /*now we can use this tree to read the lengths for the tree that this function will return*/
- bitlen_ll = (unsigned*)malloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
- bitlen_d = (unsigned*)malloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
- if (!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);
- lodepng_memset(bitlen_ll, 0, NUM_DEFLATE_CODE_SYMBOLS * sizeof(*bitlen_ll));
- lodepng_memset(bitlen_d, 0, NUM_DISTANCE_SYMBOLS * sizeof(*bitlen_d));
-
- /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/
- i = 0;
- while (i < HLIT + HDIST) {
- unsigned code;
- ensureBits25(reader, 22); /* up to 15 bits for huffman code, up to 7 extra bits below*/
- code = huffmanDecodeSymbol(reader, &tree_cl);
- if (code <= 15) /*a length code*/ {
- if (i < HLIT) bitlen_ll[i] = code;
- else bitlen_d[i - HLIT] = code;
- ++i;
- } else if (code == 16) /*repeat previous*/ {
- unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/
- unsigned value; /*set value to the previous code*/
-
- if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/
-
- replength += readBits(reader, 2);
-
- if (i < HLIT + 1) value = bitlen_ll[i - 1];
- else value = bitlen_d[i - HLIT - 1];
- /*repeat this value in the next lengths*/
- for (n = 0; n < replength; ++n) {
- if (i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/
- if (i < HLIT) bitlen_ll[i] = value;
- else bitlen_d[i - HLIT] = value;
- ++i;
- }
- } else if(code == 17) /*repeat "0" 3-10 times*/ {
- unsigned replength = 3; /*read in the bits that indicate repeat length*/
- replength += readBits(reader, 3);
-
- /*repeat this value in the next lengths*/
- for (n = 0; n < replength; ++n) {
- if (i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/
-
- if (i < HLIT) bitlen_ll[i] = 0;
- else bitlen_d[i - HLIT] = 0;
- ++i;
- }
- } else if(code == 18) /*repeat "0" 11-138 times*/ {
- unsigned replength = 11; /*read in the bits that indicate repeat length*/
- replength += readBits(reader, 7);
-
- /*repeat this value in the next lengths*/
- for (n = 0; n < replength; ++n) {
- if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/
-
- if(i < HLIT) bitlen_ll[i] = 0;
- else bitlen_d[i - HLIT] = 0;
- ++i;
- }
- } else /*if(code == INVALIDSYMBOL)*/ {
- ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
- }
- /*check if any of the ensureBits above went out of bounds*/
- if (reader->bp > reader->bitsize) {
- /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
- (10=no endcode, 11=wrong jump outside of tree)*/
- /* TODO: revise error codes 10,11,50: the above comment is no longer valid */
- ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
- }
- }
- if (error) break;
-
- if (bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/
-
- /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
- error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);
- if (error) break;
- error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);
-
- break; /*end of error-while*/
- }
-
- free(bitlen_cl);
- free(bitlen_ll);
- free(bitlen_d);
- HuffmanTree_cleanup(&tree_cl);
-
- return error;
-}
-
-
-/*inflate a block with dynamic of fixed Huffman tree. btype must be 1 or 2.*/
-static unsigned inflateHuffmanBlock(ucvector* out, LodePNGBitReader* reader, unsigned btype)
-{
- unsigned error = 0;
- HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
- HuffmanTree tree_d; /*the huffman tree for distance codes*/
-
- HuffmanTree_init(&tree_ll);
- HuffmanTree_init(&tree_d);
-
- if (btype == 1) error = getTreeInflateFixed(&tree_ll, &tree_d);
- else /*if(btype == 2)*/ error = getTreeInflateDynamic(&tree_ll, &tree_d, reader);
-
- while (!error) /*decode all symbols until end reached, breaks at end code*/ {
- /*code_ll is literal, length or end code*/
- unsigned code_ll;
- ensureBits25(reader, 20); /* up to 15 for the huffman symbol, up to 5 for the length extra bits */
- code_ll = huffmanDecodeSymbol(reader, &tree_ll);
- if (code_ll <= 255) /*literal symbol*/ {
- if (!ucvector_resize(out, out->size + 1)) ERROR_BREAK(83 /*alloc fail*/);
- out->data[out->size - 1] = (unsigned char)code_ll;
- } else if (code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/ {
- unsigned code_d, distance;
- unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
- size_t start, backward, length;
-
- /*part 1: get length base*/
- length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];
-
- /*part 2: get extra bits and add the value of that to length*/
- numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
- if (numextrabits_l != 0) {
- /* bits already ensured above */
- length += readBits(reader, numextrabits_l);
- }
-
- /*part 3: get distance code*/
- ensureBits32(reader, 28); /* up to 15 for the huffman symbol, up to 13 for the extra bits */
- code_d = huffmanDecodeSymbol(reader, &tree_d);
- if (code_d > 29) {
- if (code_d <= 31) {
- ERROR_BREAK(18); /*error: invalid distance code (30-31 are never used)*/
- } else /* if(code_d == INVALIDSYMBOL) */{
- ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
- }
- }
- distance = DISTANCEBASE[code_d];
-
- /*part 4: get extra bits from distance*/
- numextrabits_d = DISTANCEEXTRA[code_d];
- if (numextrabits_d != 0) {
- /* bits already ensured above */
- distance += readBits(reader, numextrabits_d);
- }
-
- /*part 5: fill in all the out[n] values based on the length and dist*/
- start = out->size;
- if (distance > start) ERROR_BREAK(52); /*too long backward distance*/
- backward = start - distance;
-
- if (!ucvector_resize(out, out->size + length)) ERROR_BREAK(83 /*alloc fail*/);
- if (distance < length) {
- size_t forward;
- lodepng_memcpy(out->data + start, out->data + backward, distance);
- start += distance;
- for (forward = distance; forward < length; ++forward) {
- out->data[start++] = out->data[backward++];
- }
- } else {
- lodepng_memcpy(out->data + start, out->data + backward, length);
- }
- } else if (code_ll == 256) {
- break; /*end code, break the loop*/
- } else /*if(code_ll == INVALIDSYMBOL)*/ {
- ERROR_BREAK(16); /*error: tried to read disallowed huffman symbol*/
- }
- /*check if any of the ensureBits above went out of bounds*/
- if (reader->bp > reader->bitsize) {
- /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
- (10=no endcode, 11=wrong jump outside of tree)*/
- /* TODO: revise error codes 10,11,50: the above comment is no longer valid */
- ERROR_BREAK(51); /*error, bit pointer jumps past memory*/
- }
- }
-
- HuffmanTree_cleanup(&tree_ll);
- HuffmanTree_cleanup(&tree_d);
-
- return error;
-}
-
-
-static unsigned inflateNoCompression(ucvector* out, LodePNGBitReader* reader, const LodePNGDecompressSettings* settings)
-{
- size_t bytepos;
- size_t size = reader->size;
- unsigned LEN, NLEN, error = 0;
-
- /*go to first boundary of byte*/
- bytepos = (reader->bp + 7u) >> 3u;
-
- /*read LEN (2 bytes) and NLEN (2 bytes)*/
- if (bytepos + 4 >= size) return 52; /*error, bit pointer will jump past memory*/
- LEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2;
- NLEN = (unsigned)reader->data[bytepos] + ((unsigned)reader->data[bytepos + 1] << 8u); bytepos += 2;
-
- /*check if 16-bit NLEN is really the one's complement of LEN*/
- if (!settings->ignore_nlen && LEN + NLEN != 65535) {
- return 21; /*error: NLEN is not one's complement of LEN*/
- }
-
- if (!ucvector_resize(out, out->size + LEN)) return 83; /*alloc fail*/
-
- /*read the literal data: LEN bytes are now stored in the out buffer*/
- if (bytepos + LEN > size) return 23; /*error: reading outside of in buffer*/
-
- lodepng_memcpy(out->data + out->size - LEN, reader->data + bytepos, LEN);
- bytepos += LEN;
-
- reader->bp = bytepos << 3u;
-
- return error;
-}
-
-
-static unsigned lodepng_inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings)
-{
- unsigned BFINAL = 0;
- LodePNGBitReader reader;
- unsigned error = LodePNGBitReader_init(&reader, in, insize);
-
- if (error) return error;
-
- while (!BFINAL) {
- unsigned BTYPE;
- if (!ensureBits9(&reader, 3)) return 52; /*error, bit pointer will jump past memory*/
- BFINAL = readBits(&reader, 1);
- BTYPE = readBits(&reader, 2);
-
- if (BTYPE == 3) return 20; /*error: invalid BTYPE*/
- else if (BTYPE == 0) error = inflateNoCompression(out, &reader, settings); /*no compression*/
- else error = inflateHuffmanBlock(out, &reader, BTYPE); /*compression, BTYPE 01 or 10*/
-
- if (error) return error;
- }
-
- return error;
-}
-
-
-static unsigned inflatev(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings)
-{
- if (settings->custom_inflate) {
- unsigned error = settings->custom_inflate(&out->data, &out->size, in, insize, settings);
- out->allocsize = out->size;
- return error;
- } else {
- return lodepng_inflatev(out, in, insize, settings);
- }
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Adler32 / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len)
-{
- unsigned s1 = adler & 0xffffu;
- unsigned s2 = (adler >> 16u) & 0xffffu;
-
- while (len != 0u) {
- unsigned i;
- /*at least 5552 sums can be done before the sums overflow, saving a lot of module divisions*/
- unsigned amount = len > 5552u ? 5552u : len;
- len -= amount;
- for (i = 0; i != amount; ++i) {
- s1 += (*data++);
- s2 += s1;
- }
- s1 %= 65521u;
- s2 %= 65521u;
- }
-
- return (s2 << 16u) | s1;
-}
-
-/*Return the adler32 of the bytes data[0..len-1]*/
-static unsigned adler32(const unsigned char* data, unsigned len)
-{
- return update_adler32(1u, data, len);
-}
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Zlib / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-static unsigned lodepng_zlib_decompressv(ucvector* out, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings)
-{
- unsigned error = 0;
- unsigned CM, CINFO, FDICT;
-
- if (insize < 2) return 53; /*error, size of zlib data too small*/
- /*read information from zlib header*/
- if ((in[0] * 256 + in[1]) % 31 != 0) {
- /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/
- return 24;
- }
-
- CM = in[0] & 15;
- CINFO = (in[0] >> 4) & 15;
- /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/
- FDICT = (in[1] >> 5) & 1;
- /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/
-
- if (CM != 8 || CINFO > 7) {
- /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/
- return 25;
- }
- if (FDICT != 0) {
- /*error: the specification of PNG says about the zlib stream:
- "The additional flags shall not specify a preset dictionary."*/
- return 26;
- }
-
- error = inflatev(out, in + 2, insize - 2, settings);
- if (error) return error;
-
- if (!settings->ignore_adler32) {
- unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]);
- unsigned checksum = adler32(out->data, (unsigned)(out->size));
- if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/
- }
-
- return 0; /*no error*/
-}
-
-
-/*expected_size is expected output size, to avoid intermediate allocations. Set to 0 if not known. */
-static unsigned zlib_decompress(unsigned char** out, size_t* outsize, size_t expected_size, const unsigned char* in, size_t insize, const LodePNGDecompressSettings* settings)
-{
- if(settings->custom_zlib) {
- return settings->custom_zlib(out, outsize, in, insize, settings);
- } else {
- unsigned error;
- ucvector v = ucvector_init(*out, *outsize);
- if (expected_size) {
- /*reserve the memory to avoid intermediate reallocations*/
- ucvector_resize(&v, *outsize + expected_size);
- v.size = *outsize;
- }
- error = lodepng_zlib_decompressv(&v, in, insize, settings);
- *out = v.data;
- *outsize = v.size;
- return error;
- }
-}
-
-
-static void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings)
-{
- settings->ignore_adler32 = 0;
- settings->ignore_nlen = 0;
- settings->custom_zlib = 0;
- settings->custom_inflate = 0;
- settings->custom_context = 0;
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* ////////////////////////////////////////////////////////////////////////// */
-/* // End of Zlib related code. Begin of PNG related code. // */
-/* ////////////////////////////////////////////////////////////////////////// */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-
-#if 0 //thorvg don't use crc
-/* CRC polynomial: 0xedb88320 */
-static unsigned lodepng_crc32_table[256] = {
- 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u,
- 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u,
- 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u,
- 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u,
- 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u,
- 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u,
- 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u,
- 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u,
- 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u,
- 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u,
- 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u,
- 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u,
- 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u,
- 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u,
- 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u,
- 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u,
- 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u,
- 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u,
- 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u,
- 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u,
- 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,
- 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u,
- 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u,
- 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u,
- 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u,
- 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u,
- 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u,
- 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u,
- 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u,
- 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u,
- 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u,
- 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u
-};
-
-
-/* Calculate CRC32 of buffer
- Return the CRC of the bytes buf[0..len-1]. */
-static unsigned lodepng_crc32(const unsigned char* data, size_t length)
-{
- unsigned r = 0xffffffffu;
- size_t i;
- for (i = 0; i < length; ++i) {
- r = lodepng_crc32_table[(r ^ data[i]) & 0xffu] ^ (r >> 8u);
- }
- return r ^ 0xffffffffu;
-}
-#endif
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Reading and writing PNG color channel bits / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/* The color channel bits of less-than-8-bit pixels are read with the MSB of bytes first,
-so LodePNGBitWriter and LodePNGBitReader can't be used for those. */
-
-static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
-{
- unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
- ++(*bitpointer);
- return result;
-}
-
-
-/* TODO: make this faster */
-static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
-{
- unsigned result = 0;
- size_t i;
- for (i = 0 ; i < nbits; ++i) {
- result <<= 1u;
- result |= (unsigned)readBitFromReversedStream(bitpointer, bitstream);
- }
- return result;
-}
-
-
-static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
-{
- /*the current bit in bitstream may be 0 or 1 for this to work*/
- if (bit == 0) bitstream[(*bitpointer) >> 3u] &= (unsigned char)(~(1u << (7u - ((*bitpointer) & 7u))));
- else bitstream[(*bitpointer) >> 3u] |= (1u << (7u - ((*bitpointer) & 7u)));
- ++(*bitpointer);
-}
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / PNG chunks / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*
- The lodepng_chunk functions are normally not needed, except to traverse the
- unknown chunks stored in the LodePNGInfo struct, or add new ones to it.
- It also allows traversing the chunks of an encoded PNG file yourself.
-
- The chunk pointer always points to the beginning of the chunk itself, that is
- the first byte of the 4 length bytes.
-
- In the PNG file format, chunks have the following format:
- -4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer)
- -4 bytes chunk type (ASCII a-z,A-Z only, see below)
- -length bytes of data (may be 0 bytes if length was 0)
- -4 bytes of CRC, computed on chunk name + data
-
- The first chunk starts at the 8th byte of the PNG file, the entire rest of the file
- exists out of concatenated chunks with the above format.
-
- PNG standard chunk ASCII naming conventions:
- -First byte: uppercase = critical, lowercase = ancillary
- -Second byte: uppercase = public, lowercase = private
- -Third byte: must be uppercase
- -Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy
-*/
-
-
-/*
- Gets the length of the data of the chunk. Total chunk length has 12 bytes more.
- There must be at least 4 bytes to read from. If the result value is too large,
- it may be corrupt data.
-*/
-static unsigned lodepng_chunk_length(const unsigned char* chunk)
-{
- return lodepng_read32bitInt(&chunk[0]);
-}
-
-
-/* check if the type is the given type */
-static unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type)
-{
- if (lodepng_strlen(type) != 4) return 0;
- return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
-}
-
-
-/* 0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard) */
-static unsigned char lodepng_chunk_ancillary(const unsigned char* chunk)
-{
- return ((chunk[4] & 32) != 0);
-}
-
-
-static const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk)
-{
- return &chunk[8];
-}
-
-#if 0 //thorvg don't use crc
-/* returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!) */
-static unsigned lodepng_chunk_check_crc(const unsigned char* chunk)
-{
- unsigned length = lodepng_chunk_length(chunk);
- unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]);
- /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
- unsigned checksum = lodepng_crc32(&chunk[4], length + 4);
- if (CRC != checksum) return 1;
- else return 0;
-}
-#endif
-
-static const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end)
-{
- if (chunk >= end || end - chunk < 12) return end; /*too small to contain a chunk*/
- if (chunk[0] == 0x89 && chunk[1] == 0x50 && chunk[2] == 0x4e && chunk[3] == 0x47
- && chunk[4] == 0x0d && chunk[5] == 0x0a && chunk[6] == 0x1a && chunk[7] == 0x0a) {
- /* Is PNG magic header at start of PNG file. Jump to first actual chunk. */
- return chunk + 8;
- } else {
- size_t total_chunk_length;
- const unsigned char* result;
- if (lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return end;
- result = chunk + total_chunk_length;
- if (result < chunk) return end; /*pointer overflow*/
- return result;
- }
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / Color types, channels, bits / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-/*checks if the colortype is valid and the bitdepth bd is allowed for this colortype.
-Return value is a LodePNG error code.*/
-static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd)
-{
- switch(colortype) {
- case LCT_GREY: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break;
- case LCT_RGB: if(!( bd == 8 || bd == 16)) return 37; break;
- case LCT_PALETTE: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break;
- case LCT_GREY_ALPHA: if(!( bd == 8 || bd == 16)) return 37; break;
- case LCT_RGBA: if(!( bd == 8 || bd == 16)) return 37; break;
- case LCT_MAX_OCTET_VALUE: return 31; /* invalid color type */
- default: return 31; /* invalid color type */
- }
- return 0; /*allowed color type / bits combination*/
-}
-
-
-static unsigned getNumColorChannels(LodePNGColorType colortype)
-{
- switch(colortype) {
- case LCT_GREY: return 1;
- case LCT_RGB: return 3;
- case LCT_PALETTE: return 1;
- case LCT_GREY_ALPHA: return 2;
- case LCT_RGBA: return 4;
- case LCT_MAX_OCTET_VALUE: return 0; /* invalid color type */
- default: return 0; /*invalid color type*/
- }
-}
-
-
-static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth)
-{
- /*bits per pixel is amount of channels * bits per channel*/
- return getNumColorChannels(colortype) * bitdepth;
-}
-
-
-static void lodepng_color_mode_init(LodePNGColorMode* info)
-{
- info->key_defined = 0;
- info->key_r = info->key_g = info->key_b = 0;
- info->colortype = LCT_RGBA;
- info->bitdepth = 8;
- info->palette = 0;
- info->palettesize = 0;
-}
-
-
-/*allocates palette memory if needed, and initializes all colors to black*/
-static void lodepng_color_mode_alloc_palette(LodePNGColorMode* info)
-{
- size_t i;
- /*if the palette is already allocated, it will have size 1024 so no reallocation needed in that case*/
- /*the palette must have room for up to 256 colors with 4 bytes each.*/
- if (!info->palette) info->palette = (unsigned char*)malloc(1024);
- if (!info->palette) return; /*alloc fail*/
- for (i = 0; i != 256; ++i) {
- /*Initialize all unused colors with black, the value used for invalid palette indices.
- This is an error according to the PNG spec, but common PNG decoders make it black instead.
- That makes color conversion slightly faster due to no error handling needed.*/
- info->palette[i * 4 + 0] = 0;
- info->palette[i * 4 + 1] = 0;
- info->palette[i * 4 + 2] = 0;
- info->palette[i * 4 + 3] = 255;
- }
-}
-
-static void lodepng_palette_clear(LodePNGColorMode* info)
-{
- if (info->palette) free(info->palette);
- info->palette = 0;
- info->palettesize = 0;
-}
-
-
-static void lodepng_color_mode_cleanup(LodePNGColorMode* info)
-{
- lodepng_palette_clear(info);
-}
-
-
-/*return value is error code (0 means no error)*/
-static unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source)
-{
- lodepng_color_mode_cleanup(dest);
- lodepng_memcpy(dest, source, sizeof(LodePNGColorMode));
- if (source->palette) {
- dest->palette = (unsigned char*)malloc(1024);
- if (!dest->palette && source->palettesize) return 83; /*alloc fail*/
- lodepng_memcpy(dest->palette, source->palette, source->palettesize * 4);
- }
- return 0;
-}
-
-
-static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b)
-{
- size_t i;
- if (a->colortype != b->colortype) return 0;
- if (a->bitdepth != b->bitdepth) return 0;
- if (a->key_defined != b->key_defined) return 0;
- if (a->key_defined) {
- if(a->key_r != b->key_r) return 0;
- if(a->key_g != b->key_g) return 0;
- if(a->key_b != b->key_b) return 0;
- }
- if (a->palettesize != b->palettesize) return 0;
- for (i = 0; i != a->palettesize * 4; ++i) {
- if (a->palette[i] != b->palette[i]) return 0;
- }
- return 1;
-}
-
-
-static size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
-{
- size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth);
- size_t n = (size_t)w * (size_t)h;
- return ((n / 8u) * bpp) + ((n & 7u) * bpp + 7u) / 8u;
-}
-
-
-/* Returns the byte size of a raw image buffer with given width, height and color mode */
-static size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color)
-{
- return lodepng_get_raw_size_lct(w, h, color->colortype, color->bitdepth);
-}
-
-
-/*in an idat chunk, each scanline is a multiple of 8 bits, unlike the lodepng output buffer,
-and in addition has one extra byte per line: the filter byte. So this gives a larger
-result than lodepng_get_raw_size. Set h to 1 to get the size of 1 row including filter byte. */
-static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, unsigned bpp)
-{
- /* + 1 for the filter byte, and possibly plus padding bits per line. */
- /* Ignoring casts, the expression is equal to (w * bpp + 7) / 8 + 1, but avoids overflow of w * bpp */
- size_t line = ((size_t)(w / 8u) * bpp) + 1u + ((w & 7u) * bpp + 7u) / 8u;
- return (size_t)h * line;
-}
-
-
-/* Safely checks whether size_t overflow can be caused due to amount of pixels.
- This check is overcautious rather than precise. If this check indicates no overflow,
- you can safely compute in a size_t (but not an unsigned):
- -(size_t)w * (size_t)h * 8
- -amount of bytes in IDAT (including filter, padding and Adam7 bytes)
- -amount of bytes in raw color model
- Returns 1 if overflow possible, 0 if not. */
-static int lodepng_pixel_overflow(unsigned w, unsigned h, const LodePNGColorMode* pngcolor, const LodePNGColorMode* rawcolor)
-{
- size_t bpp = LODEPNG_MAX(lodepng_get_bpp_lct(pngcolor->colortype, pngcolor->bitdepth), lodepng_get_bpp_lct(rawcolor->colortype, rawcolor->bitdepth));
- size_t numpixels, total;
- size_t line; /* bytes per line in worst case */
-
- if (lodepng_mulofl((size_t)w, (size_t)h, &numpixels)) return 1;
- if (lodepng_mulofl(numpixels, 8, &total)) return 1; /* bit pointer with 8-bit color, or 8 bytes per channel color */
-
- /* Bytes per scanline with the expression "(w / 8u) * bpp) + ((w & 7u) * bpp + 7u) / 8u" */
- if (lodepng_mulofl((size_t)(w / 8u), bpp, &line)) return 1;
- if (lodepng_addofl(line, ((w & 7u) * bpp + 7u) / 8u, &line)) return 1;
-
- if (lodepng_addofl(line, 5, &line)) return 1; /* 5 bytes overhead per line: 1 filterbyte, 4 for Adam7 worst case */
- if (lodepng_mulofl(line, h, &total)) return 1; /* Total bytes in worst case */
-
- return 0; /* no overflow */
-}
-
-
-static void lodepng_info_init(LodePNGInfo* info)
-{
- lodepng_color_mode_init(&info->color);
- info->interlace_method = 0;
- info->compression_method = 0;
- info->filter_method = 0;
-}
-
-
-static void lodepng_info_cleanup(LodePNGInfo* info)
-{
- lodepng_color_mode_cleanup(&info->color);
-}
-
-
-/* index: bitgroup index, bits: bitgroup size(1, 2 or 4), in: bitgroup value, out: octet array to add bits to */
-static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in)
-{
- unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/
- /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
- unsigned p = index & m;
- in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/
- in = in << (bits * (m - p));
- if(p == 0) out[index * bits / 8u] = in;
- else out[index * bits / 8u] |= in;
-}
-
-/*
- One node of a color tree
- This is the data structure used to count the number of unique colors and to get a palette
- index for a color. It's like an octree, but because the alpha channel is used too, each
- node has 16 instead of 8 children.
-*/
-struct ColorTree
-{
- ColorTree* children[16]; /* up to 16 pointers to ColorTree of next level */
- int index; /* the payload. Only has a meaningful value if this is in the last level */
-};
-
-static void color_tree_init(ColorTree* tree)
-{
- lodepng_memset(tree->children, 0, 16 * sizeof(*tree->children));
- tree->index = -1;
-}
-
-static void color_tree_cleanup(ColorTree* tree)
-{
- int i;
- for (i = 0; i != 16; ++i) {
- if(tree->children[i]) {
- color_tree_cleanup(tree->children[i]);
- free(tree->children[i]);
- }
- }
-}
-
-
-/* returns -1 if color not present, its index otherwise */
-static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
- int bit = 0;
- for (bit = 0; bit < 8; ++bit) {
- int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
- if (!tree->children[i]) return -1;
- else tree = tree->children[i];
- }
- return tree ? tree->index : -1;
-}
-
-
-/* color is not allowed to already exist.
- Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")
- Returns error code, or 0 if ok */
-static unsigned color_tree_add(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a, unsigned index)
-{
- int bit;
- for (bit = 0; bit < 8; ++bit) {
- int i = 8 * ((r >> bit) & 1) + 4 * ((g >> bit) & 1) + 2 * ((b >> bit) & 1) + 1 * ((a >> bit) & 1);
- if (!tree->children[i]) {
- tree->children[i] = (ColorTree*)malloc(sizeof(ColorTree));
- if (!tree->children[i]) return 83; /*alloc fail*/
- color_tree_init(tree->children[i]);
- }
- tree = tree->children[i];
- }
- tree->index = (int)index;
- return 0;
-}
-
-/* put a pixel, given its RGBA color, into image of any color type */
-static unsigned rgba8ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, ColorTree* tree /*for palette*/, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
- if (mode->colortype == LCT_GREY) {
- unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/
- if (mode->bitdepth == 8) out[i] = gray;
- else if (mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = gray;
- else {
- /*take the most significant bits of gray*/
- gray = ((unsigned)gray >> (8u - mode->bitdepth)) & ((1u << mode->bitdepth) - 1u);
- addColorBits(out, i, mode->bitdepth, gray);
- }
- } else if (mode->colortype == LCT_RGB) {
- if (mode->bitdepth == 8) {
- out[i * 3 + 0] = r;
- out[i * 3 + 1] = g;
- out[i * 3 + 2] = b;
- } else {
- out[i * 6 + 0] = out[i * 6 + 1] = r;
- out[i * 6 + 2] = out[i * 6 + 3] = g;
- out[i * 6 + 4] = out[i * 6 + 5] = b;
- }
- } else if(mode->colortype == LCT_PALETTE) {
- int index = color_tree_get(tree, r, g, b, a);
- if (index < 0) return 82; /*color not in palette*/
- if (mode->bitdepth == 8) out[i] = index;
- else addColorBits(out, i, mode->bitdepth, (unsigned)index);
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- unsigned char gray = r; /*((unsigned short)r + g + b) / 3u;*/
- if (mode->bitdepth == 8) {
- out[i * 2 + 0] = gray;
- out[i * 2 + 1] = a;
- } else if (mode->bitdepth == 16) {
- out[i * 4 + 0] = out[i * 4 + 1] = gray;
- out[i * 4 + 2] = out[i * 4 + 3] = a;
- }
- } else if (mode->colortype == LCT_RGBA) {
- if (mode->bitdepth == 8) {
- out[i * 4 + 0] = r;
- out[i * 4 + 1] = g;
- out[i * 4 + 2] = b;
- out[i * 4 + 3] = a;
- } else {
- out[i * 8 + 0] = out[i * 8 + 1] = r;
- out[i * 8 + 2] = out[i * 8 + 3] = g;
- out[i * 8 + 4] = out[i * 8 + 5] = b;
- out[i * 8 + 6] = out[i * 8 + 7] = a;
- }
- }
- return 0; /*no error*/
-}
-
-
-/* put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type */
-static void rgba16ToPixel(unsigned char* out, size_t i, const LodePNGColorMode* mode, unsigned short r, unsigned short g, unsigned short b, unsigned short a)
-{
- if (mode->colortype == LCT_GREY) {
- unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/
- out[i * 2 + 0] = (gray >> 8) & 255;
- out[i * 2 + 1] = gray & 255;
- } else if (mode->colortype == LCT_RGB) {
- out[i * 6 + 0] = (r >> 8) & 255;
- out[i * 6 + 1] = r & 255;
- out[i * 6 + 2] = (g >> 8) & 255;
- out[i * 6 + 3] = g & 255;
- out[i * 6 + 4] = (b >> 8) & 255;
- out[i * 6 + 5] = b & 255;
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- unsigned short gray = r; /*((unsigned)r + g + b) / 3u;*/
- out[i * 4 + 0] = (gray >> 8) & 255;
- out[i * 4 + 1] = gray & 255;
- out[i * 4 + 2] = (a >> 8) & 255;
- out[i * 4 + 3] = a & 255;
- } else if (mode->colortype == LCT_RGBA) {
- out[i * 8 + 0] = (r >> 8) & 255;
- out[i * 8 + 1] = r & 255;
- out[i * 8 + 2] = (g >> 8) & 255;
- out[i * 8 + 3] = g & 255;
- out[i * 8 + 4] = (b >> 8) & 255;
- out[i * 8 + 5] = b & 255;
- out[i * 8 + 6] = (a >> 8) & 255;
- out[i * 8 + 7] = a & 255;
- }
-}
-
-
-/* Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type. */
-static void getPixelColorRGBA8(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode)
-{
- if (mode->colortype == LCT_GREY) {
- if (mode->bitdepth == 8) {
- *r = *g = *b = in[i];
- if (mode->key_defined && *r == mode->key_r) *a = 0;
- else *a = 255;
- } else if (mode->bitdepth == 16) {
- *r = *g = *b = in[i * 2 + 0];
- if (mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
- else *a = 255;
- } else {
- unsigned highest = ((1U << mode->bitdepth) - 1U); /* highest possible value for this bit depth */
- size_t j = i * mode->bitdepth;
- unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
- *r = *g = *b = (value * 255) / highest;
- if (mode->key_defined && value == mode->key_r) *a = 0;
- else *a = 255;
- }
- } else if (mode->colortype == LCT_RGB) {
- if (mode->bitdepth == 8) {
- *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2];
- if (mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0;
- else *a = 255;
- } else {
- *r = in[i * 6 + 0];
- *g = in[i * 6 + 2];
- *b = in[i * 6 + 4];
- if (mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
- && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
- && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
- else *a = 255;
- }
- } else if (mode->colortype == LCT_PALETTE) {
- unsigned index;
- if (mode->bitdepth == 8) index = in[i];
- else {
- size_t j = i * mode->bitdepth;
- index = readBitsFromReversedStream(&j, in, mode->bitdepth);
- }
- /* out of bounds of palette not checked: see lodepng_color_mode_alloc_palette. */
- *r = mode->palette[index * 4 + 0];
- *g = mode->palette[index * 4 + 1];
- *b = mode->palette[index * 4 + 2];
- *a = mode->palette[index * 4 + 3];
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- if (mode->bitdepth == 8) {
- *r = *g = *b = in[i * 2 + 0];
- *a = in[i * 2 + 1];
- } else {
- *r = *g = *b = in[i * 4 + 0];
- *a = in[i * 4 + 2];
- }
- } else if (mode->colortype == LCT_RGBA) {
- if (mode->bitdepth == 8) {
- *r = in[i * 4 + 0];
- *g = in[i * 4 + 1];
- *b = in[i * 4 + 2];
- *a = in[i * 4 + 3];
- } else {
- *r = in[i * 8 + 0];
- *g = in[i * 8 + 2];
- *b = in[i * 8 + 4];
- *a = in[i * 8 + 6];
- }
- }
-}
-
-
-/* Similar to getPixelColorRGBA8, but with all the for loops inside of the color
- mode test cases, optimized to convert the colors much faster, when converting
- to the common case of RGBA with 8 bit per channel. buffer must be RGBA with
- enough memory.*/
-static void getPixelColorsRGBA8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, const unsigned char* LODEPNG_RESTRICT in, const LodePNGColorMode* mode)
-{
- unsigned num_channels = 4;
- size_t i;
- if (mode->colortype == LCT_GREY) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i];
- buffer[3] = 255;
- }
- if (mode->key_defined) {
- buffer -= numpixels * num_channels;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- if(buffer[0] == mode->key_r) buffer[3] = 0;
- }
- }
- } else if (mode->bitdepth == 16) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 2];
- buffer[3] = mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r ? 0 : 255;
- }
- } else {
- unsigned highest = ((1U << mode->bitdepth) - 1U); /* highest possible value for this bit depth */
- size_t j = 0;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
- buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;
- buffer[3] = mode->key_defined && value == mode->key_r ? 0 : 255;
- }
- }
- } else if (mode->colortype == LCT_RGB) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- //lodepng_memcpy(buffer, &in[i * 3], 3);
- //Convert colortype to LCT_BGR?
- buffer[0] = in[i * 3 + 2];
- buffer[1] = in[i * 3 + 1];
- buffer[2] = in[i * 3 + 0];
- buffer[3] = 255;
- }
- if (mode->key_defined) {
- buffer -= numpixels * num_channels;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- if (buffer[0] == mode->key_r && buffer[1]== mode->key_g && buffer[2] == mode->key_b) buffer[3] = 0;
- }
- }
- } else {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = in[i * 6 + 0];
- buffer[1] = in[i * 6 + 2];
- buffer[2] = in[i * 6 + 4];
- buffer[3] = mode->key_defined
- && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
- && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
- && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b ? 0 : 255;
- }
- }
- } else if (mode->colortype == LCT_PALETTE) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned index = in[i];
- /* out of bounds of palette not checked: see lodepng_color_mode_alloc_palette. */
- lodepng_memcpy(buffer, &mode->palette[index * 4], 4);
- }
- } else {
- size_t j = 0;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth);
- /* out of bounds of palette not checked: see lodepng_color_mode_alloc_palette. */
- lodepng_memcpy(buffer, &mode->palette[index * 4], 4);
- }
- }
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];
- buffer[3] = in[i * 2 + 1];
- }
- } else {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];
- buffer[3] = in[i * 4 + 2];
- }
- }
- } else if (mode->colortype == LCT_RGBA) {
- if (mode->bitdepth == 8) {
- lodepng_memcpy(buffer, in, numpixels * 4);
- } else {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = in[i * 8 + 0];
- buffer[1] = in[i * 8 + 2];
- buffer[2] = in[i * 8 + 4];
- buffer[3] = in[i * 8 + 6];
- }
- }
- }
-}
-
-
-/* Similar to getPixelColorsRGBA8, but with 3-channel RGB output. */
-static void getPixelColorsRGB8(unsigned char* LODEPNG_RESTRICT buffer, size_t numpixels, const unsigned char* LODEPNG_RESTRICT in, const LodePNGColorMode* mode)
-{
- const unsigned num_channels = 3;
- size_t i;
- if (mode->colortype == LCT_GREY) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i];
- }
- } else if (mode->bitdepth == 16) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 2];
- }
- } else {
- unsigned highest = ((1U << mode->bitdepth) - 1U); /* highest possible value for this bit depth */
- size_t j = 0;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
- buffer[0] = buffer[1] = buffer[2] = (value * 255) / highest;
- }
- }
- } else if (mode->colortype == LCT_RGB) {
- if (mode->bitdepth == 8) {
- lodepng_memcpy(buffer, in, numpixels * 3);
- } else {
- for(i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = in[i * 6 + 0];
- buffer[1] = in[i * 6 + 2];
- buffer[2] = in[i * 6 + 4];
- }
- }
- } else if (mode->colortype == LCT_PALETTE) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned index = in[i];
- /* out of bounds of palette not checked: see lodepng_color_mode_alloc_palette. */
- lodepng_memcpy(buffer, &mode->palette[index * 4], 3);
- }
- } else {
- size_t j = 0;
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- unsigned index = readBitsFromReversedStream(&j, in, mode->bitdepth);
- /* out of bounds of palette not checked: see lodepng_color_mode_alloc_palette. */
- lodepng_memcpy(buffer, &mode->palette[index * 4], 3);
- }
- }
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- if (mode->bitdepth == 8) {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 2 + 0];
- }
- } else {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = buffer[1] = buffer[2] = in[i * 4 + 0];
- }
- }
- } else if (mode->colortype == LCT_RGBA) {
- if (mode->bitdepth == 8) {
- for(i = 0; i != numpixels; ++i, buffer += num_channels) {
- lodepng_memcpy(buffer, &in[i * 4], 3);
- }
- } else {
- for (i = 0; i != numpixels; ++i, buffer += num_channels) {
- buffer[0] = in[i * 8 + 0];
- buffer[1] = in[i * 8 + 2];
- buffer[2] = in[i * 8 + 4];
- }
- }
- }
-}
-
-
-/* Get RGBA16 color of pixel with index i (y * width + x) from the raw image with
- given color type, but the given color type must be 16-bit itself. */
-static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a, const unsigned char* in, size_t i, const LodePNGColorMode* mode)
-{
- if (mode->colortype == LCT_GREY) {
- *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1];
- if (mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
- else *a = 65535;
- } else if (mode->colortype == LCT_RGB) {
- *r = 256u * in[i * 6 + 0] + in[i * 6 + 1];
- *g = 256u * in[i * 6 + 2] + in[i * 6 + 3];
- *b = 256u * in[i * 6 + 4] + in[i * 6 + 5];
- if (mode->key_defined
- && 256u * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
- && 256u * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
- && 256u * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
- else *a = 65535;
- } else if (mode->colortype == LCT_GREY_ALPHA) {
- *r = *g = *b = 256u * in[i * 4 + 0] + in[i * 4 + 1];
- *a = 256u * in[i * 4 + 2] + in[i * 4 + 3];
- } else if (mode->colortype == LCT_RGBA) {
- *r = 256u * in[i * 8 + 0] + in[i * 8 + 1];
- *g = 256u * in[i * 8 + 2] + in[i * 8 + 3];
- *b = 256u * in[i * 8 + 4] + in[i * 8 + 5];
- *a = 256u * in[i * 8 + 6] + in[i * 8 + 7];
- }
-}
-
-/*
- Converts raw buffer from one color type to another color type, based on
- LodePNGColorMode structs to describe the input and output color type.
- See the reference manual at the end of this header file to see which color conversions are supported.
- return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported)
- The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel
- of the output color type (lodepng_get_bpp).
- For < 8 bpp images, there should not be padding bits at the end of scanlines.
- For 16-bit per channel colors, uses big endian format like PNG does.
- Return value is LodePNG error code
-*/
-static unsigned lodepng_convert(unsigned char* out, const unsigned char* in, const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h)
-{
- size_t i;
- ColorTree tree;
- size_t numpixels = (size_t)w * (size_t)h;
- unsigned error = 0;
-
- if (mode_in->colortype == LCT_PALETTE && !mode_in->palette) {
- return 107; /* error: must provide palette if input mode is palette */
- }
-
- if (lodepng_color_mode_equal(mode_out, mode_in)) {
- size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
- lodepng_memcpy(out, in, numbytes);
- return 0;
- }
-
- if (mode_out->colortype == LCT_PALETTE) {
- size_t palettesize = mode_out->palettesize;
- const unsigned char* palette = mode_out->palette;
- size_t palsize = (size_t)1u << mode_out->bitdepth;
- /* if the user specified output palette but did not give the values, assume
- they want the values of the input color type (assuming that one is palette).
- Note that we never create a new palette ourselves.*/
- if (palettesize == 0) {
- palettesize = mode_in->palettesize;
- palette = mode_in->palette;
- /* if the input was also palette with same bitdepth, then the color types are also
- equal, so copy literally. This to preserve the exact indices that were in the PNG
- even in case there are duplicate colors in the palette.*/
- if (mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) {
- size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
- lodepng_memcpy(out, in, numbytes);
- return 0;
- }
- }
- if (palettesize < palsize) palsize = palettesize;
- color_tree_init(&tree);
- for (i = 0; i != palsize; ++i) {
- const unsigned char* p = &palette[i * 4];
- error = color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i);
- if (error) break;
- }
- }
-
- if (!error) {
- if (mode_in->bitdepth == 16 && mode_out->bitdepth == 16) {
- for (i = 0; i != numpixels; ++i) {
- unsigned short r = 0, g = 0, b = 0, a = 0;
- getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);
- rgba16ToPixel(out, i, mode_out, r, g, b, a);
- }
- } else if (mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) {
- getPixelColorsRGBA8(out, numpixels, in, mode_in);
- } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) {
- getPixelColorsRGB8(out, numpixels, in, mode_in);
- } else {
- unsigned char r = 0, g = 0, b = 0, a = 0;
- for (i = 0; i != numpixels; ++i) {
- getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);
- error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a);
- if (error) break;
- }
- }
- }
-
- if (mode_out->colortype == LCT_PALETTE) {
- color_tree_cleanup(&tree);
- }
-
- return error;
-}
-
-
-/* Paeth predictor, used by PNG filter type 4
- The parameters are of type short, but should come from unsigned chars, the shorts
- are only needed to make the paeth calculation correct.
-*/
-static unsigned char paethPredictor(short a, short b, short c)
-{
- short pa = LODEPNG_ABS(b - c);
- short pb = LODEPNG_ABS(a - c);
- short pc = LODEPNG_ABS(a + b - c - c);
- /* return input value associated with smallest of pa, pb, pc (with certain priority if equal) */
- if (pb < pa) { a = b; pa = pb; }
- return (pc < pa) ? c : a;
-}
-
-
-/*shared values used by multiple Adam7 related functions*/
-static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
-static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
-static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
-static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
-
-/* Outputs various dimensions and positions in the image related to the Adam7 reduced images.
- passw: output containing the width of the 7 passes
- passh: output containing the height of the 7 passes
- filter_passstart: output containing the index of the start and end of each
- reduced image with filter bytes
- padded_passstart output containing the index of the start and end of each
- reduced image when without filter bytes but with padded scanlines
- passstart: output containing the index of the start and end of each reduced
- image without padding between scanlines, but still padding between the images
- w, h: width and height of non-interlaced image
- bpp: bits per pixel
- "padded" is only relevant if bpp is less than 8 and a scanline or image does not
- end at a full byte */
-static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8], size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp)
-{
- /* the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass */
- unsigned i;
-
- /* calculate width and height in pixels of each pass */
- for (i = 0; i != 7; ++i) {
- passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
- passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
- if(passw[i] == 0) passh[i] = 0;
- if(passh[i] == 0) passw[i] = 0;
- }
-
- filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
- for (i = 0; i != 7; ++i) {
- /* if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte) */
- filter_passstart[i + 1] = filter_passstart[i]
- + ((passw[i] && passh[i]) ? passh[i] * (1u + (passw[i] * bpp + 7u) / 8u) : 0);
- /* bits padded if needed to fill full byte at end of each scanline */
- padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7u) / 8u);
- /* only padded at end of reduced image */
- passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7u) / 8u;
- }
-}
-
-
-/* ////////////////////////////////////////////////////////////////////////// */
-/* / PNG Decoder / */
-/* ////////////////////////////////////////////////////////////////////////// */
-
-static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned char filterType, size_t length)
-{
- /* For PNG filter method 0
- unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte,
- the filter works byte per byte (bytewidth = 1)
- precon is the previous unfiltered scanline, recon the result, scanline the current one
- the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
- recon and scanline MAY be the same memory address! precon must be disjoint. */
-
- size_t i;
- switch (filterType) {
- case 0: {
- if (bytewidth == 4) {
- for (i = 0; i < length; i += 4) {
- //RGBA -> BGRA
- recon[i + 0] = scanline[i + 2];
- recon[i + 1] = scanline[i + 1];
- recon[i + 2] = scanline[i + 0];
- recon[i + 3] = scanline[i + 3];
- }
- } else {
- for (i = 0; i != length; ++i) recon[i] = scanline[i];
- }
- break;
- }
- case 1: {
- for (i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
- for (i = bytewidth; i < length; ++i) recon[i] = scanline[i] + recon[i - bytewidth];
- break;
- }
- case 2: {
- if (precon) {
- for (i = 0; i != length; ++i) recon[i] = scanline[i] + precon[i];
- } else {
- for (i = 0; i != length; ++i) recon[i] = scanline[i];
- }
- break;
- }
- case 3: {
- if (precon) {
- for (i = 0; i != bytewidth; ++i) recon[i] = scanline[i] + (precon[i] >> 1u);
- for (i = bytewidth; i < length; ++i) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) >> 1u);
- } else {
- for (i = 0; i != bytewidth; ++i) recon[i] = scanline[i];
- for (i = bytewidth; i < length; ++i) recon[i] = scanline[i] + (recon[i - bytewidth] >> 1u);
- }
- break;
- }
- case 4: {
- if (precon) {
- for (i = 0; i != bytewidth; ++i) {
- recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
- }
-
- /* Unroll independent paths of the paeth predictor. A 6x and 8x version would also be possible but that
- adds too much code. Whether this actually speeds anything up at all depends on compiler and settings. */
- if (bytewidth >= 4) {
- for (; i + 3 < length; i += 4) {
- size_t j = i - bytewidth;
- unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2], s3 = scanline[i + 3];
- unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2], r3 = recon[j + 3];
- unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2], p3 = precon[i + 3];
- unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2], q3 = precon[j + 3];
- recon[i + 0] = s0 + paethPredictor(r0, p0, q0);
- recon[i + 1] = s1 + paethPredictor(r1, p1, q1);
- recon[i + 2] = s2 + paethPredictor(r2, p2, q2);
- recon[i + 3] = s3 + paethPredictor(r3, p3, q3);
- }
- } else if (bytewidth >= 3) {
- for (; i + 2 < length; i += 3) {
- size_t j = i - bytewidth;
- unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1], s2 = scanline[i + 2];
- unsigned char r0 = recon[j + 0], r1 = recon[j + 1], r2 = recon[j + 2];
- unsigned char p0 = precon[i + 0], p1 = precon[i + 1], p2 = precon[i + 2];
- unsigned char q0 = precon[j + 0], q1 = precon[j + 1], q2 = precon[j + 2];
- recon[i + 0] = s0 + paethPredictor(r0, p0, q0);
- recon[i + 1] = s1 + paethPredictor(r1, p1, q1);
- recon[i + 2] = s2 + paethPredictor(r2, p2, q2);
- }
- } else if (bytewidth >= 2) {
- for (; i + 1 < length; i += 2) {
- size_t j = i - bytewidth;
- unsigned char s0 = scanline[i + 0], s1 = scanline[i + 1];
- unsigned char r0 = recon[j + 0], r1 = recon[j + 1];
- unsigned char p0 = precon[i + 0], p1 = precon[i + 1];
- unsigned char q0 = precon[j + 0], q1 = precon[j + 1];
- recon[i + 0] = s0 + paethPredictor(r0, p0, q0);
- recon[i + 1] = s1 + paethPredictor(r1, p1, q1);
- }
- }
-
- for (; i != length; ++i) {
- recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
- }
- } else {
- for (i = 0; i != bytewidth; ++i) {
- recon[i] = scanline[i];
- }
- for (i = bytewidth; i < length; ++i) {
- /* paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth] */
- recon[i] = (scanline[i] + recon[i - bytewidth]);
- }
- }
- break;
- }
- default: return 36; /* error: invalid filter type given */
- }
- return 0;
-}
-
-
-static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
-{
- /* For PNG filter method 0
- this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times)
- out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
- w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
- in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes) */
-
- unsigned y;
- unsigned char* prevline = 0;
-
- /* bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise */
- size_t bytewidth = (bpp + 7u) / 8u;
- /* the width of a scanline in bytes, not including the filter type */
- size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u;
-
- for (y = 0; y < h; ++y) {
- size_t outindex = linebytes * y;
- size_t inindex = (1 + linebytes) * y; /* the extra filterbyte added to each row */
- unsigned char filterType = in[inindex];
- CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes));
- prevline = &out[outindex];
- }
-
- return 0;
-}
-
-/* in: Adam7 interlaced image, with no padding bits between scanlines, but between
- reduced images so that each reduced image starts at a byte.
- out: the same pixels, but re-ordered so that they're now a non-interlaced image with size w*h
- bpp: bits per pixel
- out has the following size in bits: w * h * bpp.
- in is possibly bigger due to padding bits between reduced images.
- out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation
- (because that's likely a little bit faster)
- NOTE: comments about padding bits are only relevant if bpp < 8 */
-static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
-{
- unsigned passw[7], passh[7];
- size_t filter_passstart[8], padded_passstart[8], passstart[8];
- unsigned i;
-
- Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
- if (bpp >= 8) {
- for(i = 0; i != 7; ++i) {
- unsigned x, y, b;
- size_t bytewidth = bpp / 8u;
- for (y = 0; y < passh[i]; ++y)
- for (x = 0; x < passw[i]; ++x) {
- size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
- size_t pixeloutstart = ((ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * (size_t)w + ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bytewidth;
- for (b = 0; b < bytewidth; ++b) {
- out[pixeloutstart + b] = in[pixelinstart + b];
- }
- }
- }
- } else /* bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers */ {
- for (i = 0; i != 7; ++i) {
- unsigned x, y, b;
- unsigned ilinebits = bpp * passw[i];
- unsigned olinebits = bpp * w;
- size_t obp, ibp; /* bit pointers (for out and in buffer) */
- for (y = 0; y < passh[i]; ++y)
- for (x = 0; x < passw[i]; ++x) {
- ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
- obp = (ADAM7_IY[i] + (size_t)y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + (size_t)x * ADAM7_DX[i]) * bpp;
- for (b = 0; b < bpp; ++b) {
- unsigned char bit = readBitFromReversedStream(&ibp, in);
- setBitOfReversedStream(&obp, out, bit);
- }
- }
- }
- }
-}
-
-
-static void removePaddingBits(unsigned char* out, const unsigned char* in, size_t olinebits, size_t ilinebits, unsigned h)
-{
- /* After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need
- to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers
- for the Adam7 code, the color convert code and the output to the user.
- in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must
- have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
- also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
- only useful if (ilinebits - olinebits) is a value in the range 1..7 */
- unsigned y;
- size_t diff = ilinebits - olinebits;
- size_t ibp = 0, obp = 0; /*input and output bit pointers*/
- for (y = 0; y < h; ++y) {
- size_t x;
- for (x = 0; x < olinebits; ++x) {
- unsigned char bit = readBitFromReversedStream(&ibp, in);
- setBitOfReversedStream(&obp, out, bit);
- }
- ibp += diff;
- }
-}
-
-
-/* out must be buffer big enough to contain full image, and in must contain the full decompressed data from
- the IDAT chunks (with filter index bytes and possible padding bits)
- return value is error */
-static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, unsigned w, unsigned h, const LodePNGInfo* info_png)
-{
- /* This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype.
- Steps:
- *) if no Adam7: 1) unfilter 2) remove padding bits (= possible extra bits per scanline if bpp < 8)
- *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
- NOTE: the in buffer will be overwritten with intermediate data! */
- unsigned bpp = lodepng_get_bpp_lct(info_png->color.colortype, info_png->color.bitdepth);
- if (bpp == 0) return 31; /* error: invalid colortype */
-
- if (info_png->interlace_method == 0) {
- if (bpp < 8 && w * bpp != ((w * bpp + 7u) / 8u) * 8u) {
- CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));
- removePaddingBits(out, in, w * bpp, ((w * bpp + 7u) / 8u) * 8u, h);
- }
- /* we can immediately filter into the out buffer, no other steps needed */
- else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));
- } else /* interlace_method is 1 (Adam7) */ {
- unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
- unsigned i;
-
- Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
-
- for (i = 0; i != 7; ++i) {
- CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp));
- /* TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline,
- move bytes instead of bits or move not at all */
- if (bpp < 8) {
- /* remove padding bits in scanlines; after this there still may be padding
- bits between the different reduced images: each reduced image still starts nicely at a byte */
- removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp, ((passw[i] * bpp + 7u) / 8u) * 8u, passh[i]);
- }
- }
- Adam7_deinterlace(out, in, w, h, bpp);
- }
- return 0;
-}
-
-
-static unsigned readChunk_PLTE(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
-{
- unsigned pos = 0, i;
- color->palettesize = chunkLength / 3u;
- if (color->palettesize == 0 || color->palettesize > 256) return 38; /* error: palette too small or big */
- lodepng_color_mode_alloc_palette(color);
- if (!color->palette && color->palettesize) {
- color->palettesize = 0;
- return 83; /* alloc fail */
- }
-
- for (i = 0; i != color->palettesize; ++i) {
- color->palette[4 * i + 0] = data[pos++]; /*R*/
- color->palette[4 * i + 1] = data[pos++]; /*G*/
- color->palette[4 * i + 2] = data[pos++]; /*B*/
- color->palette[4 * i + 3] = 255; /*alpha*/
- }
-
- return 0; /* OK */
-}
-
-
-static unsigned readChunk_tRNS(LodePNGColorMode* color, const unsigned char* data, size_t chunkLength)
-{
- unsigned i;
- if (color->colortype == LCT_PALETTE) {
- /* error: more alpha values given than there are palette entries */
- if (chunkLength > color->palettesize) return 39;
-
- for (i = 0; i != chunkLength; ++i) color->palette[4 * i + 3] = data[i];
- } else if (color->colortype == LCT_GREY) {
- /* error: this chunk must be 2 bytes for grayscale image */
- if (chunkLength != 2) return 30;
-
- color->key_defined = 1;
- color->key_r = color->key_g = color->key_b = 256u * data[0] + data[1];
- } else if (color->colortype == LCT_RGB) {
- /* error: this chunk must be 6 bytes for RGB image */
- if (chunkLength != 6) return 41;
-
- color->key_defined = 1;
- color->key_r = 256u * data[0] + data[1];
- color->key_g = 256u * data[2] + data[3];
- color->key_b = 256u * data[4] + data[5];
- }
- else return 42; /* error: tRNS chunk not allowed for other color models */
-
- return 0; /* OK */
-}
-
-
-/* read a PNG, the result will be in the same color type as the PNG (hence "generic") */
-static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize)
-{
- unsigned char IEND = 0;
- const unsigned char* chunk;
- unsigned char* idat; /*the data from idat chunks, zlib compressed*/
- size_t idatsize = 0;
- unsigned char* scanlines = 0;
- size_t scanlines_size = 0, expected_size = 0;
- size_t outsize = 0;
-
- /* safe output values in case error happens */
- *out = 0;
- *w = *h = 0;
-
- state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
- if (state->error) return;
-
- if (lodepng_pixel_overflow(*w, *h, &state->info_png.color, &state->info_raw)) {
- CERROR_RETURN(state->error, 92); /*overflow possible due to amount of pixels*/
- }
-
- /*the input filesize is a safe upper bound for the sum of idat chunks size*/
- idat = (unsigned char*)malloc(insize);
- if (!idat) CERROR_RETURN(state->error, 83); /*alloc fail*/
-
- chunk = &in[33]; /*first byte of the first chunk after the header*/
-
- /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
- IDAT data is put at the start of the in buffer*/
- while (!IEND && !state->error) {
- unsigned chunkLength;
- const unsigned char* data; /*the data in the chunk*/
-
- /*error: size of the in buffer too small to contain next chunk*/
- if ((size_t)((chunk - in) + 12) > insize || chunk < in) {
- if (state->decoder.ignore_end) break; /*other errors may still happen though*/
- CERROR_BREAK(state->error, 30);
- }
-
- /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
- chunkLength = lodepng_chunk_length(chunk);
- /*error: chunk length larger than the max PNG chunk size*/
- if (chunkLength > 2147483647) {
- if (state->decoder.ignore_end) break; /*other errors may still happen though*/
- CERROR_BREAK(state->error, 63);
- }
-
- if ((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in) {
- CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
- }
-
- data = lodepng_chunk_data_const(chunk);
-
- /*for unknown chunk order*/
- //unsigned unknown = 0;
-
- /*IDAT chunk, containing compressed image data*/
- if (lodepng_chunk_type_equals(chunk, "IDAT")) {
- size_t newsize;
- if (lodepng_addofl(idatsize, chunkLength, &newsize)) CERROR_BREAK(state->error, 95);
- if (newsize > insize) CERROR_BREAK(state->error, 95);
- lodepng_memcpy(idat + idatsize, data, chunkLength);
- idatsize += chunkLength;
- } else if (lodepng_chunk_type_equals(chunk, "IEND")) {
- /*IEND chunk*/
- IEND = 1;
- } else if (lodepng_chunk_type_equals(chunk, "PLTE")) {
- /*palette chunk (PLTE)*/
- state->error = readChunk_PLTE(&state->info_png.color, data, chunkLength);
- if (state->error) break;
- } else if (lodepng_chunk_type_equals(chunk, "tRNS")) {
- /*palette transparency chunk (tRNS). Even though this one is an ancillary chunk , it is still compiled
- in without 'LODEPNG_COMPILE_ANCILLARY_CHUNKS' because it contains essential color information that
- affects the alpha channel of pixels. */
- state->error = readChunk_tRNS(&state->info_png.color, data, chunkLength);
- if (state->error) break;
- } else /*it's not an implemented chunk type, so ignore it: skip over the data*/ {
- /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
- if (!state->decoder.ignore_critical && !lodepng_chunk_ancillary(chunk)) {
- CERROR_BREAK(state->error, 69);
- }
- //unknown = 1;
- }
-
-#if 0 //We don't use CRC
- if (!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/ {
- if (lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/
- }
-#endif
- if (!IEND) chunk = lodepng_chunk_next_const(chunk, in + insize);
- }
-
- if (state->info_png.color.colortype == LCT_PALETTE && !state->info_png.color.palette) {
- state->error = 106; /* error: PNG file must have PLTE chunk if color type is palette */
- }
-
- if (!state->error) {
- /*predict output size, to allocate exact size for output buffer to avoid more dynamic allocation.
- If the decompressed size does not match the prediction, the image must be corrupt.*/
- if (state->info_png.interlace_method == 0) {
- size_t bpp = lodepng_get_bpp_lct(state->info_png.color.colortype, state->info_png.color.bitdepth);
- expected_size = lodepng_get_raw_size_idat(*w, *h, bpp);
- } else {
- size_t bpp = lodepng_get_bpp_lct(state->info_png.color.colortype, state->info_png.color.bitdepth);
- /*Adam-7 interlaced: expected size is the sum of the 7 sub-images sizes*/
- expected_size = 0;
- expected_size += lodepng_get_raw_size_idat((*w + 7) >> 3, (*h + 7) >> 3, bpp);
- if (*w > 4) expected_size += lodepng_get_raw_size_idat((*w + 3) >> 3, (*h + 7) >> 3, bpp);
- expected_size += lodepng_get_raw_size_idat((*w + 3) >> 2, (*h + 3) >> 3, bpp);
- if (*w > 2) expected_size += lodepng_get_raw_size_idat((*w + 1) >> 2, (*h + 3) >> 2, bpp);
- expected_size += lodepng_get_raw_size_idat((*w + 1) >> 1, (*h + 1) >> 2, bpp);
- if (*w > 1) expected_size += lodepng_get_raw_size_idat((*w + 0) >> 1, (*h + 1) >> 1, bpp);
- expected_size += lodepng_get_raw_size_idat((*w + 0), (*h + 0) >> 1, bpp);
- }
- state->error = zlib_decompress(&scanlines, &scanlines_size, expected_size, idat, idatsize, &state->decoder.zlibsettings);
- }
-
- if (!state->error && scanlines_size != expected_size) state->error = 91; /*decompressed size doesn't match prediction*/
- free(idat);
-
- if (!state->error) {
- outsize = lodepng_get_raw_size(*w, *h, &state->info_png.color);
- *out = (unsigned char*)malloc(outsize);
- if (!*out) state->error = 83; /*alloc fail*/
- }
- if (!state->error) {
- lodepng_memset(*out, 0, outsize);
- state->error = postProcessScanlines(*out, scanlines, *w, *h, &state->info_png);
- }
- free(scanlines);
-}
-
-
-static void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings)
-{
- settings->color_convert = 1;
- settings->ignore_crc = 0;
- settings->ignore_critical = 0;
- settings->ignore_end = 0;
- lodepng_decompress_settings_init(&settings->zlibsettings);
-}
-
-
-/************************************************************************/
-/* External Class Implementation */
-/************************************************************************/
-
-/*read the information from the header and store it in the LodePNGInfo. return value is error*/
-unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize)
-{
- unsigned width, height;
- LodePNGInfo* info = &state->info_png;
- if (insize == 0 || in == 0) {
- CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/
- }
- if (insize < 33) {
- CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/
- }
-
- /* when decoding a new PNG image, make sure all parameters created after previous decoding are reset */
- /* TODO: remove this. One should use a new LodePNGState for new sessions */
- lodepng_info_cleanup(info);
- lodepng_info_init(info);
-
- if (in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) {
- CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/
- }
- if (lodepng_chunk_length(in + 8) != 13) {
- CERROR_RETURN_ERROR(state->error, 94); /*error: header size must be 13 bytes*/
- }
- if (!lodepng_chunk_type_equals(in + 8, "IHDR")) {
- CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/
- }
-
- /*read the values given in the header*/
- width = lodepng_read32bitInt(&in[16]);
- height = lodepng_read32bitInt(&in[20]);
- /*TODO: remove the undocumented feature that allows to give null pointers to width or height*/
- if (w) *w = width;
- if (h) *h = height;
- info->color.bitdepth = in[24];
- info->color.colortype = (LodePNGColorType)in[25];
- info->compression_method = in[26];
- info->filter_method = in[27];
- info->interlace_method = in[28];
-
- /*errors returned only after the parsing so other values are still output*/
-
- /*error: invalid image size*/
- if (width == 0 || height == 0) CERROR_RETURN_ERROR(state->error, 93);
- /*error: invalid colortype or bitdepth combination*/
- state->error = checkColorValidity(info->color.colortype, info->color.bitdepth);
- if (state->error) return state->error;
- /*error: only compression method 0 is allowed in the specification*/
- if (info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32);
- /*error: only filter method 0 is allowed in the specification*/
- if (info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33);
- /*error: only interlace methods 0 and 1 exist in the specification*/
- if (info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34);
-
-#if 0 //thorvg don't use crc
- if (!state->decoder.ignore_crc) {
- unsigned CRC = lodepng_read32bitInt(&in[29]);
- unsigned checksum = lodepng_crc32(&in[12], 17);
- if (CRC != checksum) {
- CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/
- }
- }
-#endif
- return state->error;
-}
-
-
-unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize)
-{
- *out = 0;
- decodeGeneric(out, w, h, state, in, insize);
- if (state->error) return state->error;
- if (!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color)) {
- /*same color type, no copying or converting of data needed*/
- /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype
- the raw image has to the end user*/
- if (!state->decoder.color_convert) {
- state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color);
- if (state->error) return state->error;
- }
- } else { /*color conversion needed*/
- unsigned char* data = *out;
- size_t outsize;
-
- /*TODO: check if this works according to the statement in the documentation: "The converter can convert
- from grayscale input color type, to 8-bit grayscale or grayscale with alpha"*/
- if (!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA) && !(state->info_raw.bitdepth == 8)) {
- return 56; /*unsupported color mode conversion*/
- }
-
- outsize = lodepng_get_raw_size(*w, *h, &state->info_raw);
- *out = (unsigned char*)malloc(outsize);
- if (!(*out)) {
- state->error = 83; /*alloc fail*/
- }
- else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h);
- free(data);
- }
- return state->error;
-}
-
-
-void lodepng_state_init(LodePNGState* state)
-{
- lodepng_decoder_settings_init(&state->decoder);
- lodepng_color_mode_init(&state->info_raw);
- lodepng_info_init(&state->info_png);
- state->error = 1;
-}
-
-
-void lodepng_state_cleanup(LodePNGState* state)
-{
- lodepng_color_mode_cleanup(&state->info_raw);
- lodepng_info_cleanup(&state->info_png);
-}
diff --git a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h b/thirdparty/thorvg/src/loaders/png/tvgLodePng.h
deleted file mode 100644
index 0cdac7cbea..0000000000
--- a/thirdparty/thorvg/src/loaders/png/tvgLodePng.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- LodePNG version 20200306
-
- Copyright (c) 2005-2020 Lode Vandevenne
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any source
- distribution.
-*/
-
-#ifndef _TVG_LODEPNG_H_
-#define _TVG_LODEPNG_H_
-
-#include <stddef.h>
-
-/*The PNG color types (also used for raw image).*/
-enum LodePNGColorType
-{
- LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/
- LCT_RGB = 2, /*RGB: 8,16 bit*/
- LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/
- LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/
- LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/
- /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid
- byte value from 0 to 255 that could be present in an invalid PNG file header. Do
- not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use
- the valid color type names above, or numeric values like 1 or 7 when checking for
- particular disallowed color type byte values, or cast to integer to print it.*/
- LCT_MAX_OCTET_VALUE = 255
-};
-
-/*Settings for zlib decompression*/
-struct LodePNGDecompressSettings
-{
- /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */
- unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
- unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/
-
- /*use custom zlib decoder instead of built in one (default: null)*/
- unsigned (*custom_zlib)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*);
- /*use custom deflate decoder instead of built in one (default: null) if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate)*/
- unsigned (*custom_inflate)(unsigned char**, size_t*, const unsigned char*, size_t, const LodePNGDecompressSettings*);
-
- const void* custom_context; /*optional custom settings for custom functions*/
-};
-
-/*
- Color mode of an image. Contains all information required to decode the pixel
- bits to RGBA colors. This information is the same as used in the PNG file
- format, and is used both for PNG and raw image data in LodePNG.
-*/
-struct LodePNGColorMode
-{
- /*header (IHDR)*/
- LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/
- unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/
-
- /*
- palette (PLTE and tRNS)
-
- Dynamically allocated with the colors of the palette, including alpha.
- This field may not be allocated directly, use lodepng_color_mode_init first,
- then lodepng_palette_add per color to correctly initialize it (to ensure size
- of exactly 1024 bytes).
-
- The alpha channels must be set as well, set them to 255 for opaque images.
-
- When decoding, by default you can ignore this palette, since LodePNG already
- fills the palette colors in the pixels of the raw RGBA output.
-
- The palette is only supported for color type 3.
- */
- unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/
- size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/
-
- /*
- transparent color key (tRNS)
-
- This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
- For grayscale PNGs, r, g and b will all 3 be set to the same.
-
- When decoding, by default you can ignore this information, since LodePNG sets
- pixels with this key to transparent already in the raw RGBA output.
-
- The color key is only supported for color types 0 and 2.
- */
- unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
- unsigned key_r; /*red/grayscale component of color key*/
- unsigned key_g; /*green component of color key*/
- unsigned key_b; /*blue component of color key*/
-};
-
-/*Information about the PNG image, except pixels, width and height.*/
-struct LodePNGInfo
-{
- /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
- unsigned compression_method;/*compression method of the original file. Always 0.*/
- unsigned filter_method; /*filter method of the original file*/
- unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/
- LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/
-};
-
-/*
- Settings for the decoder. This contains settings for the PNG and the Zlib
- decoder, but not the Info settings from the Info structs.
-*/
-struct LodePNGDecoderSettings
-{
- LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
-
- /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */
- unsigned ignore_crc; /*ignore CRC checksums*/
- unsigned ignore_critical; /*ignore unknown critical chunks*/
- unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/
- /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable
- errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some
- strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters
- in string keys, etc... */
-
- unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
-};
-
-/*The settings, state and information for extended encoding and decoding.*/
-struct LodePNGState
-{
- LodePNGDecoderSettings decoder; /*the decoding settings*/
- LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/
- LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/
- unsigned error;
-};
-
-void lodepng_state_init(LodePNGState* state);
-void lodepng_state_cleanup(LodePNGState* state);
-unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize);
-unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state, const unsigned char* in, size_t insize);
-
-#endif //_TVG_LODEPNG_H_
diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
deleted file mode 100644
index 3e293176b7..0000000000
--- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <memory.h>
-#include "tvgLoader.h"
-#include "tvgPngLoader.h"
-
-
-/************************************************************************/
-/* Internal Class Implementation */
-/************************************************************************/
-
-
-static inline uint32_t PREMULTIPLY(uint32_t c)
-{
- auto a = (c >> 24);
- return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff);
-}
-
-
-static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
-{
- auto buffer = data;
- for (uint32_t y = 0; y < h; ++y, buffer += w) {
- auto src = buffer;
- for (uint32_t x = 0; x < w; ++x, ++src) {
- *src = PREMULTIPLY(*src);
- }
- }
-}
-
-
-void PngLoader::clear()
-{
- lodepng_state_cleanup(&state);
-
- if (freeData) free(data);
- data = nullptr;
- size = 0;
- freeData = false;
-}
-
-
-/************************************************************************/
-/* External Class Implementation */
-/************************************************************************/
-
-PngLoader::PngLoader()
-{
- lodepng_state_init(&state);
-}
-
-
-PngLoader::~PngLoader()
-{
- if (freeData) free(data);
- free(image);
-}
-
-
-bool PngLoader::open(const string& path)
-{
- clear();
-
- auto pngFile = fopen(path.c_str(), "rb");
- if (!pngFile) return false;
-
- auto ret = false;
-
- //determine size
- if (fseek(pngFile, 0, SEEK_END) < 0) goto finalize;
- if (((size = ftell(pngFile)) < 1)) goto finalize;
- if (fseek(pngFile, 0, SEEK_SET)) goto finalize;
-
- data = (unsigned char *) malloc(size);
- if (!data) goto finalize;
-
- freeData = true;
-
- if (fread(data, size, 1, pngFile) < 1) goto failure;
-
- lodepng_state_init(&state);
-
- unsigned int width, height;
- if (lodepng_inspect(&width, &height, &state, data, size) > 0) goto failure;
-
- w = static_cast<float>(width);
- h = static_cast<float>(height);
- ret = true;
-
- goto finalize;
-
-failure:
- clear();
-
-finalize:
- fclose(pngFile);
- return ret;
-}
-
-
-bool PngLoader::open(const char* data, uint32_t size, bool copy)
-{
- clear();
-
- lodepng_state_init(&state);
-
- unsigned int width, height;
- if (lodepng_inspect(&width, &height, &state, (unsigned char*)(data), size) > 0) return false;
-
- if (copy) {
- this->data = (unsigned char *) malloc(size);
- if (!this->data) return false;
- memcpy((unsigned char *)this->data, data, size);
- freeData = true;
- } else {
- this->data = (unsigned char *) data;
- freeData = false;
- }
-
- w = static_cast<float>(width);
- h = static_cast<float>(height);
- this->size = size;
-
- return true;
-}
-
-
-bool PngLoader::read()
-{
- if (!data || w <= 0 || h <= 0) return false;
-
- TaskScheduler::request(this);
-
- return true;
-}
-
-
-bool PngLoader::close()
-{
- this->done();
- clear();
- return true;
-}
-
-
-unique_ptr<Surface> PngLoader::bitmap()
-{
- this->done();
-
- if (!image) return nullptr;
-
- auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
- surface->buffer = (uint32_t*)(image);
- surface->stride = w;
- surface->w = w;
- surface->h = h;
- surface->cs = SwCanvas::ARGB8888;
-
- return unique_ptr<Surface>(surface);
-}
-
-
-void PngLoader::run(unsigned tid)
-{
- if (image) {
- free(image);
- image = nullptr;
- }
- auto width = static_cast<unsigned>(w);
- auto height = static_cast<unsigned>(h);
-
- lodepng_decode(&image, &width, &height, &state, data, size);
-
- _premultiply((uint32_t*)(image), width, height);
-}
diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h
deleted file mode 100644
index 8f07f6418f..0000000000
--- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2021 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _TVG_PNG_LOADER_H_
-#define _TVG_PNG_LOADER_H_
-
-#include "tvgLodePng.h"
-#include "tvgTaskScheduler.h"
-
-
-class PngLoader : public LoadModule, public Task
-{
-private:
- LodePNGState state;
- unsigned char* data = nullptr;
- unsigned char *image = nullptr;
- unsigned long size = 0;
- bool freeData = false;
-
- void clear();
-
-public:
- PngLoader();
- ~PngLoader();
-
- using LoadModule::open;
- bool open(const string& path) override;
- bool open(const char* data, uint32_t size, bool copy) override;
- bool read() override;
- bool close() override;
-
- unique_ptr<Surface> bitmap() override;
- void run(unsigned tid) override;
-};
-
-#endif //_TVG_PNG_LOADER_H_
diff --git a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
index d7c51bdc30..c373da2dd5 100644
--- a/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
+++ b/thirdparty/thorvg/src/loaders/svg/tvgXmlParser.cpp
@@ -26,8 +26,8 @@
#ifdef _WIN32
#include <malloc.h>
-#elif defined(__FreeBSD__)
- #include <stdlib.h>
+#elif __FreeBSD__
+ #include<stdlib.h>
#else
#include <alloca.h>
#endif
@@ -390,7 +390,7 @@ bool simpleXmlParse(const char* buf, unsigned bufLength, bool strip, simpleXMLCb
if (p) {
//Invalid case: '<' nested
- if (*p == '<') return false;
+ if (*p == '<' && type != SimpleXMLType::Doctype) return false;
const char *start, *end;
start = itr + 1 + toff;
diff --git a/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
index 66de860aaa..62a75ecd3d 100644
--- a/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
+++ b/thirdparty/thorvg/src/loaders/tvg/tvgTvgBinInterpreter.cpp
@@ -23,8 +23,8 @@
#ifdef _WIN32
#include <malloc.h>
-#elif defined(__FreeBSD__)
- #include <stdlib.h>
+#elif __FreeBSD__
+ #include<stdlib.h>
#else
#include <alloca.h>
#endif
diff --git a/thirdparty/thorvg/src/savers/tvg/tvgTvgSaver.cpp b/thirdparty/thorvg/src/savers/tvg/tvgTvgSaver.cpp
index fca313b430..adf85836c3 100644
--- a/thirdparty/thorvg/src/savers/tvg/tvgTvgSaver.cpp
+++ b/thirdparty/thorvg/src/savers/tvg/tvgTvgSaver.cpp
@@ -28,8 +28,8 @@
#ifdef _WIN32
#include <malloc.h>
-#elif defined(__FreeBSD__)
- #include <stdlib.h>
+#elif __FreeBSD__
+ #include<stdlib.h>
#else
#include <alloca.h>
#endif
diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh
index a3b73a7135..f2fd2a80e4 100755
--- a/thirdparty/thorvg/update-thorvg.sh
+++ b/thirdparty/thorvg/update-thorvg.sh
@@ -1,12 +1,12 @@
-VERSION=0.8.1
+VERSION=0.8.2
rm -rf AUTHORS inc LICENSE src *.zip
-curl -L -O https://github.com/Samsung/thorvg/archive/$VERSION.zip
+curl -L -O https://github.com/Samsung/thorvg/archive/v$VERSION.zip
bsdtar --strip-components=1 -xvf *.zip
rm *.zip
-rm -rf .github docs pc res test tools .git* *.md *.txt wasm_build.sh
+rm -rf .github docs pc res test tools tvgcompat .git* *.md *.txt wasm_build.sh
find . -type f -name 'meson.build' -delete
rm -rf src/bin src/bindings src/examples src/wasm
-rm -rf src/lib/gl_engine tvgcompat
+rm -rf src/lib/gl_engine src/loaders/external_jpg src/loaders/png
cat << EOF > inc/config.h
#ifndef THORVG_CONFIG_H
#define THORVG_CONFIG_H